Skip to content

Instantly share code, notes, and snippets.

@Cypher1
Created October 27, 2022 01:17
Show Gist options
  • Save Cypher1/f3c68d755b3c158dcdffbf4d8d726ddd to your computer and use it in GitHub Desktop.
Save Cypher1/f3c68d755b3c158dcdffbf4d8d726ddd to your computer and use it in GitHub Desktop.
A couple of handy types for Rust programming
// 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