Created
October 27, 2022 01:17
-
-
Save Cypher1/f3c68d755b3c158dcdffbf4d8d726ddd to your computer and use it in GitHub Desktop.
A couple of handy types for Rust programming
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright 2022 Google LLC. | |
// SPDX-License-Identifier: Apache-2.0use std::marker::PhantomData; | |
#[derive(PartialEq, Eq, Hash)] | |
pub struct TypedIndex<T>(Index, PhantomData<T>); | |
impl<T> std::fmt::Debug for TypedIndex<T> { | |
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | |
write!(f, "{}[{}]", std::any::type_name::<T>(), self.0) | |
} | |
} | |
impl<T> TypedIndex<T> { | |
pub fn new(id: Index) -> Self { | |
Self(id, PhantomData::default()) | |
} | |
} | |
impl<T> Copy for TypedIndex<T> {} | |
impl<T> Clone for TypedIndex<T> { | |
fn clone(&self) -> Self { | |
Self(self.0, self.1) | |
} | |
} | |
pub type Index = usize; | |
#[derive(Clone, Debug, PartialEq, Eq)] | |
pub enum ArenaError { | |
IndexEmpty(String, Index), | |
IndexOutOfBounds(Index, Index), | |
} | |
#[derive(Default, Clone, Debug)] | |
pub struct Arena<T>(Vec<T>); | |
pub struct ArenaIterator<'a, T>(&'a Vec<T>, Index); | |
impl<'a, T> Iterator for ArenaIterator<'a, T> { | |
type Item = &'a T; | |
fn next(&mut self) -> Option<Self::Item> { | |
if self.1 < self.0.len() { | |
let value = &self.0[self.1]; | |
self.1 += 1; | |
return Some(value); | |
} | |
None | |
} | |
} | |
impl<'a, T> IntoIterator for &'a Arena<T> { | |
type Item = &'a T; | |
type IntoIter = ArenaIterator<'a, T>; | |
fn into_iter(self) -> Self::IntoIter { | |
ArenaIterator(&self.0, 0) | |
} | |
} | |
pub struct ArenaIteratorMut<'a, T>(&'a mut Vec<T>, Index); | |
impl<'a, T> Iterator for ArenaIteratorMut<'a, T> { | |
type Item = &'a mut T; | |
fn next(&mut self) -> Option<Self::Item> { | |
if self.1 < self.0.len() { | |
let value = &mut self.0[self.1]; | |
let ptr: *mut T = value; | |
self.1 += 1; | |
unsafe { // This is safe because the iterator cannot outlive the Arena. | |
return Some(&mut *ptr); | |
} | |
} | |
None | |
} | |
} | |
impl<'a, T> IntoIterator for &'a mut Arena<T> { | |
type Item = &'a mut T; | |
type IntoIter = ArenaIteratorMut<'a, T>; | |
fn into_iter(self) -> Self::IntoIter { | |
ArenaIteratorMut(&mut self.0, 0) | |
} | |
} | |
impl<T> Arena<T> { | |
pub fn add<S: Into<T>, F: FnOnce(Index) -> S>(&mut self, value: F) -> Index { | |
let id = self.0.len(); | |
self.0.push(value(id).into()); | |
id | |
} | |
pub fn get(&self, id: Index) -> Result<&T, ArenaError> { | |
self.check_id(id)?; | |
Ok(&self.0[id]) | |
} | |
pub fn get_mut(&mut self, id: Index) -> Result<&mut T, ArenaError> { | |
self.check_id(id)?; | |
Ok(&mut self.0[id]) | |
} | |
pub fn remove_by_swap(&mut self, id: Index) -> Result<T, ArenaError> { | |
self.check_id(id)?; | |
let mut value = self.0.pop().unwrap(); // There is always at least one member. | |
if id < self.0.len() { // swap if the id wasn't the last one... | |
std::mem::swap(&mut self.0[id], &mut value); | |
} | |
Ok(value) // Return the removed item. The 'user' must swap `id` and `len-1` | |
} | |
pub fn check_id(&self, id: Index) -> Result<(), ArenaError> { | |
match id >= self.0.len() { | |
true => Err(ArenaError::IndexOutOfBounds(id, self.0.len())), | |
false => Ok(()), | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment