1mod seed;
11pub use seed::{ArenaSeed, ArenaSeedError};
12use vstd::prelude::*;
13
14verus! {
15
16pub open spec fn generation_advances(current: int, next: int) -> bool {
21 next == current + 1
22}
23
24pub fn next_generation(current: u32) -> (next: Option<u32>)
28 ensures
29 next.is_some() == (current < u32::MAX),
30 next.is_some() ==> generation_advances(current as int, next.unwrap() as int),
31 next.is_some() ==> next.unwrap() != current,
32{
33 if current == u32::MAX {
34 None
35 } else {
36 Some(current + 1)
37 }
38}
39
40pub fn index_for_len(len: usize) -> (index: Option<u32>)
45 ensures
46 index.is_some() == (len <= u32::MAX as usize),
47 index.is_some() ==> index.unwrap() as usize == len,
48{
49 if len > u32::MAX as usize {
50 None
51 } else {
52 Some(len as u32)
53 }
54}
55
56proof fn reused_slot_never_aliases(current: int, next: int)
59 requires
60 generation_advances(current, next),
61 ensures
62 next != current,
63 next > current,
64{
65}
66
67}
68
69#[derive(
72 Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, serde::Serialize, serde::Deserialize,
73)]
74#[serde(bound = "")]
75pub struct Id<K> {
76 #[serde(rename = "slot", alias = "index")]
77 index: u32,
78 generation: u32,
79 #[serde(skip)]
80 _kind: std::marker::PhantomData<K>,
81}
82
83impl<K> Id<K> {
84 pub fn index(self) -> usize {
85 self.index as usize
86 }
87
88 pub fn generation(self) -> u32 {
89 self.generation
90 }
91}
92
93#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
95pub struct DocumentKind;
96#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
97pub struct ViewKind;
98#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
99pub struct PaneKind;
100#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
102pub struct WorkspaceKind;
103
104pub type DocumentId = Id<DocumentKind>;
105pub type ViewId = Id<ViewKind>;
106pub type PaneId = Id<PaneKind>;
107pub type WorkspaceId = Id<WorkspaceKind>;
108
109pub struct Arena<K, T> {
116 slots: Vec<Slot<T>>,
117 free: Vec<u32>,
118 _kind: std::marker::PhantomData<K>,
119}
120
121#[derive(Debug)]
122struct Slot<T> {
123 generation: u32,
124 value: Option<T>,
125}
126
127#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
131#[error("arena identity space exhausted")]
132pub struct ArenaExhausted;
133
134impl<K, T> Default for Arena<K, T> {
135 fn default() -> Self {
136 Self {
137 slots: Vec::new(),
138 free: Vec::new(),
139 _kind: std::marker::PhantomData,
140 }
141 }
142}
143
144impl<K, T> Arena<K, T> {
145 pub fn try_insert(&mut self, value: T) -> Result<Id<K>, ArenaExhausted> {
152 while let Some(index) = self.free.pop() {
153 let slot = &mut self.slots[index as usize];
154 let Some(generation) = next_generation(slot.generation) else {
157 continue; };
159 slot.generation = generation;
160 slot.value = Some(value);
161 return Ok(Id {
162 index,
163 generation,
164 _kind: std::marker::PhantomData,
165 });
166 }
167 let Some(index) = index_for_len(self.slots.len()) else {
170 return Err(ArenaExhausted);
171 };
172 self.slots.push(Slot {
173 generation: 0,
174 value: Some(value),
175 });
176 Ok(Id {
177 index,
178 generation: 0,
179 _kind: std::marker::PhantomData,
180 })
181 }
182
183 pub fn insert_capacity(&self) -> u64 {
187 let reusable = self
188 .free
189 .iter()
190 .filter(|&&index| self.slots[index as usize].generation < u32::MAX)
191 .count() as u64;
192 reusable + (u64::from(u32::MAX) - self.slots.len() as u64)
193 }
194
195 pub fn get(&self, id: Id<K>) -> Option<&T> {
197 self.slots
198 .get(id.index as usize)
199 .filter(|s| s.generation == id.generation)
200 .and_then(|s| s.value.as_ref())
201 }
202
203 pub fn get_mut(&mut self, id: Id<K>) -> Option<&mut T> {
204 self.slots
205 .get_mut(id.index as usize)
206 .filter(|s| s.generation == id.generation)
207 .and_then(|s| s.value.as_mut())
208 }
209
210 pub fn remove(&mut self, id: Id<K>) -> Option<T> {
212 let slot = self.slots.get_mut(id.index as usize)?;
213 if slot.generation != id.generation {
214 return None;
215 }
216 let value = slot.value.take()?;
217 self.free.push(id.index);
218 Some(value)
219 }
220
221 pub fn iter(&self) -> impl Iterator<Item = (Id<K>, &T)> {
222 self.slots.iter().enumerate().filter_map(|(i, s)| {
223 s.value.as_ref().map(|v| {
224 (
225 Id {
226 index: i as u32,
227 generation: s.generation,
228 _kind: std::marker::PhantomData,
229 },
230 v,
231 )
232 })
233 })
234 }
235
236 pub fn values_mut(&mut self) -> impl Iterator<Item = &mut T> {
238 self.slots.iter_mut().filter_map(|slot| slot.value.as_mut())
239 }
240
241 pub fn len(&self) -> usize {
242 self.slots.iter().filter(|s| s.value.is_some()).count()
243 }
244
245 pub fn clear(&mut self) {
247 let live: Vec<u32> = self
248 .slots
249 .iter()
250 .enumerate()
251 .filter(|(_, s)| s.value.is_some())
252 .map(|(i, _)| i as u32)
253 .collect();
254 for s in &mut self.slots {
255 s.value = None;
256 }
257 self.free.extend(live);
258 }
259 pub fn is_empty(&self) -> bool {
260 self.len() == 0
261 }
262}
263
264macro_rules! coordinate {
268 ($name:ident, $unit:literal) => {
269 #[derive(
270 Debug,
271 Clone,
272 Copy,
273 PartialEq,
274 Eq,
275 PartialOrd,
276 Ord,
277 Hash,
278 Default,
279 serde::Serialize,
280 serde::Deserialize,
281 )]
282 #[repr(transparent)]
283 #[serde(transparent)]
284 pub struct $name(usize);
285
286 impl $name {
287 #[inline]
288 pub fn new(v: usize) -> Self {
289 Self(v)
290 }
291 #[inline]
294 pub fn get(self) -> usize {
295 self.0
296 }
297 #[inline]
298 pub fn saturating_sub(self, n: usize) -> Self {
299 Self(self.0.saturating_sub(n))
300 }
301 }
302
303 impl std::ops::AddAssign<usize> for $name {
304 #[inline]
305 fn add_assign(&mut self, n: usize) {
306 self.0 += n;
307 }
308 }
309 impl std::ops::SubAssign<usize> for $name {
310 #[inline]
311 fn sub_assign(&mut self, n: usize) {
312 self.0 -= n;
313 }
314 }
315 impl PartialEq<usize> for $name {
318 #[inline]
319 fn eq(&self, other: &usize) -> bool {
320 self.0 == *other
321 }
322 }
323 impl PartialOrd<usize> for $name {
324 #[inline]
325 fn partial_cmp(&self, other: &usize) -> Option<std::cmp::Ordering> {
326 self.0.partial_cmp(other)
327 }
328 }
329 impl std::ops::Add<usize> for $name {
330 type Output = $name;
331 #[inline]
332 fn add(self, n: usize) -> $name {
333 $name(self.0 + n)
334 }
335 }
336 impl std::ops::Sub<usize> for $name {
337 type Output = $name;
338 #[inline]
339 fn sub(self, n: usize) -> $name {
340 $name(self.0 - n)
341 }
342 }
343 impl std::ops::Sub<$name> for $name {
344 type Output = usize; #[inline]
346 fn sub(self, other: $name) -> usize {
347 self.0 - other.0
348 }
349 }
350 impl std::fmt::Display for $name {
351 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
352 write!(f, "{} {}", self.0, $unit)
353 }
354 }
355 impl From<$name> for usize {
356 #[inline]
357 fn from(v: $name) -> usize {
358 v.0
359 }
360 }
361 impl From<usize> for $name {
362 #[inline]
363 fn from(v: usize) -> $name {
364 $name(v)
365 }
366 }
367 };
368}
369
370coordinate!(ByteOffset, "B");
371coordinate!(LineIndex, "L");
372coordinate!(ByteColumn, "col:B");
373coordinate!(Utf16Column, "col:u16");
374coordinate!(DisplayColumn, "col:dsp");
375
376#[derive(
378 Debug,
379 Clone,
380 Copy,
381 PartialEq,
382 Eq,
383 PartialOrd,
384 Ord,
385 Hash,
386 Default,
387 serde::Serialize,
388 serde::Deserialize,
389)]
390#[serde(transparent)]
391pub struct BufferRevision(u64);
392
393impl BufferRevision {
394 pub const fn new(value: u64) -> Self {
395 Self(value)
396 }
397 pub const fn get(self) -> u64 {
398 self.0
399 }
400 pub fn checked_next(self) -> Option<Self> {
401 self.0.checked_add(1).map(Self)
402 }
403}
404
405impl std::fmt::Display for BufferRevision {
406 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
407 self.0.fmt(formatter)
408 }
409}
410
411impl From<u64> for BufferRevision {
412 fn from(value: u64) -> Self {
413 Self(value)
414 }
415}
416
417#[cfg(test)]
424mod tests {
425 use super::*;
426
427 #[test]
428 fn stale_ids_fail_lookup() {
429 let mut a: Arena<DocumentKind, String> = Arena::default();
430 let one = a.try_insert("one".into()).unwrap();
431 let two = a.try_insert("two".into()).unwrap();
432 assert_eq!(a.get(one).map(String::as_str), Some("one"));
433 a.remove(one);
434 assert_eq!(a.get(one), None, "removed");
435 let three = a.try_insert("three".into()).unwrap(); assert_eq!(a.get(one), None, "stale generation must not resolve");
437 assert_eq!(a.get(three).map(String::as_str), Some("three"));
438 assert_eq!(a.get(two).map(String::as_str), Some("two"));
439 assert_eq!(a.len(), 2);
440 }
441
442 #[test]
446 fn generation_wrap_retires_the_slot() {
447 let mut a: Arena<DocumentKind, String> = Arena::from_seed(ArenaSeed {
448 slots: vec![(u32::MAX - 1, None)],
449 free: vec![0],
450 })
451 .unwrap();
452 assert_eq!(a.insert_capacity(), u64::from(u32::MAX));
453 let last = a.try_insert("last".into()).unwrap();
454 assert_eq!((last.index(), last.generation()), (0, u32::MAX));
455 a.remove(last);
456 let fresh = a.try_insert("fresh".into()).unwrap();
458 assert_eq!((fresh.index(), fresh.generation()), (1, 0));
459 assert_eq!(a.get(last), None, "a wrapped generation would alias");
460 assert_eq!(a.get(fresh).map(String::as_str), Some("fresh"));
461 a.remove(fresh);
464 let again = a.try_insert("again".into()).unwrap();
465 assert_eq!((again.index(), again.generation()), (1, 1));
466 assert_eq!(a.insert_capacity(), u64::from(u32::MAX) - 2);
467 }
468
469 #[test]
472 fn retired_slots_stay_dead_across_seeds() {
473 let mut a: Arena<DocumentKind, String> = Arena::from_seed(ArenaSeed {
474 slots: vec![(u32::MAX, None)],
475 free: vec![0],
476 })
477 .unwrap();
478 let live = a.try_insert("live".into()).unwrap();
479 assert_eq!(live.index(), 1, "the maxed slot was retired on reuse");
480 let seed = a.seed_with(|value| value.clone());
481 let mut rebuilt = Arena::from_seed(seed).unwrap();
482 let after = rebuilt.try_insert("after".into()).unwrap();
483 assert_eq!(after.index(), 2, "retirement is part of the seed");
484 assert_eq!(rebuilt.get(live).map(String::as_str), Some("live"));
485 }
486}