intuicio_framework_arena/
lib.rs

1use intuicio_data::{
2    Finalize,
3    lifetime::{Lifetime, ReadLock, ValueReadAccess, ValueWriteAccess},
4    type_hash::TypeHash,
5};
6use serde::{Deserialize, Serialize};
7use std::{
8    alloc::{Layout, alloc, dealloc},
9    error::Error,
10    marker::PhantomData,
11};
12
13#[derive(Debug, PartialEq, Eq)]
14pub enum ArenaError {
15    InvalidAreaType { type_hash: TypeHash },
16    IndexNotFound { type_hash: TypeHash, index: Index },
17    CannotReadItem { type_hash: TypeHash, index: Index },
18    CannotWriteItem { type_hash: TypeHash, index: Index },
19    ArenaNotFound { type_hash: TypeHash },
20}
21
22impl Error for ArenaError {}
23
24impl std::fmt::Display for ArenaError {
25    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26        match self {
27            Self::InvalidAreaType { type_hash } => {
28                write!(f, "Invalid area type: {:?}", type_hash)
29            }
30            Self::IndexNotFound { type_hash, index } => {
31                write!(f, "Index: {} not found in arena: {:?}", index, type_hash)
32            }
33            Self::CannotReadItem { type_hash, index } => {
34                write!(
35                    f,
36                    "Cannot read item at index: {} in arena: {:?}",
37                    index, type_hash
38                )
39            }
40            Self::CannotWriteItem { type_hash, index } => {
41                write!(
42                    f,
43                    "Cannot write item at index: {} in arena: {:?}",
44                    index, type_hash
45                )
46            }
47            Self::ArenaNotFound { type_hash } => {
48                write!(f, "Arena not found: {:?}", type_hash)
49            }
50        }
51    }
52}
53
54#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
55pub struct Index {
56    id: u32,
57    generation: u32,
58}
59
60impl Default for Index {
61    fn default() -> Self {
62        Self::INVALID
63    }
64}
65
66impl Index {
67    pub const INVALID: Self = unsafe { Self::new_unchecked(u32::MAX, 0) };
68
69    pub const fn new(id: u32, generation: u32) -> Option<Self> {
70        if id < u32::MAX {
71            Some(Self { id, generation })
72        } else {
73            None
74        }
75    }
76
77    /// # Safety
78    pub const unsafe fn new_unchecked(id: u32, generation: u32) -> Self {
79        Self { id, generation }
80    }
81
82    pub const fn is_valid(self) -> bool {
83        self.id < u32::MAX
84    }
85
86    pub const fn id(self) -> u32 {
87        self.id
88    }
89
90    pub const fn generation(self) -> u32 {
91        self.generation
92    }
93
94    pub const fn to_u64(self) -> u64 {
95        ((self.generation as u64) << 32) | self.id as u64
96    }
97
98    pub const fn from_u64(value: u64) -> Self {
99        Self {
100            generation: (value >> 32) as u32,
101            id: value as u32,
102        }
103    }
104
105    pub const fn bump_generation(mut self) -> Self {
106        self.generation = self.generation.wrapping_add(1);
107        self
108    }
109}
110
111impl std::fmt::Display for Index {
112    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
113        if self.is_valid() {
114            write!(f, "@{}:#{}", self.id, self.generation)
115        } else {
116            write!(f, "@none:#{}", self.generation)
117        }
118    }
119}
120
121#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
122pub struct AnyIndex {
123    index: Index,
124    type_hash: TypeHash,
125}
126
127impl Default for AnyIndex {
128    fn default() -> Self {
129        Self::INVALID
130    }
131}
132
133impl AnyIndex {
134    pub const INVALID: Self = Self::new(Index::INVALID, TypeHash::INVALID);
135
136    pub const fn new(index: Index, type_hash: TypeHash) -> Self {
137        Self { index, type_hash }
138    }
139
140    pub fn is<T>(self) -> bool {
141        self.type_hash == TypeHash::of::<T>()
142    }
143
144    pub const fn is_valid(self) -> bool {
145        self.index.is_valid()
146    }
147
148    pub const fn index(self) -> Index {
149        self.index
150    }
151
152    pub const fn type_hash(self) -> TypeHash {
153        self.type_hash
154    }
155}
156
157impl std::fmt::Display for AnyIndex {
158    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
159        write!(f, "{}:^{}", self.index, self.type_hash)
160    }
161}
162
163pub struct Arena {
164    type_hash: TypeHash,
165    item_layout: Layout,
166    finalizer: unsafe fn(*mut ()),
167    memory: *mut u8,
168    capacity: usize,
169    layout: Layout,
170    lifetime: Lifetime,
171    indices_lifetimes: Vec<(Index, Lifetime)>,
172    indices_to_reuse: Vec<Index>,
173    index_generator: u32,
174}
175
176unsafe impl Send for Arena {}
177unsafe impl Sync for Arena {}
178
179impl Drop for Arena {
180    fn drop(&mut self) {
181        self.clear();
182        self.lifetime.write_lock().using(|| unsafe {
183            dealloc(self.memory, self.layout);
184        });
185    }
186}
187
188impl Arena {
189    pub fn new<T: Finalize>(capacity: usize) -> Self {
190        unsafe {
191            Self::new_raw(
192                TypeHash::of::<T>(),
193                Layout::new::<T>(),
194                T::finalize_raw,
195                capacity,
196            )
197        }
198    }
199
200    /// # Safety
201    pub unsafe fn new_raw(
202        type_hash: TypeHash,
203        mut item_layout: Layout,
204        finalizer: unsafe fn(*mut ()),
205        mut capacity: usize,
206    ) -> Self {
207        item_layout = item_layout.pad_to_align();
208        capacity = capacity.max(1);
209        let (memory, layout) = unsafe { Self::allocate_memory_unlocked(item_layout, capacity) };
210        Self {
211            type_hash,
212            item_layout,
213            finalizer,
214            memory,
215            capacity,
216            layout,
217            lifetime: Default::default(),
218            indices_lifetimes: Vec::with_capacity(capacity),
219            indices_to_reuse: Default::default(),
220            index_generator: 0,
221        }
222    }
223
224    pub fn type_hash(&self) -> TypeHash {
225        self.type_hash
226    }
227
228    pub fn item_layout(&self) -> &Layout {
229        &self.item_layout
230    }
231
232    pub fn finalizer(&self) -> unsafe fn(*mut ()) {
233        self.finalizer
234    }
235
236    pub fn capacity(&self) -> usize {
237        self.lifetime.read_lock().using(|| self.capacity)
238    }
239
240    pub fn len(&self) -> usize {
241        self.lifetime
242            .read_lock()
243            .using(|| self.indices_lifetimes.len())
244    }
245
246    pub fn is_empty(&self) -> bool {
247        self.lifetime
248            .read_lock()
249            .using(|| self.indices_lifetimes.is_empty())
250    }
251
252    pub fn contains(&self, index: Index) -> bool {
253        self.lifetime
254            .read_lock()
255            .using(|| self.indices_lifetimes.iter().any(|(idx, _)| *idx == index))
256    }
257
258    pub fn clear(&mut self) {
259        self.lifetime.write_lock().using(|| {
260            for index in 0..self.indices_lifetimes.len() {
261                unsafe {
262                    let target = self.memory.add(index * self.item_layout.size());
263                    (self.finalizer)(target.cast());
264                }
265            }
266            self.indices_lifetimes.clear();
267        });
268    }
269
270    pub fn insert<T>(&mut self, value: T) -> Result<Index, ArenaError> {
271        self.lifetime.write_lock().using(move || unsafe {
272            let type_hash = TypeHash::of::<T>();
273            if self.type_hash == type_hash {
274                let (index, target) = self.allocate_unlocked();
275                target.cast::<T>().write(value);
276                Ok(index)
277            } else {
278                Err(ArenaError::InvalidAreaType { type_hash })
279            }
280        })
281    }
282
283    /// # Safety
284    pub unsafe fn allocate(&mut self) -> (Index, *mut u8) {
285        self.lifetime
286            .write_lock()
287            .using(|| unsafe { self.allocate_unlocked() })
288    }
289
290    pub fn remove(&mut self, index: Index) -> Result<(), ArenaError> {
291        self.lifetime.write_lock().using(|| {
292            if self.indices_lifetimes.is_empty() {
293                return Err(ArenaError::IndexNotFound {
294                    type_hash: self.type_hash,
295                    index,
296                });
297            }
298            let Some(idx) = self
299                .indices_lifetimes
300                .iter()
301                .position(|(idx, _)| *idx == index)
302            else {
303                return Err(ArenaError::IndexNotFound {
304                    type_hash: self.type_hash,
305                    index,
306                });
307            };
308            self.indices_to_reuse.push(index);
309            unsafe {
310                let target = self.memory.add(idx * self.item_layout.size());
311                (self.finalizer)(target.cast());
312                self.indices_lifetimes.swap_remove(idx);
313                if self.indices_lifetimes.len() != idx {
314                    let source = self
315                        .memory
316                        .add(self.indices_lifetimes.len() * self.item_layout.size());
317                    source.copy_to(target, self.item_layout.size());
318                    self.indices_lifetimes[idx].1 = Default::default();
319                }
320            }
321            Ok(())
322        })
323    }
324
325    pub fn read<T>(&self, index: Index) -> Result<ValueReadAccess<T>, ArenaError> {
326        self.lifetime.read_lock().using(|| unsafe {
327            let type_hash = TypeHash::of::<T>();
328            if self.type_hash != type_hash {
329                return Err(ArenaError::InvalidAreaType { type_hash });
330            }
331            if let Some(idx) = self
332                .indices_lifetimes
333                .iter()
334                .position(|(idx, _)| *idx == index)
335            {
336                let address = self
337                    .memory
338                    .cast_const()
339                    .add(idx * self.item_layout.size())
340                    .cast::<T>();
341                self.indices_lifetimes[idx]
342                    .1
343                    .read_ptr(address)
344                    .ok_or(ArenaError::CannotReadItem {
345                        type_hash: self.type_hash,
346                        index,
347                    })
348            } else {
349                Err(ArenaError::IndexNotFound {
350                    type_hash: self.type_hash,
351                    index,
352                })
353            }
354        })
355    }
356
357    pub fn write<T>(&self, index: Index) -> Result<ValueWriteAccess<T>, ArenaError> {
358        self.lifetime.read_lock().using(|| unsafe {
359            let type_hash = TypeHash::of::<T>();
360            if self.type_hash != type_hash {
361                return Err(ArenaError::InvalidAreaType { type_hash });
362            }
363            if let Some(idx) = self
364                .indices_lifetimes
365                .iter()
366                .position(|(idx, _)| *idx == index)
367            {
368                let address = self.memory.add(idx * self.item_layout.size()).cast::<T>();
369                self.indices_lifetimes[idx].1.write_ptr(address).ok_or(
370                    ArenaError::CannotWriteItem {
371                        type_hash: self.type_hash,
372                        index,
373                    },
374                )
375            } else {
376                Err(ArenaError::IndexNotFound {
377                    type_hash: self.type_hash,
378                    index,
379                })
380            }
381        })
382    }
383
384    /// # Safety
385    pub unsafe fn read_ptr(&self, index: Index) -> Result<*const u8, ArenaError> {
386        self.lifetime.read_lock().using(|| unsafe {
387            if let Some(idx) = self
388                .indices_lifetimes
389                .iter()
390                .position(|(idx, _)| *idx == index)
391            {
392                Ok(self.memory.cast_const().add(idx * self.item_layout.size()))
393            } else {
394                Err(ArenaError::IndexNotFound {
395                    type_hash: self.type_hash,
396                    index,
397                })
398            }
399        })
400    }
401
402    /// # Safety
403    pub unsafe fn write_ptr(&self, index: Index) -> Result<*mut u8, ArenaError> {
404        self.lifetime.read_lock().using(|| unsafe {
405            if let Some(idx) = self
406                .indices_lifetimes
407                .iter()
408                .position(|(idx, _)| *idx == index)
409            {
410                Ok(self.memory.add(idx * self.item_layout.size()))
411            } else {
412                Err(ArenaError::IndexNotFound {
413                    type_hash: self.type_hash,
414                    index,
415                })
416            }
417        })
418    }
419
420    pub fn is<T>(&self, index: Index) -> Result<bool, ArenaError> {
421        self.is_raw(index, TypeHash::of::<T>())
422    }
423
424    pub fn is_raw(&self, index: Index, type_hash: TypeHash) -> Result<bool, ArenaError> {
425        self.lifetime.read_lock().using(|| {
426            if self.type_hash == type_hash {
427                Ok(self.indices_lifetimes.iter().any(|(idx, _)| *idx == index))
428            } else {
429                Err(ArenaError::InvalidAreaType { type_hash })
430            }
431        })
432    }
433
434    pub fn indices(&self) -> impl Iterator<Item = Index> + '_ {
435        let _lock = self.lifetime.read_lock();
436        ArenaLockedIter {
437            inner: self.indices_lifetimes.iter().map(|(index, _)| *index),
438            _lock,
439        }
440    }
441
442    pub fn iter<'a, T: 'a>(&'a self) -> impl Iterator<Item = ValueReadAccess<'a, T>> {
443        let type_hash = TypeHash::of::<T>();
444        (self.type_hash == type_hash)
445            .then_some(())
446            .into_iter()
447            .flat_map(|_| {
448                let _lock = self.lifetime.read_lock();
449                ArenaLockedIter {
450                    inner: ArenaIter {
451                        arena: self,
452                        index: 0,
453                        _phantom: PhantomData,
454                    },
455                    _lock,
456                }
457            })
458    }
459
460    pub fn iter_mut<'a, T: 'a>(&'a self) -> impl Iterator<Item = ValueWriteAccess<'a, T>> {
461        let type_hash = TypeHash::of::<T>();
462        (self.type_hash == type_hash)
463            .then_some(())
464            .into_iter()
465            .flat_map(|_| {
466                let _lock = self.lifetime.read_lock();
467                ArenaLockedIter {
468                    inner: ArenaIterMut {
469                        arena: self,
470                        index: 0,
471                        _phantom: PhantomData,
472                    },
473                    _lock,
474                }
475            })
476    }
477
478    /// # Safety
479    unsafe fn allocate_unlocked(&mut self) -> (Index, *mut u8) {
480        if self.indices_lifetimes.len() == self.capacity {
481            self.capacity *= 2;
482            unsafe { self.reallocate_unlocked(self.indices_lifetimes.len(), self.capacity) };
483        }
484        let index = match self.indices_to_reuse.pop() {
485            Some(index) => index.bump_generation(),
486            None => {
487                let id = self.index_generator;
488                self.index_generator = self.index_generator.wrapping_add(1);
489                unsafe { Index::new_unchecked(id, 0) }
490            }
491        };
492        let idx = self.indices_lifetimes.len();
493        self.indices_lifetimes.push((index, Default::default()));
494        (index, unsafe {
495            self.memory.add(idx * self.item_layout.size())
496        })
497    }
498
499    unsafe fn reallocate_unlocked(&mut self, size: usize, capacity: usize) {
500        let (memory, layout) =
501            unsafe { Self::allocate_memory_unlocked(self.item_layout, capacity) };
502        unsafe { self.memory.copy_to(memory, self.item_layout.size() * size) };
503        unsafe { dealloc(self.memory, self.layout) };
504        self.memory = memory;
505        self.layout = layout;
506        for (_, lifetime) in &mut self.indices_lifetimes {
507            *lifetime = Default::default();
508        }
509    }
510
511    unsafe fn allocate_memory_unlocked(
512        mut item_layout: Layout,
513        capacity: usize,
514    ) -> (*mut u8, Layout) {
515        item_layout = item_layout.pad_to_align();
516        let layout = if item_layout.size() == 0 {
517            unsafe { Layout::from_size_align_unchecked(1, 1) }
518        } else {
519            unsafe {
520                Layout::from_size_align_unchecked(
521                    item_layout.size() * capacity,
522                    item_layout.align(),
523                )
524            }
525        };
526        let memory = unsafe { alloc(layout) };
527        (memory, layout)
528    }
529}
530
531#[derive(Default)]
532pub struct AnyArena {
533    pub new_arena_capacity: usize,
534    arenas: Vec<Arena>,
535}
536
537impl AnyArena {
538    pub fn with_new_arena_capacity(mut self, capacity: usize) -> Self {
539        self.new_arena_capacity = capacity;
540        self
541    }
542
543    pub fn len(&self) -> usize {
544        self.arenas.iter().map(|arena| arena.len()).sum()
545    }
546
547    pub fn is_empty(&self) -> bool {
548        self.arenas.iter().all(|arena| arena.is_empty())
549    }
550
551    pub fn contains(&self, index: AnyIndex) -> bool {
552        self.arenas
553            .iter()
554            .find(|arena| arena.type_hash == index.type_hash)
555            .map(|arena| arena.contains(index.index))
556            .unwrap_or_default()
557    }
558
559    pub fn arenas(&self) -> &[Arena] {
560        &self.arenas
561    }
562
563    pub fn arenas_mut(&mut self) -> &mut [Arena] {
564        &mut self.arenas
565    }
566
567    pub fn arena<T>(&self) -> Option<&Arena> {
568        unsafe { self.arena_raw(TypeHash::of::<T>()) }
569    }
570
571    /// # Safety
572    pub unsafe fn arena_raw(&self, type_hash: TypeHash) -> Option<&Arena> {
573        self.arenas
574            .iter()
575            .find(|arena| arena.type_hash == type_hash)
576    }
577
578    pub fn ensure_arena<T: Finalize>(&mut self) -> &mut Arena {
579        unsafe {
580            self.ensure_arena_raw(
581                TypeHash::of::<T>(),
582                Layout::new::<T>().pad_to_align(),
583                T::finalize_raw,
584            )
585        }
586    }
587
588    /// # Safety
589    pub unsafe fn ensure_arena_raw(
590        &mut self,
591        type_hash: TypeHash,
592        item_layout: Layout,
593        finalizer: unsafe fn(*mut ()),
594    ) -> &mut Arena {
595        let index = match self
596            .arenas
597            .iter()
598            .position(|arena| arena.type_hash == type_hash)
599        {
600            Some(index) => index,
601            None => {
602                self.arenas.push(unsafe {
603                    Arena::new_raw(type_hash, item_layout, finalizer, self.new_arena_capacity)
604                });
605                self.arenas.len() - 1
606            }
607        };
608        &mut self.arenas[index]
609    }
610
611    pub fn clear(&mut self) {
612        for arena in &mut self.arenas {
613            arena.clear();
614        }
615        self.arenas.clear();
616    }
617
618    pub fn insert<T: Finalize>(&mut self, value: T) -> AnyIndex {
619        let type_hash = TypeHash::of::<T>();
620        if let Some(arena) = self
621            .arenas
622            .iter_mut()
623            .find(|arena| arena.type_hash == type_hash)
624        {
625            AnyIndex::new(arena.insert(value).unwrap(), type_hash)
626        } else {
627            let mut arena = Arena::new::<T>(self.new_arena_capacity);
628            let index = arena.insert(value).unwrap();
629            self.arenas.push(arena);
630            AnyIndex::new(index, type_hash)
631        }
632    }
633
634    /// # Safety
635    pub unsafe fn allocate(
636        &mut self,
637        type_hash: TypeHash,
638        item_layout: Layout,
639        finalizer: unsafe fn(*mut ()),
640    ) -> (AnyIndex, *mut u8) {
641        if let Some(arena) = self
642            .arenas
643            .iter_mut()
644            .find(|arena| arena.type_hash == type_hash)
645        {
646            let (index, address) = unsafe { arena.allocate() };
647            (AnyIndex::new(index, type_hash), address)
648        } else {
649            let mut arena = unsafe {
650                Arena::new_raw(type_hash, item_layout, finalizer, self.new_arena_capacity)
651            };
652            let (index, address) = unsafe { arena.allocate() };
653            self.arenas.push(arena);
654            (AnyIndex::new(index, type_hash), address)
655        }
656    }
657
658    pub fn remove(&mut self, index: AnyIndex) -> Result<(), ArenaError> {
659        if let Some(idx) = self
660            .arenas
661            .iter_mut()
662            .position(|arena| arena.type_hash == index.type_hash)
663        {
664            let result = self.arenas[idx].remove(index.index);
665            if self.arenas[idx].is_empty() {
666                self.arenas.swap_remove(idx);
667            }
668            result
669        } else {
670            Err(ArenaError::ArenaNotFound {
671                type_hash: index.type_hash,
672            })
673        }
674    }
675
676    pub fn read<T>(&self, index: AnyIndex) -> Result<ValueReadAccess<T>, ArenaError> {
677        if let Some(arena) = self
678            .arenas
679            .iter()
680            .find(|arena| arena.type_hash == index.type_hash)
681        {
682            arena.read(index.index)
683        } else {
684            Err(ArenaError::ArenaNotFound {
685                type_hash: index.type_hash,
686            })
687        }
688    }
689
690    pub fn write<T>(&self, index: AnyIndex) -> Result<ValueWriteAccess<T>, ArenaError> {
691        if let Some(arena) = self
692            .arenas
693            .iter()
694            .find(|arena| arena.type_hash == index.type_hash)
695        {
696            arena.write(index.index)
697        } else {
698            Err(ArenaError::ArenaNotFound {
699                type_hash: index.type_hash,
700            })
701        }
702    }
703
704    /// # Safety
705    pub unsafe fn read_ptr(&self, index: AnyIndex) -> Result<*const u8, ArenaError> {
706        if let Some(arena) = self
707            .arenas
708            .iter()
709            .find(|arena| arena.type_hash == index.type_hash)
710        {
711            unsafe { arena.read_ptr(index.index) }
712        } else {
713            Err(ArenaError::ArenaNotFound {
714                type_hash: index.type_hash,
715            })
716        }
717    }
718
719    /// # Safety
720    pub unsafe fn write_ptr(&self, index: AnyIndex) -> Result<*mut u8, ArenaError> {
721        if let Some(arena) = self
722            .arenas
723            .iter()
724            .find(|arena| arena.type_hash == index.type_hash)
725        {
726            unsafe { arena.write_ptr(index.index) }
727        } else {
728            Err(ArenaError::ArenaNotFound {
729                type_hash: index.type_hash,
730            })
731        }
732    }
733
734    pub fn is<T>(&self, index: AnyIndex) -> Result<bool, ArenaError> {
735        self.is_raw(index, TypeHash::of::<T>())
736    }
737
738    pub fn is_raw(&self, index: AnyIndex, type_hash: TypeHash) -> Result<bool, ArenaError> {
739        for arena in &self.arenas {
740            if arena.type_hash == type_hash {
741                return Ok(arena.contains(index.index));
742            }
743        }
744        Err(ArenaError::ArenaNotFound {
745            type_hash: index.type_hash,
746        })
747    }
748
749    pub fn indices(&self) -> impl Iterator<Item = AnyIndex> + '_ {
750        self.arenas.iter().flat_map(|arena| {
751            arena
752                .indices()
753                .map(move |index| AnyIndex::new(index, arena.type_hash))
754        })
755    }
756
757    pub fn iter<'a, T: 'a>(&'a self) -> impl Iterator<Item = ValueReadAccess<'a, T>> {
758        self.arenas.iter().flat_map(|arena| arena.iter::<T>())
759    }
760
761    pub fn iter_mut<'a, T: 'a>(&'a self) -> impl Iterator<Item = ValueWriteAccess<'a, T>> {
762        self.arenas.iter().flat_map(|arena| arena.iter_mut::<T>())
763    }
764}
765
766pub struct ArenaLockedIter<T, I: Iterator<Item = T>> {
767    inner: I,
768    _lock: ReadLock,
769}
770
771impl<T, I: Iterator<Item = T>> Iterator for ArenaLockedIter<T, I> {
772    type Item = T;
773
774    fn next(&mut self) -> Option<Self::Item> {
775        self.inner.next()
776    }
777}
778
779pub struct ArenaIter<'a, T> {
780    index: usize,
781    arena: &'a Arena,
782    _phantom: PhantomData<fn() -> T>,
783}
784
785impl<'a, T: 'a> Iterator for ArenaIter<'a, T> {
786    type Item = ValueReadAccess<'a, T>;
787
788    fn next(&mut self) -> Option<Self::Item> {
789        if self.index < self.arena.indices_lifetimes.len() {
790            unsafe {
791                let address = self.arena.memory.cast::<T>().add(self.index);
792                let result = self.arena.indices_lifetimes[self.index]
793                    .1
794                    .read_ptr::<T>(address);
795                self.index += 1;
796                result
797            }
798        } else {
799            None
800        }
801    }
802
803    fn size_hint(&self) -> (usize, Option<usize>) {
804        let size = self.arena.indices_lifetimes.len() - self.index;
805        (size, Some(size))
806    }
807}
808
809pub struct ArenaIterMut<'a, T> {
810    index: usize,
811    arena: &'a Arena,
812    _phantom: PhantomData<fn() -> T>,
813}
814
815impl<'a, T: 'a> Iterator for ArenaIterMut<'a, T> {
816    type Item = ValueWriteAccess<'a, T>;
817
818    fn next(&mut self) -> Option<Self::Item> {
819        if self.index < self.arena.indices_lifetimes.len() {
820            unsafe {
821                let address = self.arena.memory.cast::<T>().add(self.index);
822                let result = self.arena.indices_lifetimes[self.index]
823                    .1
824                    .write_ptr::<T>(address);
825                self.index += 1;
826                result
827            }
828        } else {
829            None
830        }
831    }
832
833    fn size_hint(&self) -> (usize, Option<usize>) {
834        let size = self.arena.indices_lifetimes.len() - self.index;
835        (size, Some(size))
836    }
837}
838
839#[cfg(test)]
840mod tests {
841    use super::*;
842
843    #[test]
844    fn test_async() {
845        fn is_async<T: Send + Sync>() {}
846
847        is_async::<Arena>();
848        is_async::<AnyArena>();
849    }
850
851    #[test]
852    fn test_arena() {
853        let mut arena = Arena::new::<String>(0);
854        assert_eq!(arena.type_hash(), TypeHash::of::<String>());
855        assert!(arena.is_empty());
856        assert_eq!(arena.len(), 0);
857        assert_eq!(arena.capacity(), 1);
858
859        let hello = arena.insert("Hello".to_owned()).unwrap();
860        assert!(!arena.is_empty());
861        assert_eq!(arena.len(), 1);
862        assert_eq!(arena.capacity(), 1);
863        assert!(arena.contains(hello));
864
865        let world = arena.insert("World!".to_owned()).unwrap();
866        assert!(!arena.is_empty());
867        assert_eq!(arena.len(), 2);
868        assert_eq!(arena.capacity(), 2);
869        assert!(arena.contains(world));
870
871        assert_eq!(arena.read::<String>(hello).unwrap().as_str(), "Hello");
872        assert_eq!(arena.read::<String>(world).unwrap().as_str(), "World!");
873
874        *arena.write(world).unwrap() = "world".to_owned();
875        assert_eq!(arena.read::<String>(world).unwrap().as_str(), "world");
876
877        assert_eq!(
878            arena
879                .iter::<String>()
880                .map(|item| item.to_owned())
881                .collect::<Vec<_>>(),
882            vec!["Hello".to_owned(), "world".to_owned()]
883        );
884
885        arena.remove(hello).unwrap();
886        assert!(!arena.is_empty());
887        assert_eq!(arena.len(), 1);
888        assert_eq!(arena.capacity(), 2);
889        assert!(!arena.contains(hello));
890
891        assert!(arena.read::<String>(hello).is_err());
892        assert_eq!(arena.read::<String>(world).unwrap().as_str(), "world");
893
894        arena.clear();
895        assert!(arena.is_empty());
896        assert_eq!(arena.len(), 0);
897        assert_eq!(arena.capacity(), 2);
898    }
899
900    #[test]
901    fn test_typed_arena() {
902        let mut arena = AnyArena::default();
903        assert!(arena.is_empty());
904        assert_eq!(arena.len(), 0);
905
906        let number = arena.insert(42usize);
907        assert!(!arena.is_empty());
908        assert_eq!(arena.len(), 1);
909        assert!(arena.contains(number));
910
911        let boolean = arena.insert(true);
912        assert!(!arena.is_empty());
913        assert_eq!(arena.len(), 2);
914        assert!(arena.contains(boolean));
915
916        assert_eq!(*arena.read::<usize>(number).unwrap(), 42);
917        assert!(*arena.read::<bool>(boolean).unwrap());
918
919        *arena.write(boolean).unwrap() = false;
920        assert!(!*arena.read::<bool>(boolean).unwrap());
921
922        arena.remove(number).unwrap();
923        assert!(!arena.is_empty());
924        assert_eq!(arena.len(), 1);
925        assert!(!arena.contains(number));
926
927        assert!(arena.read::<usize>(number).is_err());
928        assert!(!*arena.read::<bool>(boolean).unwrap());
929
930        arena.clear();
931        assert!(arena.is_empty());
932        assert_eq!(arena.len(), 0);
933    }
934}