rotunda/
lib.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3#![no_std]
4#![cfg_attr(
5    feature = "nightly",
6    feature(
7        ptr_metadata,
8        derive_coerce_pointee,
9        allocator_api,
10        read_buf,
11        core_io_borrowed_buf
12    )
13)]
14#![cfg_attr(all(feature = "nightly", feature = "std"), feature(can_vector))]
15#![warn(
16    missing_docs,
17    clippy::empty_line_after_doc_comments,
18    clippy::missing_safety_doc
19)]
20#![deny(unsafe_attr_outside_unsafe, unsafe_op_in_unsafe_fn)]
21
22//! This module contains types for using the arena allocation strategy. See the [`Arena`] type
23//! for more information on how to use arena allocation.
24//!
25//! # Arena allocation
26//!
27//! In many workloads, the lifetime of a heap allocation is scoped to a particular function call.
28//! For example:
29//!
30//! ```
31//! # #[derive(Default)]
32//! # struct SomeType {};
33//! # #[derive(Default)]
34//! # struct OtherType {};
35//! # fn use_values(_: &SomeType, _: &OtherType) {}
36//! fn some_function() {
37//!     let value = Box::new(SomeType::default());
38//!     let value_2 = Box::new(OtherType::default());
39//!
40//!     // Use `value` and `value_2` in the body of `some_function()`
41//!     // ...
42//!     use_values(&*value, &*value_2);
43//!
44//!     // `value` and `value_2` are dropped and deallocated here as the function returns.
45//! }
46//! ```
47//!
48//! If many values need to be allocated and deallocated for a function body, this can be
49//! inefficient as the heap allocator needs to do work to allocate and deallocate each
50//! individual value.
51//!
52//! To compensate for this, many strategies can be used so that values are allocated from
53//! a single block of memory, reducing the work that the memory allocator needs to do.
54//! One of these strategies is called arena allocation.
55//!
56//! The idea behind arena allocation is to preallocate a large block of memory, and then
57//! write values into that block as necessary. Values cannot be freed until the entire block
58//! is finished with, when every value is implicitly deallocated at once.
59//!
60//! # Examples
61//!
62//! To rewrite the above example `some_function()` using arena allocation provided by this crate,
63//! an `Arena` would need to be constructed or passed in to the function. Any transient data allocated
64//! by the function would then be allocated from the `Arena`:
65//!
66//! ```
67//! use rotunda::{Arena, handle::Handle};
68//!
69//! # #[derive(Default)]
70//! # struct SomeType {};
71//! # #[derive(Default)]
72//! # struct OtherType {};
73//! # fn use_values(_: &SomeType, _: &OtherType) {}
74//! fn some_function(arena: &Arena) {
75//!     // Allocate the values as before:
76//!     let value = Handle::new_in(&arena, SomeType::default());
77//!     let value_2 = Handle::new_in(&arena, OtherType::default());
78//!
79//!     // Use the values as before:
80//!     use_values(&*value, &*value_2);
81//!
82//!     // The values are dropped here, but the memory backing them in the arena is
83//!     // not deallocated until the `Arena` is dropped, or the `Arena::reset()` method
84//!     // is called.
85//! }
86//! ```
87//!
88//! The `Arena` can be visualised as an array of memory, with an integer marking the current
89//! end of the `Arena`. When the `Arena` is first initialised and has a block allocated, then
90//! the stack is empty:
91//!
92//! ```text
93//! +-------+-----------------------------------------------------------+
94//! |  (H)  |                                                           |
95//! +-------+-----------------------------------------------------------+
96//! ^       ^
97//! Header  Arena end
98//! ```
99//!
100//! Then, when `value` and `value_2` are allocated into the arena, they
101//! are written into the memory, and the end is adjusted to point into the
102//! next available memory space:
103//!
104//! ```text
105//! +-------+---------------+---------------+--------------------------------------+
106//! |  (H)  |     (data)    |     (data)    |                                      |
107//! +-------+---------------+---------------+--------------------------------------+
108//! ^       ^               ^               ^
109//! Header  value           value_2         Arena end
110//! ```
111//!
112//! Then, when `value` and `value_2` are dropped, their `drop` logic will be
113//! called, but the backing storage of the `Arena` will not shrink to release
114//! the memory; it will remain inaccessible for future allocations:
115//!
116//! ```text
117//! +-------+-------------------------------+--------------------------------------+
118//! |  (H)  |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx|                                      |
119//! +-------+-------------------------------+--------------------------------------+
120//! ^                                       ^
121//! Header                                  Arena end
122//! ```
123//!
124//! When the [`Arena::reset()`] method is called then the memory will be reclaimed,
125//! and will be usable for future allocations. Note that no active references are
126//! allowed into the `Arena` when [`Arena::reset()`] is called, so there is no
127//! danger of referring to dangling memory. When the `Arena` is dropped, the
128//! backing memory will be deallocated by the system allocator and returned to
129//! the operating system.
130//!
131//! If a block of memory in the arena is completely used up, then a new one will be
132//! allocated. Each block stores a pointer to the next block in its header, so blocks
133//! will be accessible. reseting an `Arena` will cause blocks to be stored in a free
134//! list so that they can be re-used later, reducing pressure on the memory allocator.
135//!
136//! # Handle Types
137//!
138//! The `arena` module comes with a few specialised handle types to make working with `Arena`s
139//! more ergonomic. These provide a few useful conveniences:
140//!
141//! * They have a lifetime which ensures that data allocated from the `Arena` cannot outlive the
142//!   `Arena`, preventing use after frees.
143//! * They handle `Drop` logic when the handle goes out of scope, preventing resource leaks.
144//!
145//! ## [`Handle`]
146//!
147//! The basic handle type is [`handle::Handle`], which is analogous to a `Box<T>` - it provides unique ownership
148//! of an object allocated in an [`Arena`], allows mutation, and drops the object when it goes out of scope.
149//!
150//! Read more in the [`handle`] module.
151//!
152//! ## [`RcHandle`] and [`WeakHandle`]
153//!
154//! These are reference counted shared ownership handle types, analogous to `Rc<T>` and `Weak<T>`.
155//!
156//! Read more in the [`rc_handle`] module.
157//!
158//! ## [`Buffer`]
159//!
160//! An owned, growable buffer of elements backed by an allocation into an `Arena`. The [`Buffer`] has
161//! a fixed maximum size which cannot be changed in the `Arena`.
162//!
163//! Read more in the [`buffer`] module.
164//!
165//! ## [`StringBuffer`]
166//!
167//! An owned, growable buffer containing utf8 encoded bytes.
168//!
169//! Read more in the [`string_buffer`] module.
170//!
171//! ## [`LinkedList`]
172//!
173//! A linked list of nodes, backed by an `Arena`. This allows an ordered collection of elements backed by
174//! an `Arena` without requiring contiguous space for all elements in the `Arena`.
175//!
176//! Read more in the [`linked_list`] module.
177//!
178//! # Features
179//!
180//! This crate can be customised with a few optional features:
181//!
182//! ## `allocator-api2`
183//!
184//! This feature uses the `allocator-api2` crate for its definitions of the `Allocator` trait
185//! and other supporting APIs. This allows `rotunda` to be built on the `stable` and `beta`
186//! rust compilers.
187//!
188//! It is required that at least one of either this feature or the `nightly` feature are enabled so that
189//! an allocator API is provided.
190//!
191//! ## `nightly`
192//!
193//! This feature enables usage of nightly features in `rotunda`, such as [`CoercePointee`]. It also
194//! allows using the `Allocator` trait and supporting APIs from [`alloc::alloc`]. Note that this feature
195//! will supersede `allocator-api2` (i.e. `alloc::alloc::Allocator` will be used over `allocator_api2::alloc::Allocator`)
196//! if both are enabled.
197//!
198//! ## `std`
199//!
200//! This feature enables integration with `std` traits, such as [`std::io::Read`].
201//!
202//! ## `serde`
203//!
204//! This feature allows the contents of handle types to be serialized transparently using [`serde`].
205//!
206//! [`Arena`]: ./struct.Arena.html
207//! [`Arena::reset()`]: ./struct.Arena.html#method.reset
208//! [`handle::Handle`]: ./handle/struct.Handle.html
209//! [`handle`]: ./handle/index.html
210//! [`Handle`]: ./handle/struct.Handle.html
211//! [`WeakHandle`]: ./rc_handle/struct.WeakHandle.html
212//! [`RcHandle`]: ./rc_handle/struct.RcHandle.html
213//! [`rc_handle`]: ./rc_handle/index.html
214//! [`Buffer`]: ./buffer/struct.Buffer.html
215//! [`StringBuffer`]: ./string_buffer/struct.StringBuffer.html
216//! [`string_buffer`]: ./string_buffer/index.html
217//! [`LinkedList`]: ./linked_list/struct.LinkedList.html
218//! [`linked_list`]: ./linked_list/index.html
219//! [`CoercePointee`]: https://doc.rust-lang.org/stable/core/marker/derive.CoercePointee.html
220//! [`alloc::alloc`]: https://doc.rust-lang.org/stable/core/alloc/alloc/index.html
221//! [`std::io::Read`]: https://doc.rust-lang.org/stable/std/io/trait.Read.html
222//! [`serde`]: https://docs.rs/serde/latest
223
224#[cfg(not(any(feature = "allocator-api2", feature = "nightly")))]
225compile_error!("An allocator must be provided, either through `nightly` or `allocator-api2`");
226
227#[cfg(feature = "nightly")]
228extern crate alloc;
229
230#[cfg(all(feature = "allocator-api2", not(feature = "nightly")))]
231extern crate allocator_api2 as alloc;
232
233#[cfg(any(test, feature = "std"))]
234extern crate std;
235
236use crate::blocks::{Block, BlockIter, Blocks, ScopedRestore};
237use alloc::alloc::{AllocError, Allocator, Global, Layout, LayoutError, handle_alloc_error};
238use core::{
239    error::Error as ErrorTrait,
240    ffi::c_void,
241    fmt,
242    iter::FusedIterator,
243    marker::PhantomData,
244    mem::{ManuallyDrop, MaybeUninit},
245    ptr::{self, NonNull},
246    str,
247};
248
249pub mod buffer;
250pub mod handle;
251pub mod linked_list;
252pub mod rc_handle;
253pub mod string_buffer;
254
255mod blocks;
256#[cfg(test)]
257mod tests;
258
259/// An arena allocator, parameterised by global allocator.
260///
261/// See the [module documentation](index.html) for more info.
262pub struct Arena<A: Allocator = Global> {
263    blocks: Blocks,
264    alloc: A,
265    _boo: PhantomData<*mut c_void>,
266}
267
268impl Arena {
269    /// Creates a new `Arena` with the default allocator and block size.
270    ///
271    /// See [`Arena::new_in()`] for more details.
272    ///
273    /// # Example
274    ///
275    /// ```
276    /// use rotunda::Arena;
277    ///
278    /// let arena = Arena::new();
279    /// ```
280    ///
281    /// [`Arena::new_in()`]: ./struct.Arena.html#method.new_in
282    #[must_use]
283    #[inline]
284    pub const fn new() -> Self {
285        const { Self::new_in(Global) }
286    }
287
288    /// Creates a new `Arena` with the default allocator and a custom block size
289    /// in bytes.
290    ///
291    /// See [`Arena::with_block_size_in()`] for more details.
292    ///
293    /// # Panics
294    ///
295    /// This method will panic if `block_size` is greater than `isize::MAX`, as this is a
296    /// requirement rust imposes on its allocator trait.
297    ///
298    /// # Example
299    ///
300    /// ```
301    /// use rotunda::Arena;
302    ///
303    /// let block_size = 1024 * 1024 * 3;
304    /// let arena = Arena::with_block_size(block_size);
305    /// ```
306    ///
307    /// [`Arena::with_block_size_in()`]: ./struct.Arena.html#method.with_block_size_in
308    #[must_use]
309    #[inline]
310    pub const fn with_block_size(block_size: usize) -> Self {
311        Self::with_block_size_in(block_size, Global)
312    }
313}
314
315impl<A: Allocator> Arena<A> {
316    /// Create a new `Arena`, using the provided `allocator` to allocate
317    /// backing storage from.
318    ///
319    /// The default block size is `isize::MAX + 1`. This provides a good
320    /// trade-off between blocks which are large enough to store most types
321    /// and not require too much reallocation, but not too large that
322    /// the allocator may run out of memory when allocating the backing
323    /// memory for the `Arena`.
324    ///
325    /// See [`Arena::with_block_size_in()`] for more details.
326    ///
327    /// # Notes
328    ///
329    /// This function requires the `allocator_api` feature to be enabled to
330    /// use it.
331    ///
332    /// # Example
333    ///
334    /// ```
335    /// #![cfg_attr(feature = "nightly", feature(allocator_api))]
336    ///
337    /// #[cfg(all(feature = "allocator-api2", not(feature = "nightly")))]
338    /// use allocator_api2::alloc::Global;
339    ///
340    /// #[cfg(feature = "nightly")]
341    /// use std::alloc::Global;
342    ///
343    /// use rotunda::Arena;
344    ///
345    /// let arena = Arena::new_in(Global);
346    /// ```
347    ///
348    /// [`Arena::with_block_size_in()`]: ./struct.Arena.html#method.with_block_size_in
349    #[must_use]
350    #[inline]
351    pub const fn new_in(allocator: A) -> Self {
352        let default_block_size = i16::MAX as usize + 1;
353        Self::with_block_size_in(default_block_size, allocator)
354    }
355
356    /// Create a new `Arena` with the given `block_size` in bytes, and the provided
357    /// `allocator` to allocate backing storage from.
358    ///
359    /// # Panics
360    ///
361    /// This method will panic if `block_size` is greater than `isize::MAX`, as this is a
362    /// requirement rust imposes on its allocator trait.
363    ///
364    /// # Example
365    ///
366    /// ```
367    /// #![cfg_attr(feature = "nightly", feature(allocator_api))]
368    ///
369    /// #[cfg(all(feature = "allocator-api2", not(feature = "nightly")))]
370    /// use allocator_api2::alloc::Global;
371    ///
372    /// #[cfg(feature = "nightly")]
373    /// use std::alloc::Global;
374    ///
375    /// use rotunda::Arena;
376    ///
377    /// let block_size = 4 * 1024 * 1024;
378    /// let arena = Arena::with_block_size_in(block_size, Global);
379    /// ```
380    #[must_use]
381    #[inline]
382    pub const fn with_block_size_in(block_size: usize, allocator: A) -> Self {
383        Self {
384            blocks: Blocks::new(block_size),
385            alloc: allocator,
386            _boo: PhantomData,
387        }
388    }
389
390    /// Returns the total number of bytes which can be allocated into the current
391    /// block before a new block will need to be allocated.
392    ///
393    /// If a current block is not available, returns `None`.
394    ///
395    /// # Example
396    ///
397    /// ```
398    /// use rotunda::{Arena, handle::Handle};
399    ///
400    /// let block_size = 4 * 1024 * 1024;
401    /// let arena = Arena::with_block_size(block_size);
402    ///
403    /// let handle = Handle::new_in(&arena, 54i32);
404    /// assert_eq!(arena.curr_block_capacity().unwrap(), block_size - std::mem::size_of::<i32>());
405    /// ```
406    #[must_use]
407    #[inline]
408    pub fn curr_block_capacity(&self) -> Option<usize> {
409        self.blocks.curr_block_capacity()
410    }
411
412    /// Reserves the given number of `num_blocks` into the `Arena`, placing them in the free list.
413    ///
414    /// Should the current block overflow while servicing allocation requests, the free blocks
415    /// can be used without needing to call the allocator.
416    ///
417    /// # Panics
418    ///
419    /// If the allocator cannot allocate the blocks, then `handle_alloc_err()` will be called,
420    /// which may panic or abort the process.
421    ///
422    /// # Example
423    ///
424    /// ```
425    /// use rotunda::Arena;
426    ///
427    /// let arena = Arena::new();
428    /// # let mut arena = arena;
429    ///
430    /// arena.reserve_blocks(3);
431    /// # assert_eq!(arena.free_blocks().count(), 3);
432    /// ```
433    #[track_caller]
434    #[inline]
435    pub fn reserve_blocks(&self, num_blocks: usize) {
436        let (layout, alloc) = (self.blocks.block_layout(), self.allocator());
437        for _ in 0..num_blocks {
438            let block = Block::alloc(layout, alloc);
439            self.blocks.push_free_block(block);
440        }
441    }
442
443    /// Tries to reserve the given number of `num_blocks` into the `Arena`, placing them in the free list.
444    ///
445    /// Should the current block overflow while servicing allocation requests, the free blocks
446    /// can be used without needing to call the allocator.
447    ///
448    /// # Errors
449    ///
450    /// If the allocator cannot allocate a `Block`, then `AllocError` is returned. If other blocks were allocated
451    /// as part of this call, then they will remain in the `Arena`.
452    ///
453    /// # Example
454    ///
455    /// ```
456    /// # #![cfg_attr(feature = "nightly", feature(allocator_api))]
457    ///
458    /// # #[cfg(all(feature = "allocator-api2", not(feature = "nightly")))]
459    /// # use allocator_api2::alloc::AllocError;
460    ///
461    /// # #[cfg(feature = "nightly")]
462    /// # use std::alloc::AllocError;
463    ///
464    /// use rotunda::Arena;
465    ///
466    /// let arena = Arena::new();
467    /// # let mut arena = arena;
468    ///
469    /// # fn inner(arena: &Arena) -> Result<(), AllocError> {
470    /// arena.try_reserve_blocks(3)?;
471    /// # Ok(())
472    /// # }
473    /// # inner(&arena);
474    /// # assert_eq!(arena.free_blocks().count(), 3);
475    /// ```
476    #[inline]
477    pub fn try_reserve_blocks(&self, num_blocks: usize) -> Result<(), AllocError> {
478        let (layout, alloc) = (self.blocks.block_layout(), self.allocator());
479        for _ in 0..num_blocks {
480            let block = Block::try_alloc(layout, alloc)?;
481            self.blocks.push_free_block(block);
482        }
483        Ok(())
484    }
485
486    /// Returns a pointer into the head of the current block.
487    ///
488    /// The available space in the current block is returned as the slice length.
489    ///
490    /// # Examples
491    ///
492    /// ```
493    /// use core::{mem, ptr};
494    /// use rotunda::{Arena, handle::Handle};
495    ///
496    /// let capacity = 3100;
497    ///
498    /// let arena = Arena::with_block_size(capacity);
499    ///
500    /// assert!(arena.curr_block_head().is_none());
501    ///
502    /// arena.force_push_new_block();
503    ///
504    /// let block = arena.curr_block_head().unwrap();
505    /// assert_eq!(block.len(), capacity);
506    ///
507    /// let data = Handle::new_in(&arena, 24i32);
508    /// assert!(ptr::eq(Handle::as_ptr(&data).cast::<u8>(), block.as_ptr().cast()));
509    ///
510    /// let block = arena.curr_block_head().unwrap();
511    /// assert_eq!(block.len(), capacity - mem::size_of::<i32>());
512    /// ```
513    #[inline]
514    pub fn curr_block_head(&self) -> Option<NonNull<[MaybeUninit<u8>]>> {
515        let curr_block = self.blocks.curr_block().get()?;
516
517        let (block_size, block_pos) = (self.block_size(), self.blocks.curr_block_pos().get());
518
519        let data = unsafe {
520            Block::data_ptr(curr_block, block_size)
521                .cast::<MaybeUninit<u8>>()
522                .as_ptr()
523                .map_addr(|data| data + block_pos)
524        };
525
526        NonNull::new(ptr::slice_from_raw_parts_mut(data, block_size - block_pos))
527    }
528
529    /// Forces the `Arena` to push all allocations into a new block of memory.
530    ///
531    /// The current block of memory will be moved to the used list, and will be
532    /// inaccessible until the `Arena` is cleared.
533    ///
534    /// This function will take a block from the free list if it is available, or allocate
535    /// a new one otherwise.
536    ///
537    /// # Panics
538    ///
539    /// This method will panic if the global allocator is unable to allocate a new block.
540    ///
541    /// # Examples
542    ///
543    /// ```
544    /// use rotunda::{Arena, handle::Handle};
545    /// use core::mem;
546    ///
547    /// let arena = Arena::with_block_size(640);
548    ///
549    /// let handle_1 = Handle::new_in(&arena, 543);
550    /// let handle_2 = Handle::new_in(&arena, 123);
551    ///
552    /// assert_eq!(
553    ///     Handle::as_ptr(&handle_2).addr() - Handle::as_ptr(&handle_1).addr(),
554    ///     mem::size_of::<i32>());
555    ///
556    /// arena.force_push_new_block();
557    ///
558    /// let handle_3 = Handle::new_in(&arena, 456);
559    ///
560    /// assert_ne!(
561    ///     Handle::as_ptr(&handle_3).addr() - Handle::as_ptr(&handle_2).addr(),
562    ///     mem::size_of::<i32>());
563    /// ```
564    #[track_caller]
565    #[inline]
566    pub fn force_push_new_block(&self) {
567        let _ = unsafe {
568            self.get_free_block()
569                .map_err(|_| handle_alloc_error(self.blocks.block_layout()))
570        };
571    }
572
573    /// Forces the `Arena` to push all allocations into a new block of memory.
574    ///
575    /// The current block of memory will be moved to the used list, and will be
576    /// inaccessible until the `Arena` is cleared.
577    ///
578    /// This function will take a block from the free list if it is available, or allocate
579    /// a new one otherwise.
580    ///
581    /// # Errors
582    ///
583    /// This method will return an error if the global allocator is unable to allocate a new block.
584    #[inline]
585    pub fn try_force_push_new_block(&self) -> Result<(), AllocError> {
586        unsafe { self.get_free_block().map(|_| ()) }
587    }
588
589    /// Checks whether the current block has the capacity to allocate up to `block_capacity_bytes`.
590    ///
591    /// # Examples
592    ///
593    /// ```
594    /// #[cfg(all(feature = "allocator-api2", not(feature = "nightly")))]
595    /// use allocator_api2::alloc::Layout;
596    ///
597    /// #[cfg(feature = "nightly")]
598    /// use std::alloc::Layout;
599    ///
600    /// use rotunda::Arena;
601    ///
602    /// let arena = Arena::with_block_size(25);
603    /// arena.force_push_new_block();
604    ///
605    /// assert!(arena.has_block_capacity(24));
606    ///
607    /// let layout = Layout::new::<[u8; 5]>();
608    /// arena.alloc_raw(layout);
609    ///
610    /// assert!(!arena.has_block_capacity(24));
611    /// ```
612    #[inline]
613    pub fn has_block_capacity(&self, block_capacity_bytes: usize) -> bool {
614        if self.block_size() < block_capacity_bytes {
615            return false;
616        }
617
618        self.curr_block_capacity()
619            .map(|cap| cap >= block_capacity_bytes)
620            .unwrap_or_default()
621    }
622
623    /// Checks whether the current block has the capacity to allocate up to `block_capacity_bytes`,
624    /// and allocates a new block if it doesn't.
625    ///
626    ///
627    /// # Examples
628    ///
629    /// ```
630    /// #[cfg(all(feature = "allocator-api2", not(feature = "nightly")))]
631    /// use allocator_api2::alloc::Layout;
632    ///
633    /// #[cfg(feature = "nightly")]
634    /// use std::alloc::Layout;
635    ///
636    /// use rotunda::Arena;
637    ///
638    /// let arena = Arena::with_block_size(25);
639    /// assert_eq!(arena.curr_block_capacity(), None);
640    ///
641    /// arena.ensure_block_capacity(20);
642    /// assert_eq!(arena.curr_block_capacity(), Some(25));
643    ///
644    /// let _ = arena.alloc_raw(Layout::new::<[u8; 23]>());
645    /// assert!(!arena.has_block_capacity(20));
646    ///
647    /// arena.ensure_block_capacity(20);
648    /// assert!(arena.has_block_capacity(20));
649    /// ```
650    #[inline]
651    pub fn ensure_block_capacity(&self, block_capacity_bytes: usize) {
652        if self.block_size() < block_capacity_bytes {
653            return;
654        }
655
656        if !self.has_block_capacity(block_capacity_bytes) {
657            self.force_push_new_block();
658        }
659    }
660
661    /// Resets the `Arena` so that all used blocks are moved into the free list, and
662    /// the current block counter is reset to `0`.
663    ///
664    /// This method does not use the `Arena`'s allocator to perform any memory
665    /// deallocation.
666    ///
667    /// # Examples
668    ///
669    /// ```
670    /// use rotunda::{Arena, handle::Handle};
671    ///
672    /// let mut arena = Arena::new();
673    /// {
674    ///     let handle_1 = Handle::new_in(&arena, 23);
675    ///     arena.force_push_new_block();
676    ///
677    ///     let handle_2 = Handle::new_in(&arena, 45);
678    ///     arena.force_push_new_block();
679    ///
680    ///     let handle_2 = Handle::new_in(&arena, 67);
681    ///     arena.force_push_new_block();
682    /// }
683    ///
684    /// arena.reset();
685    /// arena.trim();
686    ///
687    /// assert!(arena.curr_block().is_some());
688    /// ```
689    #[inline]
690    pub fn reset(&mut self) {
691        self.blocks.reset();
692    }
693
694    /// Resets the `Arena` so that all used blocks, and the current block, are moved into
695    /// the free list.
696    ///
697    /// This method does not use the `Arena`'s allocator to perform any memory
698    /// deallocation.
699    ///
700    /// # Examples
701    ///
702    /// ```
703    /// use rotunda::{Arena, handle::Handle};
704    ///
705    /// let mut arena = Arena::new();
706    /// {
707    ///     let handle_1 = Handle::new_in(&arena, 123);
708    ///     arena.force_push_new_block();
709    ///
710    ///     let handle_2 = Handle::new_in(&arena, 456);
711    ///     arena.force_push_new_block();
712    ///
713    ///     let handle_2 = Handle::new_in(&arena, 789);
714    ///     arena.force_push_new_block();
715    /// }
716    ///
717    /// arena.reset_all();
718    /// arena.trim();
719    ///
720    /// assert!(arena.curr_block().is_none());
721    #[inline]
722    pub fn reset_all(&mut self) {
723        self.blocks.reset_all();
724    }
725
726    /// Deallocates all blocks in the `Arena`'s free list.
727    ///
728    /// # Examples
729    ///
730    /// ```
731    /// use rotunda::{Arena, handle::Handle};
732    ///
733    /// let mut arena = Arena::new();
734    /// arena.reserve_blocks(1);
735    ///
736    /// assert_eq!(arena.free_blocks().count(), 1);
737    ///
738    /// arena.trim();
739    ///
740    /// assert_eq!(arena.free_blocks().count(), 0);
741    /// ```
742    #[inline]
743    pub fn trim(&self) {
744        self.blocks.trim(self.allocator());
745    }
746
747    /// Deallocates `n` blocks in the `Arena`'s free list.
748    ///
749    /// # Examples
750    ///
751    /// ```
752    /// use rotunda::Arena;
753    ///
754    /// let mut arena = Arena::new();
755    /// arena.reserve_blocks(5);
756    ///
757    /// assert_eq!(arena.free_blocks().count(), 5);
758    ///
759    /// arena.trim_n(2);
760    ///
761    /// assert_eq!(arena.free_blocks().count(), 3);
762    /// ```
763    #[track_caller]
764    #[inline]
765    pub fn trim_n(&self, n: usize) {
766        self.blocks.trim_n(n, self.allocator());
767    }
768
769    /// Runs the given closure within a scope that frees all memory allocated from the arena within
770    /// it.
771    ///
772    /// # Examples
773    ///
774    /// ```
775    /// use rotunda::{Arena, handle::Handle};
776    ///
777    /// let arena = Arena::new();
778    /// let result = arena.with_scope(|| {
779    ///     let h1 = Handle::new_in(&arena, 5);
780    ///     let h2 = Handle::new_in(&arena, 10);
781    ///     *h1 + *h2
782    /// });
783    ///
784    /// // `h1` and `h2` have been deallocated here, and the memory in the arena has been reset to
785    /// // from before they were allocated, so the space can be re-used.
786    ///
787    /// assert_eq!(result, 15);
788    /// ```
789    ///
790    /// # Notes
791    ///
792    /// The lifetime of `T` must be `'static`, which means that the closure cannot return borrowed data.
793    ///
794    /// If this is too restrictive, you can use [`Arena::with_scope_dynamic()`].
795    ///
796    /// The arena state is restored using a guard type, so the arena's memory will be restored if the given
797    /// closure panics.
798    ///
799    /// [`Arena::with_scope_dynamic()`]: ./struct.Arena.html#method.with_scope_dynamic
800    #[inline]
801    pub fn with_scope<T: 'static, F: FnOnce() -> T>(&self, f: F) -> T {
802        let _scope = ScopedRestore::new(&self.blocks);
803        f()
804    }
805
806    /// Runs the given closure within a scope that frees all memory allocated from the arena within
807    /// it.
808    ///
809    /// This function is similar to [`Arena::with_scope()`], except that it relaxes the
810    /// `'static` lifetime requirement on the return type. This allows the caller to
811    /// return borrowed data from the scope closure.
812    ///
813    /// As the closure taken by the function does not take ownership of items moved into it, it
814    /// can freely use items from the caller's scope, and does not have an `Arena` parameter.
815    ///
816    /// # Examples
817    ///
818    /// ```
819    /// use rotunda::{Arena, handle::Handle};
820    /// use core::cell::Cell;
821    ///
822    /// let data = vec![Cell::new(23)];
823    /// let arena = Arena::new();
824    /// let value = unsafe {
825    ///     arena.with_scope_dynamic(|| {
826    ///         let handle = Handle::new_in(&arena, 25);
827    ///         let value = &data[0];
828    ///         value.update(|old_val| old_val + *handle);
829    ///         value
830    ///     })
831    /// };
832    ///
833    /// assert_eq!(value.get(), 48);
834    /// ```
835    ///
836    /// # Safety
837    ///
838    /// This method is unsafe as it is possible to return a handle to memory which would
839    /// be freed in the Arena automatically as the scope exits. This would allow safe code
840    /// to overwrite the memory in the `Arena` with a new value while still allowing the
841    /// old `Handle` to be accessed, which could cause memory unsafety.
842    ///
843    /// To avoid this safety issue, never return data allocated in the arena during the scope.
844    ///
845    /// ```
846    /// use rotunda::{Arena, handle::Handle};
847    ///
848    /// let arena = Arena::new();
849    ///
850    /// let handle = unsafe {
851    ///     arena.with_scope_dynamic(|| {
852    ///         let handle = Handle::new_in(&arena, vec![1, 2, 3, 4, 5]);
853    ///         # let mut handle = handle;
854    ///         # unsafe { core::ptr::drop_in_place(Handle::as_mut_ptr(&mut handle)); } // Keep miri happy
855    ///         handle
856    ///     })
857    /// };
858    ///
859    /// // Warning ⚠️: `handle` has simultaneously been leakded and points to uninitialised memory.
860    /// // It is undefined behaviour to dereference it in any way (including via non-trivial drop).
861    /// # core::mem::forget(handle);
862    ///
863    /// // Warning ⚠️: This call to `Handle::new()` will use the same memory as which was used in the
864    /// // `with_scope_dynamic()` call above.
865    /// let handle = Handle::new_in(&arena, [128usize, 255, 300]);
866    /// ```
867    ///
868    /// Note that this includes 'smuggling' handles out through a collection type which
869    /// uses the `Arena` as a backing store:
870    ///
871    /// ```
872    /// use rotunda::{Arena, buffer::Buffer, handle::Handle};
873    ///
874    /// let arena = Arena::new();
875    /// let mut buffer = Buffer::with_capacity_in(&arena, 5);
876    ///
877    /// unsafe {
878    ///     arena.with_scope_dynamic(|| {
879    ///         let handle = Handle::new_in(&arena, String::from("This is a message!"));
880    ///         # let mut handle = handle;
881    ///         # unsafe { core::ptr::drop_in_place(Handle::as_mut_ptr(&mut handle)); } // Keep miri happy
882    ///         buffer.push(handle);
883    ///     });
884    /// };
885    ///
886    /// // Warning ⚠️: `buffer[0]` has simultaneously been leakded and points to uninitialised memory.
887    /// // It is undefined behaviour to dereference it in any way (including via non-trivial drop).
888    /// # core::mem::forget(buffer.remove(0));
889    /// ```
890    ///
891    /// [`Arena::with_scope()`]: ./struct.Arena.html#method.with_scope
892    #[inline]
893    pub unsafe fn with_scope_dynamic<T, F: FnOnce() -> T>(&self, f: F) -> T {
894        let _scope = ScopedRestore::new(&self.blocks);
895        f()
896    }
897
898    /// Returns a reference to the underlying [`Allocator`] type used to allocate/deallocate
899    /// memory.
900    ///
901    /// # Examples
902    ///
903    /// ```
904    /// # use rotunda::Arena;
905    /// let arena = Arena::new();
906    /// let allocator = arena.allocator();
907    /// # let _ = allocator;
908    /// ```
909    ///
910    /// [`Allocator`]: https://doc.rust-lang.org/stable/alloc/alloc/trait.Allocator.html
911    #[must_use]
912    #[inline]
913    pub fn allocator(&self) -> &A {
914        &self.alloc
915    }
916
917    /// Returns the block size of the `Arena`. This is specified using the [`Arena::with_block_size()`]
918    /// and [`Arena::with_block_size_in()`] constructors.
919    ///
920    /// # Examples
921    ///
922    /// ```
923    /// use rotunda::Arena;
924    ///
925    /// const BLOCK_SIZE: usize = 6 * 1024 * 1024;
926    /// let arena = Arena::with_block_size(BLOCK_SIZE);
927    ///
928    ///  assert_eq!(arena.block_size(), BLOCK_SIZE);
929    /// ```
930    ///
931    /// [`Arena::with_block_size()`]:
932    /// [`Arena::with_block_size_in()`]:
933    #[must_use]
934    #[inline]
935    pub fn block_size(&self) -> usize {
936        self.blocks.block_size()
937    }
938
939    /// Returns a new allocation matching `layout` from the current block in the `Arena`.
940    ///
941    /// # Panics
942    ///
943    /// This method can panic if:
944    ///
945    /// * The requested `Layout` can never be satisfied by a block with the size of [`Arena::block_size()`].
946    /// * The underlying allocator raises an error which is handled by the [`handle_alloc_error()`] function.
947    ///
948    /// [`Arena::block_size()`]: ./struct.Arena.html#method.block_size
949    /// [`handle_alloc_error()`]: https://doc.rust-lang.org/stable/alloc/alloc/fn.handle_alloc_error.html
950    #[track_caller]
951    #[must_use]
952    pub fn alloc_raw(&self, layout: Layout) -> NonNull<c_void> {
953        if layout.size() == 0 {
954            return self.alloc_zst(layout.align());
955        }
956
957        #[cold]
958        #[track_caller]
959        #[inline(never)]
960        fn insert_fresh_block_fail(layout: &Layout) -> ! {
961            panic!(
962                "can never insert a type with layout `Layout (size = {}, align = {})` into arena",
963                layout.size(),
964                layout.align()
965            );
966        }
967
968        if let Err(e) = self.get_block_for_layout(layout) {
969            match e {
970                Error::AllocErr(_) => handle_alloc_error(layout),
971                _ => insert_fresh_block_fail(&layout),
972            }
973        }
974
975        unsafe {
976            let slot = self.blocks.bump_layout(layout);
977            NonNull::new_unchecked(slot.as_ptr())
978        }
979    }
980
981    /// Returns a new allocation matching `layout` in the `Arena`.
982    ///
983    /// # Errors
984    ///
985    /// If the underlying allocator could not service a request, then
986    /// an `Error::AllocErr` is returned.
987    ///
988    /// If the given `layout` could not fit in an empty block, then
989    /// `Error::BadLayout` is returned.
990    ///
991    /// # Examples
992    ///
993    /// ```
994    /// #[cfg(all(feature = "allocator-api2", not(feature = "nightly")))]
995    /// use allocator_api2::alloc::Layout;
996    ///
997    /// #[cfg(feature = "nightly")]
998    /// use std::alloc::Layout;
999    ///
1000    /// # use rotunda::Error;
1001    /// use rotunda::Arena;
1002    ///
1003    /// let arena = Arena::with_block_size(4);
1004    ///
1005    /// # fn inner(arena: &Arena) -> Result<(), rotunda::Error> {
1006    /// let data = arena.try_alloc_raw(Layout::new::<u16>()).expect("Will succeed");
1007    /// let will_error = arena.try_alloc_raw(Layout::new::<u64>())?;
1008    /// # Ok(())
1009    /// # }
1010    /// # let result = inner(&arena);
1011    /// # let layout = match result.unwrap_err() { Error::BadLayout(l) => l, _ => unreachable!() };
1012    /// # assert_eq!(layout, Layout::new::<u64>());
1013    /// ```
1014    #[inline]
1015    pub fn try_alloc_raw(&self, layout: Layout) -> Result<NonNull<c_void>, Error> {
1016        if layout.size() == 0 {
1017            return Ok(self.alloc_zst(layout.align()));
1018        }
1019
1020        self.get_block_for_layout(layout)?;
1021
1022        unsafe {
1023            let slot = self.blocks.bump_layout(layout);
1024            Ok(NonNull::new_unchecked(slot.as_ptr()))
1025        }
1026    }
1027
1028    /// Returns a new zeroed allocation from the current block in the `Arena`.
1029    ///
1030    /// If the current block in the `Arena` is full, then a new one will be allocated and used.
1031    ///
1032    /// # Panics
1033    ///
1034    /// This method can panic if:
1035    ///
1036    /// * The requested `Layout` can never be satisfied by a block with the size of [`Arena::block_size()`].
1037    /// * The underlying allocator raises an error which is handled by the [`handle_alloc_error()`] function.
1038    ///
1039    /// [`Arena::block_size()`]: ./struct.Arena.html#method.block_size
1040    /// [`handle_alloc_error()`]: https://doc.rust-lang.org/stable/alloc/alloc/fn.handle_alloc_error.html
1041    #[track_caller]
1042    #[must_use]
1043    #[inline]
1044    pub fn alloc_raw_zeroed(&self, layout: Layout) -> NonNull<c_void> {
1045        let slot = self.alloc_raw(layout);
1046        unsafe {
1047            ptr::write_bytes(slot.as_ptr().cast::<u8>(), b'\0', layout.size());
1048        }
1049        slot
1050    }
1051
1052    /// Allocate the given `value` into this `Arena` and returns an exclusive reference to it.
1053    ///
1054    /// The allocated value is wrapped in a [`ManuallyDrop`] to indicate that its `drop` method
1055    /// will not be called when the value goes out of scope. If the value has a meaningful
1056    /// [`Drop::drop()`] implementation, then you should call [`ManuallyDrop::drop()`] on it.
1057    ///
1058    /// # Errors
1059    ///
1060    /// This method can fail if the arena cannot allocate a new block to store the value.
1061    ///
1062    /// # Example
1063    ///
1064    /// ```
1065    /// use core::mem::ManuallyDrop;
1066    /// use rotunda::Arena;
1067    ///
1068    /// let mut arena = Arena::new();
1069    ///
1070    /// let value = arena.alloc_ref("Hello!");
1071    /// assert_eq!(**value, "Hello!");
1072    ///
1073    /// unsafe {
1074    ///     ManuallyDrop::drop(value);
1075    /// }
1076    /// ```
1077    ///
1078    /// [`ManuallyDrop`]: https://doc.rust-lang.org/stable/core/mem/struct.ManuallyDrop.html
1079    /// [`Drop::drop()`]: https://doc.rust-lang.org/stable/core/ops/trait.Drop.html#tymethod.drop
1080    /// [`ManuallyDrop::drop()`]: https://doc.rust-lang.org/stable/core/mem/struct.ManuallyDrop.html#method.drop
1081    #[allow(clippy::mut_from_ref)]
1082    #[track_caller]
1083    #[must_use]
1084    #[inline]
1085    pub fn alloc_ref<T>(&self, value: T) -> &mut ManuallyDrop<T> {
1086        let mut slot = self.alloc_raw(Layout::new::<T>()).cast::<ManuallyDrop<T>>();
1087        unsafe {
1088            slot.write(ManuallyDrop::new(value));
1089            slot.as_mut()
1090        }
1091    }
1092
1093    /// Allocate the given `string` into the `Arena`, returning a exclusive reference to the string
1094    /// in the arena.
1095    ///
1096    /// # Panics
1097    ///
1098    /// This method will panic if the string cannot be allocated in the `Arena`, or if the length of the
1099    /// `string` is larger than `isize::MAX`.
1100    ///
1101    /// # Examples
1102    ///
1103    /// ```
1104    /// use rotunda::Arena;
1105    ///
1106    /// let arena = Arena::new();
1107    ///
1108    /// let message = arena.alloc_str("hello ❤️");
1109    ///
1110    /// message.make_ascii_uppercase();
1111    ///
1112    /// assert_eq!(message, "HELLO ❤️");
1113    /// ```
1114    #[allow(clippy::mut_from_ref)]
1115    #[track_caller]
1116    #[must_use]
1117    #[inline]
1118    pub fn alloc_str<S: ?Sized + AsRef<str>>(&self, string: &S) -> &mut str {
1119        let string = string.as_ref();
1120        let len = string.len();
1121
1122        unsafe {
1123            let slot = self
1124                .alloc_raw(Layout::array::<u8>(len).expect("could not create layout for string"));
1125
1126            let slot = slot.as_ptr().cast::<u8>();
1127            ptr::copy_nonoverlapping(string.as_ptr(), slot, len);
1128            let bytes = ptr::slice_from_raw_parts_mut(slot, len);
1129            &mut *(bytes as *mut str)
1130        }
1131    }
1132
1133    /// Returns a reference to the currently in-use block, if it is available.
1134    ///
1135    /// This method requires exclusive access to the `Arena`, so there
1136    /// cannot be any objects allocated live from the arena.
1137    ///
1138    /// # Examples
1139    ///
1140    /// ```
1141    /// # use core::mem::{drop, MaybeUninit};
1142    /// use rotunda::{Arena, handle::Handle};
1143    /// let mut arena = Arena::new();
1144    ///
1145    /// let no_block = arena.curr_block();
1146    /// assert!(no_block.is_none());
1147    ///
1148    /// let handle = Handle::new_str_in(&arena, "Hello, world!");
1149    /// drop(handle);
1150    ///
1151    /// let block = arena.curr_block().expect("block must be allocated");
1152    ///
1153    /// block.fill(MaybeUninit::new(0xcd));
1154    /// ```
1155    #[must_use]
1156    #[inline]
1157    pub fn curr_block(&mut self) -> Option<&mut [MaybeUninit<u8>]> {
1158        unsafe {
1159            self.blocks
1160                .curr_block()
1161                .get()
1162                .map(|block| Block::data_mut(block, self.block_size()))
1163        }
1164    }
1165
1166    /// Returns an iterator over free blocks in the `Arena`.
1167    ///
1168    /// This method requires exclusive access to the `Arena`, so there
1169    /// cannot be any objects allocated live from the arena.
1170    ///
1171    /// # Examples
1172    ///
1173    /// ```
1174    /// use rotunda::{Arena, handle::Handle};
1175    /// use core::mem::MaybeUninit;
1176    ///
1177    /// let mut arena = Arena::new();
1178    /// # arena.force_push_new_block();
1179    /// # arena.force_push_new_block();
1180    ///
1181    /// for free_block in arena.free_blocks() {
1182    ///     free_block.fill(MaybeUninit::new(0x00));
1183    /// }
1184    /// ```
1185    #[must_use]
1186    #[inline]
1187    pub fn free_blocks(&mut self) -> FreeBlocksMut<'_, A> {
1188        FreeBlocksMut::new(self)
1189    }
1190
1191    /// Returns an iterator over all blocks in the `Arena`.
1192    ///
1193    /// This method requires exclusive access to the `Arena`, so there
1194    /// cannot be any objects allocated live from the arena.
1195    ///
1196    /// # Examples
1197    ///
1198    /// ```
1199    /// use rotunda::{Arena, handle::Handle};
1200    /// use core::mem::MaybeUninit;
1201    ///
1202    /// let mut arena = Arena::new();
1203    /// # arena.force_push_new_block();
1204    /// # arena.force_push_new_block();
1205    ///
1206    /// for block in arena.all_blocks() {
1207    ///     block.fill(MaybeUninit::new(0xff));
1208    /// }
1209    /// ```
1210    #[must_use]
1211    #[inline]
1212    pub fn all_blocks(&mut self) -> AllBlocksMut<'_, A> {
1213        AllBlocksMut::new(self)
1214    }
1215
1216    #[inline]
1217    unsafe fn get_free_block(&self) -> Result<NonNull<Block>, AllocError> {
1218        let block = match self.blocks.free_blocks().get() {
1219            // If we have a free block, grab it
1220            Some(block) => unsafe {
1221                let next_free_block = block.as_ref().next.get();
1222                block.as_ref().next.set(None);
1223
1224                self.blocks.free_blocks().set(next_free_block);
1225                block
1226            },
1227            // otherwise, alloc another one
1228            _ => self.alloc_block()?,
1229        };
1230
1231        self.blocks.curr_block_pos().set(0);
1232        if let Some(curr_block) = self.blocks.curr_block().get() {
1233            self.blocks.push_used_block(curr_block);
1234        }
1235
1236        self.blocks.curr_block().set(Some(block));
1237        Ok(block)
1238    }
1239
1240    #[inline]
1241    fn alloc_block(&self) -> Result<NonNull<Block>, AllocError> {
1242        let layout = self.blocks.block_layout();
1243        Block::try_alloc(layout, self.allocator())
1244    }
1245
1246    fn get_block_for_layout(&self, layout: Layout) -> Result<NonNull<Block>, Error> {
1247        let block = self
1248            .blocks
1249            .curr_block()
1250            .get()
1251            .filter(|_| self.blocks.can_write_layout(&layout))
1252            .map(Ok)
1253            .unwrap_or_else(|| {
1254                let block = unsafe { self.get_free_block()? };
1255                if !self.blocks.can_write_layout(&layout) {
1256                    return Err(Error::BadLayout(layout));
1257                }
1258
1259                Ok(block)
1260            });
1261
1262        if let Ok(block) = block {
1263            debug_assert!(ptr::eq(
1264                block.as_ptr(),
1265                self.blocks
1266                    .curr_block()
1267                    .get()
1268                    .map(|p| p.as_ptr())
1269                    .unwrap_or(ptr::null_mut())
1270            ));
1271        }
1272
1273        block
1274    }
1275
1276    #[must_use]
1277    fn alloc_zst(&self, align: usize) -> NonNull<c_void> {
1278        let mut ptr = NonNull::dangling();
1279        let offset = ptr.align_offset(align);
1280
1281        if offset != 0 || offset != usize::MAX {
1282            ptr = ptr.map_addr(|addr| addr.saturating_add(offset));
1283        }
1284
1285        ptr
1286    }
1287}
1288
1289impl<A: Allocator + Default> Default for Arena<A> {
1290    #[inline]
1291    fn default() -> Self {
1292        Self::new_in(Default::default())
1293    }
1294}
1295
1296impl<A: Allocator> fmt::Debug for Arena<A> {
1297    #[inline]
1298    fn fmt(&self, fmtr: &mut fmt::Formatter<'_>) -> fmt::Result {
1299        self.blocks.write_debug("Arena", fmtr)
1300    }
1301}
1302
1303unsafe impl<A: Allocator + Sync> Send for Arena<A> {}
1304
1305impl<A: Allocator> Drop for Arena<A> {
1306    #[inline]
1307    fn drop(&mut self) {
1308        unsafe {
1309            self.blocks.dealloc_all_memory(self.allocator());
1310        }
1311    }
1312}
1313
1314/// An iterator type over the free blocks of an [`Arena`].
1315///
1316/// See the [`Arena::free_blocks()`] method for more information.
1317///
1318/// [`Arena`]: ./struct.Arena.html
1319/// [`Arena::free_blocks()`]: ./struct.Arena.html#method.free_blocks
1320pub struct FreeBlocksMut<'a, A: Allocator = Global> {
1321    arena: &'a mut Arena<A>,
1322    it: BlockIter,
1323}
1324
1325impl<'a, A: Allocator> FreeBlocksMut<'a, A> {
1326    #[must_use]
1327    #[inline]
1328    const fn new(arena: &'a mut Arena<A>) -> Self {
1329        let it = BlockIter::new(arena.blocks.free_blocks().get());
1330        Self { arena, it }
1331    }
1332}
1333
1334impl<'a, A: Allocator> Iterator for FreeBlocksMut<'a, A> {
1335    type Item = &'a mut [MaybeUninit<u8>];
1336
1337    #[inline]
1338    fn next(&mut self) -> Option<Self::Item> {
1339        let block = self.it.next()?;
1340
1341        let data = unsafe {
1342            let block_size = self.arena.block_size();
1343            Block::data_mut(block, block_size)
1344        };
1345
1346        Some(data)
1347    }
1348}
1349
1350impl<'a, A: Allocator> FusedIterator for FreeBlocksMut<'a, A> {}
1351
1352impl<'a, A: Allocator> fmt::Debug for FreeBlocksMut<'a, A> {
1353    #[inline]
1354    fn fmt(&self, fmtr: &mut fmt::Formatter<'_>) -> fmt::Result {
1355        fmtr.debug_struct("FreeBlocksMut").finish_non_exhaustive()
1356    }
1357}
1358
1359/// An iterator type over every block of an [`Arena`].
1360///
1361/// See the [`Arena::all_blocks()`] method for more information.
1362///
1363/// [`Arena`]: ./struct.Arena.html
1364/// [`Arena::all_blocks()`]: ./struct.Arena.html#method.all_blocks
1365pub struct AllBlocksMut<'a, A: Allocator = Global> {
1366    arena: &'a mut Arena<A>,
1367    curr: Option<NonNull<Block>>,
1368    free_blocks: BlockIter,
1369    used_blocks: BlockIter,
1370}
1371
1372impl<'a, A: Allocator> AllBlocksMut<'a, A> {
1373    #[inline]
1374    const fn new(arena: &'a mut Arena<A>) -> Self {
1375        let curr = arena.blocks.curr_block().get();
1376
1377        let free_blocks = BlockIter::new(arena.blocks.free_blocks().get());
1378        let used_blocks = BlockIter::new(arena.blocks.used_blocks().get());
1379
1380        Self {
1381            curr,
1382            arena,
1383            free_blocks,
1384            used_blocks,
1385        }
1386    }
1387}
1388
1389impl<'a, A: Allocator> Iterator for AllBlocksMut<'a, A> {
1390    type Item = &'a mut [MaybeUninit<u8>];
1391
1392    #[inline]
1393    fn next(&mut self) -> Option<Self::Item> {
1394        self.curr
1395            .take()
1396            .or_else(|| self.free_blocks.next())
1397            .or_else(|| self.used_blocks.next())
1398            .map(|block| {
1399                let block_size = self.arena.block_size();
1400                unsafe { Block::data_mut(block, block_size) }
1401            })
1402    }
1403}
1404
1405impl<'a, A: Allocator> fmt::Debug for AllBlocksMut<'a, A> {
1406    #[inline]
1407    fn fmt(&self, fmtr: &mut fmt::Formatter<'_>) -> fmt::Result {
1408        fmtr.debug_struct("AllBlocksMut").finish_non_exhaustive()
1409    }
1410}
1411
1412/// Represents error types which may be returned while using an `Arena`.
1413#[derive(Debug)]
1414pub enum Error {
1415    /// A `Layout` could not be constructed for a particular type.
1416    LayoutErr(LayoutError),
1417    /// The underlying allocator could not service the request.
1418    AllocErr(AllocError),
1419    /// The allocation request with the given `Layout` could not be serviced.
1420    BadLayout(Layout),
1421}
1422
1423impl From<LayoutError> for Error {
1424    #[inline]
1425    fn from(value: LayoutError) -> Self {
1426        Self::LayoutErr(value)
1427    }
1428}
1429
1430impl From<AllocError> for Error {
1431    #[inline]
1432    fn from(value: AllocError) -> Self {
1433        Self::AllocErr(value)
1434    }
1435}
1436
1437impl fmt::Display for Error {
1438    #[inline]
1439    fn fmt(&self, fmtr: &mut fmt::Formatter<'_>) -> fmt::Result {
1440        match *self {
1441            Self::AllocErr(ref e) => fmt::Display::fmt(e, fmtr),
1442            Self::LayoutErr(ref e) => fmt::Display::fmt(e, fmtr),
1443            Self::BadLayout(layout) => write!(
1444                fmtr,
1445                "Arena cannot allocate a value of size {}, alignment {}",
1446                layout.size(),
1447                layout.align()
1448            ),
1449        }
1450    }
1451}
1452
1453impl ErrorTrait for Error {
1454    #[inline]
1455    fn source(&self) -> Option<&(dyn ErrorTrait + 'static)> {
1456        match *self {
1457            Self::AllocErr(ref e) => e.source(),
1458            Self::LayoutErr(ref e) => e.source(),
1459            Self::BadLayout(_) => None,
1460        }
1461    }
1462}
1463
1464pub(crate) type InvariantLifetime<'a, T> = PhantomData<fn(&'a T) -> &'a T>;
1465
1466#[inline]
1467fn layout_repeat(layout: &Layout, n: usize) -> Result<(Layout, usize), LayoutError> {
1468    let padded = layout.pad_to_align();
1469    match layout.size().checked_mul(n) {
1470        Some(array_size) => Layout::from_size_align(array_size, layout.align())
1471            .map(|layout| (layout, padded.size())),
1472        // Generate a guaranteed `LayoutError` by creating a `Layout` with alignment `0`.
1473        None => Layout::from_size_align(1, 0).map(|layout| (layout, 0)),
1474    }
1475}