mod seed;
pub use seed::{ArenaSeed, ArenaSeedError};
#[derive(
Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, serde::Serialize, serde::Deserialize,
)]
#[serde(bound = "")]
pub struct Id<K> {
#[serde(rename = "slot", alias = "index")]
index: u32,
generation: u32,
#[serde(skip)]
_kind: std::marker::PhantomData<K>,
}
impl<K> Id<K> {
pub fn index(self) -> usize {
self.index as usize
}
pub fn generation(self) -> u32 {
self.generation
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DocumentKind;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ViewKind;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct PaneKind;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct WorkspaceKind;
pub type DocumentId = Id<DocumentKind>;
pub type ViewId = Id<ViewKind>;
pub type PaneId = Id<PaneKind>;
pub type WorkspaceId = Id<WorkspaceKind>;
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
}
}
macro_rules! coordinate {
($name:ident, $unit:literal) => {
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Default,
serde::Serialize,
serde::Deserialize,
)]
#[repr(transparent)]
#[serde(transparent)]
pub struct $name(usize);
impl $name {
#[inline]
pub fn new(v: usize) -> Self {
Self(v)
}
#[inline]
pub fn get(self) -> usize {
self.0
}
#[inline]
pub fn saturating_sub(self, n: usize) -> Self {
Self(self.0.saturating_sub(n))
}
}
impl std::ops::AddAssign<usize> for $name {
#[inline]
fn add_assign(&mut self, n: usize) {
self.0 += n;
}
}
impl std::ops::SubAssign<usize> for $name {
#[inline]
fn sub_assign(&mut self, n: usize) {
self.0 -= n;
}
}
impl PartialEq<usize> for $name {
#[inline]
fn eq(&self, other: &usize) -> bool {
self.0 == *other
}
}
impl PartialOrd<usize> for $name {
#[inline]
fn partial_cmp(&self, other: &usize) -> Option<std::cmp::Ordering> {
self.0.partial_cmp(other)
}
}
impl std::ops::Add<usize> for $name {
type Output = $name;
#[inline]
fn add(self, n: usize) -> $name {
$name(self.0 + n)
}
}
impl std::ops::Sub<usize> for $name {
type Output = $name;
#[inline]
fn sub(self, n: usize) -> $name {
$name(self.0 - n)
}
}
impl std::ops::Sub<$name> for $name {
type Output = usize; #[inline]
fn sub(self, other: $name) -> usize {
self.0 - other.0
}
}
impl std::fmt::Display for $name {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} {}", self.0, $unit)
}
}
impl From<$name> for usize {
#[inline]
fn from(v: $name) -> usize {
v.0
}
}
impl From<usize> for $name {
#[inline]
fn from(v: usize) -> $name {
$name(v)
}
}
};
}
coordinate!(ByteOffset, "B");
coordinate!(LineIndex, "L");
coordinate!(ByteColumn, "col:B");
coordinate!(Utf16Column, "col:u16");
coordinate!(DisplayColumn, "col:dsp");
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Default,
serde::Serialize,
serde::Deserialize,
)]
#[serde(transparent)]
pub struct BufferRevision(u64);
impl BufferRevision {
pub const fn new(value: u64) -> Self {
Self(value)
}
pub const fn get(self) -> u64 {
self.0
}
pub fn checked_next(self) -> Option<Self> {
self.0.checked_add(1).map(Self)
}
}
impl std::fmt::Display for BufferRevision {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(formatter)
}
}
impl From<u64> for BufferRevision {
fn from(value: u64) -> Self {
Self(value)
}
}
#[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);
}
}