intuicio_framework_arena/
lib.rs

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