#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Id<K> {
index: u32,
generation: u32,
_kind: std::marker::PhantomData<K>,
}
impl<K> Id<K> {
pub fn index(self) -> usize {
self.index as usize
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DocumentKind;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ViewKind;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct PaneKind;
pub type DocumentId = Id<DocumentKind>;
pub type ViewId = Id<ViewKind>;
pub type PaneId = Id<PaneKind>;
pub struct Arena<K, T> {
slots: Vec<Slot<T>>,
free: Vec<u32>,
_kind: std::marker::PhantomData<K>,
}
#[derive(Debug)]
struct Slot<T> {
generation: u32,
value: Option<T>,
}
impl<K, T> Default for Arena<K, T> {
fn default() -> Self {
Self {
slots: Vec::new(),
free: Vec::new(),
_kind: std::marker::PhantomData,
}
}
}
impl<K, T> Arena<K, T> {
pub fn insert(&mut self, value: T) -> Id<K> {
if let Some(index) = self.free.pop() {
let slot = &mut self.slots[index as usize];
slot.generation += 1;
slot.value = Some(value);
return Id {
index,
generation: slot.generation,
_kind: std::marker::PhantomData,
};
}
let index = self.slots.len() as u32;
self.slots.push(Slot {
generation: 0,
value: Some(value),
});
Id {
index,
generation: 0,
_kind: std::marker::PhantomData,
}
}
pub fn get(&self, id: Id<K>) -> Option<&T> {
self.slots
.get(id.index as usize)
.filter(|s| s.generation == id.generation)
.and_then(|s| s.value.as_ref())
}
pub fn get_mut(&mut self, id: Id<K>) -> Option<&mut T> {
self.slots
.get_mut(id.index as usize)
.filter(|s| s.generation == id.generation)
.and_then(|s| s.value.as_mut())
}
pub fn remove(&mut self, id: Id<K>) -> Option<T> {
let slot = self.slots.get_mut(id.index as usize)?;
if slot.generation != id.generation {
return None;
}
let value = slot.value.take()?;
self.free.push(id.index);
Some(value)
}
pub fn iter(&self) -> impl Iterator<Item = (Id<K>, &T)> {
self.slots.iter().enumerate().filter_map(|(i, s)| {
s.value.as_ref().map(|v| {
(
Id {
index: i as u32,
generation: s.generation,
_kind: std::marker::PhantomData,
},
v,
)
})
})
}
pub fn len(&self) -> usize {
self.slots.iter().filter(|s| s.value.is_some()).count()
}
pub fn clear(&mut self) {
let live: Vec<u32> = self
.slots
.iter()
.enumerate()
.filter(|(_, s)| s.value.is_some())
.map(|(i, _)| i as u32)
.collect();
for s in &mut self.slots {
s.value = None;
}
self.free.extend(live);
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
pub type ByteOffset = usize;
pub type LineIndex = usize;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn stale_ids_fail_lookup() {
let mut a: Arena<DocumentKind, String> = Arena::default();
let one = a.insert("one".into());
let two = a.insert("two".into());
assert_eq!(a.get(one).map(String::as_str), Some("one"));
a.remove(one);
assert_eq!(a.get(one), None, "removed");
let three = a.insert("three".into()); assert_eq!(a.get(one), None, "stale generation must not resolve");
assert_eq!(a.get(three).map(String::as_str), Some("three"));
assert_eq!(a.get(two).map(String::as_str), Some("two"));
assert_eq!(a.len(), 2);
}
}