contiguous_arena/
lib.rs

1#![doc = include_str!("../README.md")]
2
3use std::{cmp::Ordering, fmt, marker::PhantomData, num::NonZeroU32, ops};
4
5#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Default)]
6pub struct Span {
7    start: u32,
8    end: u32,
9}
10
11impl Span {
12    pub const UNDEFINED: Self = Self { start: 0, end: 0 };
13
14    pub const fn new(start: u32, end: u32) -> Self {
15        debug_assert!(start <= end, "Span start must be <= end");
16        Span { start, end }
17    }
18
19    pub fn is_defined(&self) -> bool {
20        self.start != self.end
21    }
22
23    pub fn length(&self) -> u32 {
24        self.end - self.start
25    }
26}
27
28impl std::ops::Index<Span> for str {
29    type Output = str;
30
31    #[inline]
32    fn index(&self, span: Span) -> &str {
33        &self[span.start as usize..span.end as usize]
34    }
35}
36
37type Index = NonZeroU32;
38
39pub struct Handle<T> {
40    index: Index,
41    marker: PhantomData<T>,
42}
43
44impl<T> Clone for Handle<T> {
45    fn clone(&self) -> Self {
46        *self
47    }
48}
49
50impl<T> Copy for Handle<T> {}
51
52impl<T> PartialEq for Handle<T> {
53    fn eq(&self, other: &Self) -> bool {
54        self.index == other.index
55    }
56}
57
58impl<T> Eq for Handle<T> {}
59
60impl<T> PartialOrd for Handle<T> {
61    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
62        Some(self.cmp(other))
63    }
64}
65
66impl<T> Ord for Handle<T> {
67    fn cmp(&self, other: &Self) -> Ordering {
68        self.index.cmp(&other.index)
69    }
70}
71
72impl<T> fmt::Debug for Handle<T> {
73    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
74        write!(formatter, "[{}]", self.index)
75    }
76}
77
78impl<T> Handle<T> {
79    #[cfg(test)]
80    pub const DUMMY: Self = Handle {
81        index: NonZeroU32::new(u32::MAX).unwrap(),
82        marker: PhantomData,
83    };
84
85    #[inline]
86    pub const fn new(index: Index) -> Self {
87        Handle {
88            index,
89            marker: PhantomData,
90        }
91    }
92
93    #[inline]
94    pub const fn index(self) -> usize {
95        let index = self.index.get() - 1;
96        index as usize
97    }
98
99    #[inline]
100    fn from_usize(index: usize) -> Self {
101        let handle_index = u32::try_from(index + 1)
102            .ok()
103            .and_then(Index::new)
104            .expect("failed to insert into arena");
105        Handle::new(handle_index)
106    }
107
108    #[inline]
109    const unsafe fn from_usize_unchecked(index: usize) -> Self {
110        Handle::new(Index::new_unchecked((index + 1) as u32))
111    }
112}
113
114#[derive(Clone)]
115pub struct Arena<T> {
116    data: Vec<T>,
117    span_info: Vec<Span>,  // Kept sorted by span.start
118    free_spans: Vec<Span>, // Kept sorted by span.start
119}
120
121impl<T: Clone> Default for Arena<T> {
122    fn default() -> Self {
123        Self::new()
124    }
125}
126
127impl<T: fmt::Debug + Clone> fmt::Debug for Arena<T> {
128    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
129        f.debug_map().entries(self.iter()).finish()
130    }
131}
132
133impl<T: Clone> Arena<T> {
134    pub const fn new() -> Self {
135        Arena {
136            data: Vec::new(),
137            span_info: Vec::new(),
138            free_spans: Vec::new(),
139        }
140    }
141
142    pub fn with_capacity(capacity: usize) -> Self {
143        Arena {
144            data: Vec::with_capacity(capacity),
145            span_info: Vec::new(),
146            free_spans: Vec::new(),
147        }
148    }
149
150    pub fn into_inner(self) -> Vec<T> {
151        self.data
152    }
153
154    pub fn len(&self) -> usize {
155        self.span_info
156            .iter()
157            .map(|span| span.length() as usize)
158            .sum()
159    }
160
161    pub fn capacity(&self) -> usize {
162        self.data.capacity()
163    }
164
165    pub fn buffer_len(&self) -> usize {
166        self.data.len()
167    }
168
169    pub fn is_empty(&self) -> bool {
170        self.span_info.is_empty()
171    }
172
173    pub fn iter(&self) -> impl DoubleEndedIterator<Item = (Handle<T>, &T)> + '_ {
174        self.span_info
175            .iter()
176            .flat_map(move |&span| (span.start..span.end))
177            .map(move |i| {
178                let handle = unsafe { Handle::from_usize_unchecked(i as usize) };
179                (handle, &self.data[i as usize])
180            })
181    }
182
183    pub fn drain(&mut self) -> impl Iterator<Item = (Handle<T>, T, Span)> + '_ {
184        let arena = std::mem::take(self);
185        arena
186            .data
187            .into_iter()
188            .zip(
189                arena
190                    .span_info
191                    .into_iter()
192                    .flat_map(|span| std::iter::repeat_n(span, span.length() as usize)),
193            )
194            .enumerate()
195            .map(|(i, (v, span))| unsafe { (Handle::from_usize_unchecked(i), v, span) })
196    }
197
198    pub fn iter_mut(&mut self) -> impl DoubleEndedIterator<Item = (Handle<T>, &mut T)> + '_ {
199        let data_ptr = self.data.as_mut_ptr();
200        self.span_info
201            .iter()
202            .flat_map(move |&span| (span.start..span.end))
203            .map(move |i| {
204                let handle = unsafe { Handle::from_usize_unchecked(i as usize) };
205                let value_ref = unsafe { &mut *data_ptr.add(i as usize) };
206                (handle, value_ref)
207            })
208    }
209
210    fn find_free_span(&mut self, count: u32) -> Option<Span> {
211        if let Some(pos) = self
212            .free_spans
213            .iter()
214            .position(|span| span.length() >= count)
215        {
216            let span = self.free_spans.remove(pos);
217
218            if span.length() > count {
219                let remaining_span = Span {
220                    start: span.start + count,
221                    end: span.end,
222                };
223                match self.free_spans.binary_search(&remaining_span) {
224                    Ok(idx) => self.free_spans.insert(idx, remaining_span),
225                    Err(idx) => self.free_spans.insert(idx, remaining_span),
226                }
227            }
228            Some(Span {
229                start: span.start,
230                end: span.start + count,
231            })
232        } else {
233            None
234        }
235    }
236
237    pub fn append(&mut self, value: T, count: usize) -> Handle<T> {
238        assert!(count > 0);
239        let u_count = count as u32;
240
241        if let Some(target_span) = self.find_free_span(u_count) {
242            let start = target_span.start as usize;
243            let end = target_span.end as usize;
244            for i in start..end - 1 {
245                self.data[i] = value.clone();
246            }
247            self.data[end - 1] = value;
248
249            match self
250                .span_info
251                .binary_search_by_key(&target_span.start, |s| s.start)
252            {
253                Ok(_) => unreachable!("should not find existing span at reused start"),
254                Err(idx) => self.span_info.insert(idx, target_span),
255            }
256
257            return Handle::from_usize(start);
258        }
259
260        let start_idx = self.data.len();
261        let end_idx = start_idx + count;
262
263        self.data.resize(end_idx, value);
264
265        let new_span = Span::new(start_idx as u32, end_idx as u32);
266        self.span_info.push(new_span);
267
268        Handle::from_usize(start_idx)
269    }
270
271    pub fn fetch_if<F: Fn(&T) -> bool>(&self, fun: F) -> Option<Handle<T>> {
272        self.iter()
273            .find(|(_, data)| fun(data))
274            .map(|(handle, _)| handle)
275    }
276
277    pub fn fetch_if_or_append<F: Fn(&T, &T) -> bool>(
278        &mut self,
279        value: T,
280        count: usize,
281        fun: F,
282    ) -> Handle<T> {
283        let found_handle = self
284            .iter()
285            .find(|(_, data)| fun(data, &value))
286            .map(|(h, _)| h);
287
288        if let Some(handle) = found_handle {
289            handle
290        } else {
291            self.append(value, count)
292        }
293    }
294
295    pub fn fetch_or_append(&mut self, value: T, count: usize) -> Handle<T>
296    where
297        T: PartialEq,
298    {
299        self.fetch_if_or_append(value, count, T::eq)
300    }
301
302    pub fn try_get(&self, handle: Handle<T>) -> Result<&T, &'static str> {
303        let index = handle.index();
304        if index < self.data.len()
305            && self
306                .span_info
307                .binary_search_by(|probe| {
308                    if index < probe.start as usize {
309                        Ordering::Greater
310                    } else if index >= probe.end as usize {
311                        Ordering::Less
312                    } else {
313                        Ordering::Equal
314                    }
315                })
316                .is_ok()
317        {
318            Ok(unsafe { self.data.get_unchecked(index) })
319        } else {
320            Err("Handle out of range or points to freed memory")
321        }
322    }
323
324    pub fn get_mut(&mut self, handle: Handle<T>) -> &mut T {
325        let index = handle.index();
326        let data_len = self.data.len();
327        let span_exists = self
328            .span_info
329            .binary_search_by(|probe| {
330                if index < probe.start as usize {
331                    Ordering::Greater
332                } else if index >= probe.end as usize {
333                    Ordering::Less
334                } else {
335                    Ordering::Equal
336                }
337            })
338            .is_ok();
339
340        if index < data_len && span_exists {
341            unsafe { self.data.get_unchecked_mut(index) }
342        } else {
343            panic!("Handle out of range or points to freed memory");
344        }
345    }
346
347    pub fn clear(&mut self) {
348        self.data.clear();
349        self.span_info.clear();
350        self.free_spans.clear();
351    }
352
353    pub fn get_span(&self, handle: Handle<T>) -> Span {
354        let index = handle.index() as u32;
355        self.span_info
356            .binary_search_by(|probe| {
357                if index < probe.start {
358                    Ordering::Greater
359                } else if index >= probe.end {
360                    Ordering::Less
361                } else {
362                    Ordering::Equal
363                }
364            })
365            .map(|idx| self.span_info[idx])
366            .expect("Handle does not point to a valid span")
367    }
368
369    pub fn check_contains_handle(&self, handle: Handle<T>) -> Result<(), &'static str> {
370        self.try_get(handle).map(|_| ())
371    }
372
373    pub fn retain_mut<P>(&mut self, mut predicate: P)
374    where
375        P: FnMut(Handle<T>, &mut T) -> bool,
376    {
377        let mut handles_to_free = Vec::new();
378        let data_ptr = self.data.as_mut_ptr();
379
380        for span in &self.span_info {
381            let mut keep_span = false;
382            for i in span.start..span.end {
383                let handle = unsafe { Handle::from_usize_unchecked(i as usize) };
384                let value_ref = unsafe { &mut *data_ptr.add(i as usize) };
385                if predicate(handle, value_ref) {
386                    keep_span = true;
387                }
388            }
389            if !keep_span {
390                handles_to_free.push(unsafe { Handle::from_usize_unchecked(span.start as usize) });
391            }
392        }
393
394        for handle in handles_to_free {
395            self.free(handle);
396        }
397    }
398
399    pub fn free(&mut self, handle: Handle<T>) {
400        let index = handle.index() as u32;
401        let span_idx = match self.span_info.binary_search_by_key(&index, |s| s.start) {
402            Ok(idx) if self.span_info[idx].start == index => idx,
403            _ => panic!(
404                "attempted to free an invalid handle (not start of a span) or already freed span"
405            ),
406        };
407
408        let span_to_free = self.span_info.remove(span_idx);
409
410        let mut merged_span = span_to_free;
411
412        if let Ok(right_idx) = self
413            .free_spans
414            .binary_search_by_key(&merged_span.end, |s| s.start) {
415            merged_span.end = self.free_spans.remove(right_idx).end;
416        }
417
418        let left_search = self
419            .free_spans
420            .binary_search_by(|probe| probe.end.cmp(&merged_span.start));
421        match left_search {
422            Ok(left_idx) => {
423                merged_span.start = self.free_spans.remove(left_idx).start;
424            }
425            Err(idx) if idx > 0 => {
426                if self.free_spans[idx - 1].end == merged_span.start {
427                    merged_span.start = self.free_spans.remove(idx - 1).start;
428                }
429            }
430            _ => {}
431        }
432
433        match self.free_spans.binary_search(&merged_span) {
434            Ok(_) => unreachable!("Should not have duplicate free spans"),
435            Err(idx) => self.free_spans.insert(idx, merged_span),
436        }
437    }
438
439    #[inline]
440    pub fn as_slice(&self) -> &[T] {
441        &self.data
442    }
443
444    #[inline]
445    pub fn as_mut_slice(&mut self) -> &mut [T] {
446        &mut self.data
447    }
448
449    #[inline]
450    pub fn spans(&self) -> &[Span] {
451        &self.span_info
452    }
453
454    #[inline]
455    pub fn free_spans(&self) -> &[Span] {
456        &self.free_spans
457    }
458}
459
460impl<T: Clone> ops::Index<Handle<T>> for Arena<T> {
461    type Output = T;
462    #[inline]
463    fn index(&self, handle: Handle<T>) -> &T {
464        match self.try_get(handle) {
465            Ok(val) => val,
466            Err(msg) => panic!("{}", msg),
467        }
468    }
469}
470
471impl<T: Clone> ops::IndexMut<Handle<T>> for Arena<T> {
472    #[inline]
473    fn index_mut(&mut self, handle: Handle<T>) -> &mut T {
474        self.get_mut(handle)
475    }
476}
477
478#[cfg(test)]
479mod tests {
480    use super::*;
481
482    #[derive(Default)]
483    struct SplitMix64 {
484        x: u64,
485    }
486
487    impl SplitMix64 {
488        fn next_u64(&mut self) -> u64 {
489            self.x = self.x.wrapping_add(0x9e3779b97f4a7c15);
490            let mut z = self.x;
491            z = (z ^ (z >> 30)).wrapping_mul(0xbf58476d1ce4e5b9);
492            z = (z ^ (z >> 27)).wrapping_mul(0x94d049bb133111eb);
493            z ^ (z >> 31)
494        }
495    }
496
497    #[test]
498    fn append_non_unique() {
499        let mut arena: Arena<u8> = Arena::new();
500        let t1 = arena.append(0, 1);
501        let t2 = arena.append(0, 1);
502        assert!(t1 != t2);
503        assert!(arena[t1] == arena[t2]);
504        assert_eq!(arena.len(), 2);
505    }
506
507    #[test]
508    fn append_unique() {
509        let mut arena: Arena<u8> = Arena::new();
510        let t1 = arena.append(0, 1);
511        let t2 = arena.append(1, 1);
512        assert!(t1 != t2);
513        assert!(arena[t1] != arena[t2]);
514        assert_eq!(arena.len(), 2);
515    }
516
517    #[test]
518    fn fetch_or_append_non_unique() {
519        let mut arena: Arena<u8> = Arena::new();
520        let t1 = arena.fetch_or_append(0, 1);
521        let t2 = arena.fetch_or_append(0, 1);
522        assert!(t1 == t2);
523        assert!(arena[t1] == arena[t2]);
524        assert_eq!(arena.len(), 1);
525    }
526
527    #[test]
528    fn fetch_or_append_unique() {
529        let mut arena: Arena<u8> = Arena::new();
530        let t1 = arena.fetch_or_append(0, 1);
531        let t2 = arena.fetch_or_append(1, 1);
532        assert!(t1 != t2);
533        assert!(arena[t1] != arena[t2]);
534        assert_eq!(arena.len(), 2);
535    }
536
537    #[test]
538    fn iterators_live_only() {
539        let mut arena: Arena<u8> = Arena::new();
540        let h1 = arena.append(1, 3); // indices 0, 1, 2
541        let _h2 = arena.append(2, 2); // indices 3, 4
542        arena.free(h1);
543        let _h3 = arena.append(3, 1); // index 5
544        let _h4 = arena.append(4, 2); // indices 0, 1 (reused)
545
546        let mut live_elements = arena.iter().map(|(_, &v)| v).collect::<Vec<_>>();
547        live_elements.sort_unstable();
548        assert_eq!(live_elements, vec![2, 2, 3, 4, 4]);
549
550        assert_eq!(arena.len(), 5);
551
552        for (_, val) in arena.iter_mut() {
553            *val *= 10;
554        }
555        let mut live_elements_mut = arena.iter().map(|(_, &v)| v).collect::<Vec<_>>();
556        live_elements_mut.sort_unstable();
557        assert_eq!(live_elements_mut, vec![20, 20, 30, 40, 40]);
558    }
559
560    #[test]
561    fn reuse_spans() {
562        let mut arena: Arena<u8> = Arena::new();
563        let t1 = arena.append(5, 10); // Span 0..10
564        assert_eq!(arena.len(), 10);
565        assert_eq!(arena.spans(), &[Span::new(0, 10)]);
566        arena.free(t1); // kill the span
567        assert!(arena.is_empty());
568        assert_eq!(arena.free_spans(), &[Span::new(0, 10)]);
569
570        let t2 = arena.append(52, 10); // Reuse 0..10
571        assert_eq!(t1, t2); // should start from the same place
572        assert!(arena.free_spans().is_empty());
573        assert_eq!(arena.spans(), &[Span::new(0, 10)]);
574        assert_eq!(arena.len(), 10);
575
576        assert_eq!(arena[t2], 52);
577        for i in 1..10 {
578            let handle = unsafe { Handle::from_usize_unchecked(t1.index() + i as usize) };
579            assert_eq!(arena[handle], 52);
580        }
581
582        let t3 = arena.append(7, 42); // Append 10..52
583        assert_ne!(t2, t3); // should start from a new place
584        assert_eq!(arena.spans(), &[Span::new(0, 10), Span::new(10, 52)]);
585        assert_eq!(arena.len(), 10 + 42);
586
587        arena.free(t2); // Free 0..10
588        assert_eq!(arena.free_spans(), &[Span::new(0, 10)]);
589        assert_eq!(arena.spans(), &[Span::new(10, 52)]);
590        assert_eq!(arena.len(), 42);
591
592        let t4 = arena.append(255, 20); // Append 52..72 (doesn't fit in free span)
593        assert_ne!(t4.index(), 0); // Did not reuse 0..10
594        assert_eq!(t4.index(), 52);
595        assert_eq!(arena.free_spans(), &[Span::new(0, 10)]);
596        assert_eq!(arena.spans(), &[Span::new(10, 52), Span::new(52, 72)]);
597        assert_eq!(arena.len(), 42 + 20);
598
599        arena.free(t4); // Free 52..72
600        assert_eq!(arena.free_spans(), &[Span::new(0, 10), Span::new(52, 72)]);
601        assert_eq!(arena.spans(), &[Span::new(10, 52)]);
602        assert_eq!(arena.len(), 42);
603
604        let t5 = arena.append(123, 5); // Reuse part of 0..10 -> 0..5
605        assert_eq!(t5.index(), 0);
606        assert_eq!(arena[t5], 123);
607        assert_eq!(arena.free_spans(), &[Span::new(5, 10), Span::new(52, 72)]); // Remainder 5..10 is free
608        assert_eq!(arena.spans(), &[Span::new(0, 5), Span::new(10, 52)]); // t5, t3 (sorted)
609        assert_eq!(arena.len(), 5 + 42);
610
611        arena.free(t3); // Free 10..52
612        assert_eq!(arena.free_spans(), &[Span::new(5, 72)]);
613        assert_eq!(arena.spans(), &[Span::new(0, 5)]); // Only t5 remains
614        assert_eq!(arena.len(), 5);
615    }
616
617    #[test]
618    fn fuzz() {
619        const NUM_ITERATIONS: usize = 1000;
620
621        let mut arena: Arena<u64> = Arena::new();
622        let mut rng = SplitMix64::default();
623        let mut live_handles = Vec::new();
624
625        for j in 0..NUM_ITERATIONS {
626            let cnt = (rng.next_u64() % 10 + 1) as usize;
627            let v = rng.next_u64();
628            let t = arena.append(v, cnt);
629            live_handles.push((t, v, cnt));
630
631            assert_eq!(arena[t], v);
632            for i in 1..cnt {
633                let handle = unsafe { Handle::from_usize_unchecked(t.index() + i) };
634                assert_eq!(arena[handle], v);
635            }
636
637            if j > 10 && j % 5 == 0 && !live_handles.is_empty() {
638                let idx_to_check = rng.next_u64() as usize % live_handles.len();
639                let (prev_handle, prev_v, prev_cnt) = live_handles[idx_to_check];
640                assert_eq!(arena[prev_handle], prev_v);
641                for i in 1..prev_cnt {
642                    let handle = unsafe { Handle::from_usize_unchecked(prev_handle.index() + i) };
643                    assert_eq!(arena[handle], prev_v);
644                }
645            }
646
647            if j > 5 && j % 10 == 0 && !live_handles.is_empty() {
648                let idx_to_remove = rng.next_u64() as usize % live_handles.len();
649                let (handle_to_free, _, _) = live_handles.remove(idx_to_remove);
650                arena.free(handle_to_free);
651                assert!(arena.try_get(handle_to_free).is_err());
652            }
653        }
654
655        let mut total_len = 0;
656        for (handle, v, cnt) in &live_handles {
657            assert_eq!(arena[*handle], *v);
658            total_len += cnt;
659            for i in 1..*cnt {
660                let h = unsafe { Handle::from_usize_unchecked(handle.index() + i) };
661                assert_eq!(arena[h], *v);
662            }
663        }
664        assert_eq!(arena.len(), total_len);
665    }
666
667    #[test]
668    fn arena_retain_mut() {
669        let mut arena: Arena<i32> = Arena::new();
670        let h1 = arena.append(5, 10); // Span 0..10
671        let h2 = arena.append(52, 10); // Span 10..20
672        let h3 = arena.append(7, 10); // Span 20..30
673        let h4 = arena.append(123, 21); // Span 30..51
674        let h5 = arena.append(-7952812, 300); // Span 51..351
675
676        let initial_len = arena.len();
677        assert_eq!(initial_len, 10 + 10 + 10 + 21 + 300);
678
679        arena.retain_mut(|h, v| {
680            let h_idx = h.index();
681            if h_idx >= h2.index() && h_idx < h3.index() + 10 {
682                if *v == 7 {
683                    *v = 49;
684                }
685                true
686            } else {
687                false
688            }
689        });
690
691        assert!(arena.try_get(h1).is_err());
692        assert!(arena.try_get(h4).is_err());
693        assert!(arena.try_get(h5).is_err());
694
695        assert!(arena.try_get(h2).is_ok());
696        assert!(arena.try_get(h3).is_ok());
697
698        assert_eq!(arena[h2], 52);
699        for i in 0..10 {
700            let handle = unsafe { Handle::from_usize_unchecked(h2.index() + i) };
701            assert_eq!(arena[handle], 52);
702        }
703        assert_eq!(arena[h3], 49);
704        for i in 0..10 {
705            let handle = unsafe { Handle::from_usize_unchecked(h3.index() + i) };
706            assert_eq!(arena[handle], 49);
707        }
708
709        assert_eq!(arena.len(), 10 + 10);
710
711        assert_eq!(arena.free_spans(), &[Span::new(0, 10), Span::new(30, 351)]);
712    }
713
714    #[test]
715    fn get_span_test() {
716        let mut arena: Arena<u8> = Arena::new();
717        let h1 = arena.append(1, 5); // 0..5
718        let h2 = arena.append(2, 10); // 5..15
719        arena.free(h1);
720        let h3 = arena.append(3, 3); // 0..3
721        let h4 = arena.append(4, 4); // 15..19
722
723        let handle_in_h3 = unsafe { Handle::from_usize_unchecked(h3.index() + 1) }; // 1 in 0..3
724        let handle_in_h2 = unsafe { Handle::from_usize_unchecked(h2.index() + 5) }; // 10 in 5..15
725        let handle_in_h4 = unsafe { Handle::from_usize_unchecked(h4.index() + 2) }; // 17 in 15..19
726
727        assert_eq!(arena.get_span(handle_in_h3), Span::new(0, 3));
728        assert_eq!(arena.get_span(handle_in_h2), Span::new(5, 15));
729        assert_eq!(arena.get_span(handle_in_h4), Span::new(15, 19));
730    }
731
732    #[test]
733    #[should_panic]
734    fn get_span_panic_freed() {
735        let mut arena: Arena<u8> = Arena::new();
736        let h1 = arena.append(1, 5);
737        arena.free(h1);
738        arena.get_span(h1);
739    }
740
741    #[test]
742    #[should_panic]
743    fn index_panic_freed() {
744        let mut arena: Arena<u8> = Arena::new();
745        let h1 = arena.append(1, 5);
746        arena.free(h1);
747        let _ = arena[h1];
748    }
749
750    #[test]
751    #[should_panic]
752    fn index_mut_panic_freed() {
753        let mut arena: Arena<u8> = Arena::new();
754        let h1 = arena.append(1, 5);
755        arena.free(h1);
756        arena[h1] = 9;
757    }
758
759    #[test]
760    #[should_panic]
761    fn free_panic_middle_of_span() {
762        let mut arena: Arena<u8> = Arena::new();
763        let h1 = arena.append(1, 5); // Span 0..5
764        let handle_in_middle = unsafe { Handle::from_usize_unchecked(h1.index() + 2) }; // Index 2
765        arena.free(handle_in_middle);
766    }
767
768    #[test]
769    fn append_after_free_all() {
770        let mut arena: Arena<u8> = Arena::new();
771        let h1 = arena.append(1, 5); // Span 0..5
772        let h2 = arena.append(2, 5); // Span 5..10
773        arena.free(h1);
774        arena.free(h2);
775        assert!(arena.is_empty());
776        assert_eq!(arena.free_spans(), &[Span::new(0, 10)]);
777
778        let h3 = arena.append(3, 10); // Should reuse 0..10
779        assert_eq!(h3.index(), 0);
780        assert_eq!(arena[h3], 3);
781        for i in 0..10 {
782            let handle = unsafe { Handle::from_usize_unchecked(i) };
783            assert_eq!(arena[handle], 3);
784        }
785        assert_eq!(arena.spans(), &[Span::new(0, 10)]);
786        assert!(arena.free_spans().is_empty());
787    }
788
789    #[test]
790    fn merge_free_spans() {
791        let mut arena: Arena<u8> = Arena::new();
792        let h1 = arena.append(1, 5); // 0..5
793        let h2 = arena.append(2, 5); // 5..10
794        let h3 = arena.append(3, 5); // 10..15
795        arena.free(h1); // Free 0..5
796        arena.free(h3); // Free 10..15
797        assert_eq!(arena.free_spans(), &[Span::new(0, 5), Span::new(10, 15)]);
798
799        arena.free(h2); // Free 5..10, should merge with 0..5 and 10..15
800        assert_eq!(arena.free_spans(), &[Span::new(0, 15)]);
801        assert!(arena.spans().is_empty());
802    }
803
804    #[test]
805    fn append_exact_fit() {
806        let mut arena: Arena<u8> = Arena::new();
807        let h1 = arena.append(1, 10); // 0..10
808        arena.free(h1); // Free 0..10
809        let h2 = arena.append(2, 10); // Should reuse 0..10 exactly
810        assert_eq!(h2.index(), 0);
811        assert_eq!(arena[h2], 2);
812        assert_eq!(arena.spans(), &[Span::new(0, 10)]);
813        assert!(arena.free_spans().is_empty());
814    }
815
816    #[test]
817    fn append_larger_than_free() {
818        let mut arena: Arena<u8> = Arena::new();
819        let h1 = arena.append(1, 5); // 0..5
820        arena.free(h1); // Free 0..5
821        let h2 = arena.append(2, 10); // Needs 10, only 5 free, so append at 5..15
822        assert_eq!(h2.index(), 5);
823        assert_eq!(arena[h2], 2);
824        assert_eq!(arena.spans(), &[Span::new(5, 15)]);
825        assert_eq!(arena.free_spans(), &[Span::new(0, 5)]);
826    }
827
828    #[test]
829    fn multiple_handles_same_span() {
830        let mut arena: Arena<u8> = Arena::new();
831        let h1 = arena.append(1, 5); // 0..5
832        for i in 0..5 {
833            let handle = unsafe { Handle::from_usize_unchecked(h1.index() + i) };
834            assert_eq!(arena.get_span(handle), Span::new(0, 5));
835        }
836    }
837
838    #[test]
839    fn iterate_arena() {
840        let mut arena: Arena<u8> = Arena::new();
841        let h1 = arena.append(1, 3); // 0..3
842        let h2 = arena.append(2, 2); // 3..5
843        let mut iter = arena.iter();
844        assert_eq!(iter.next(), Some((h1, &1)));
845        assert_eq!(
846            iter.next(),
847            Some((unsafe { Handle::from_usize_unchecked(1) }, &1))
848        );
849        assert_eq!(
850            iter.next(),
851            Some((unsafe { Handle::from_usize_unchecked(2) }, &1))
852        );
853        assert_eq!(iter.next(), Some((h2, &2)));
854        assert_eq!(
855            iter.next(),
856            Some((unsafe { Handle::from_usize_unchecked(4) }, &2))
857        );
858        assert_eq!(iter.next(), None);
859    }
860
861    #[test]
862    fn drain_arena() {
863        let mut arena: Arena<u8> = Arena::new();
864        let h1 = arena.append(1, 3); // 0..3
865        let h2 = arena.append(2, 2); // 3..5
866        let drained: Vec<_> = arena.drain().collect();
867        assert_eq!(drained.len(), 5);
868        assert_eq!(drained[0], (h1, 1, Span::new(0, 3)));
869        assert_eq!(
870            drained[1],
871            (
872                unsafe { Handle::from_usize_unchecked(1) },
873                1,
874                Span::new(0, 3)
875            )
876        );
877        assert_eq!(
878            drained[2],
879            (
880                unsafe { Handle::from_usize_unchecked(2) },
881                1,
882                Span::new(0, 3)
883            )
884        );
885        assert_eq!(drained[3], (h2, 2, Span::new(3, 5)));
886        assert_eq!(
887            drained[4],
888            (
889                unsafe { Handle::from_usize_unchecked(4) },
890                2,
891                Span::new(3, 5)
892            )
893        );
894        assert!(arena.is_empty());
895        assert!(arena.spans().is_empty());
896        assert!(arena.free_spans().is_empty());
897    }
898
899    #[test]
900    fn test_with_struct() {
901        #[derive(Debug, Clone, PartialEq)]
902        struct TestStruct {
903            a: u32,
904            b: u32,
905        }
906
907        let mut arena: Arena<TestStruct> = Arena::new();
908        let val1 = TestStruct { a: 1, b: 2 };
909        let val2 = TestStruct { a: 3, b: 4 };
910        let h1 = arena.append(val1.clone(), 5);
911        let h2 = arena.append(val2.clone(), 5);
912        assert_eq!(arena[h1], val1);
913        assert_eq!(arena[h2], val2);
914        arena.free(h1);
915        let h3 = arena.append(val2.clone(), 5);
916        assert_eq!(h3.index(), 0);
917        assert_eq!(arena[h3], val2);
918    }
919
920    #[test]
921    fn test_zero_sized() {
922        #[derive(Clone, Debug, PartialEq)]
923        struct ZeroSized;
924
925        let mut arena: Arena<ZeroSized> = Arena::new();
926        let h1 = arena.append(ZeroSized, 10);
927        assert_eq!(arena.len(), 10);
928        for i in 0..10 {
929            let handle = unsafe { Handle::from_usize_unchecked(h1.index() + i) };
930            assert_eq!(arena[handle], ZeroSized);
931        }
932        arena.free(h1);
933        assert!(arena.is_empty());
934    }
935
936    #[test]
937    fn test_fetch_if() {
938        let mut arena: Arena<u8> = Arena::new();
939        let _h1 = arena.append(1, 5);
940        let h2 = arena.append(2, 5);
941        let found = arena.fetch_if(|&v| v == 2);
942        assert_eq!(found, Some(h2));
943        let not_found = arena.fetch_if(|&v| v == 3);
944        assert_eq!(not_found, None);
945    }
946
947    #[test]
948    fn test_fetch_if_or_append_custom() {
949        #[derive(Clone, Debug)]
950        struct Person {
951            name: String,
952            age: u32,
953        }
954
955        let mut arena: Arena<Person> = Arena::new();
956        let alice1 = Person {
957            name: "Alice".to_string(),
958            age: 30,
959        };
960        let alice2 = Person {
961            name: "Alice".to_string(),
962            age: 31,
963        };
964        let bob = Person {
965            name: "Bob".to_string(),
966            age: 25,
967        };
968
969        let h1 = arena.fetch_if_or_append(alice1.clone(), 1, |p1, p2| p1.name == p2.name);
970        let h2 = arena.fetch_if_or_append(alice2.clone(), 1, |p1, p2| p1.name == p2.name);
971        assert_eq!(h1, h2); // Same name, should reuse h1
972        assert_eq!(arena[h1].age, 30);
973
974        let h3 = arena.fetch_if_or_append(bob.clone(), 1, |p1, p2| p1.name == p2.name);
975        assert_ne!(h1, h3);
976        assert_eq!(arena[h3].name, "Bob");
977    }
978
979    #[test]
980    fn test_clear() {
981        let mut arena: Arena<u8> = Arena::new();
982        let h1 = arena.append(1, 5);
983        let h2 = arena.append(2, 5);
984        assert_eq!(arena.len(), 10);
985        arena.clear();
986        assert!(arena.is_empty());
987        assert!(arena.spans().is_empty());
988        assert!(arena.free_spans().is_empty());
989        assert!(arena.try_get(h1).is_err());
990        assert!(arena.try_get(h2).is_err());
991    }
992
993    #[test]
994    fn free_and_reuse_partially() {
995        let mut arena: Arena<u8> = Arena::new();
996        let h1 = arena.append(1, 10); // 0..10
997        arena.free(h1); // Free 0..10
998        let h2 = arena.append(2, 3); // Reuse 0..3
999        let h3 = arena.append(3, 4); // Reuse 3..7
1000        assert_eq!(h2.index(), 0);
1001        assert_eq!(h3.index(), 3);
1002        assert_eq!(arena.spans(), &[Span::new(0, 3), Span::new(3, 7)]);
1003        assert_eq!(arena.free_spans(), &[Span::new(7, 10)]);
1004        assert_eq!(arena[h2], 2);
1005        assert_eq!(arena[h3], 3);
1006    }
1007
1008    #[test]
1009    fn handle_ordering() {
1010        let mut arena: Arena<u8> = Arena::new();
1011        let h1 = arena.append(1, 1);
1012        let h2 = arena.append(2, 1);
1013        assert!(h1 < h2);
1014        arena.free(h1);
1015        let h3 = arena.append(3, 1); // Should reuse h1's spot
1016        assert_eq!(h3, h1);
1017        assert!(h3 < h2);
1018    }
1019
1020    #[test]
1021    fn large_counts() {
1022        let mut arena: Arena<u8> = Arena::new();
1023        let h1 = arena.append(1, 1000);
1024        assert_eq!(arena.len(), 1000);
1025        for i in 0..1000 {
1026            let handle = unsafe { Handle::from_usize_unchecked(h1.index() + i) };
1027            assert_eq!(arena[handle], 1);
1028        }
1029        arena.free(h1);
1030        assert!(arena.is_empty());
1031    }
1032}