Skip to main content

vize_carton/
allocator.rs

1//! Arena allocator wrapping bumpalo.
2
3use bumpalo::Bump;
4use std::ops::Deref;
5
6/// Arena allocator for Vize.
7///
8/// This is a thin wrapper around [`bumpalo::Bump`] that provides arena allocation.
9/// Memory is allocated in a contiguous block and freed all at once when the allocator
10/// is dropped, making it very efficient for AST construction.
11///
12/// # Example
13///
14/// ```
15/// use vize_carton::Allocator;
16///
17/// let allocator = Allocator::default();
18/// let s = allocator.alloc_str("hello");
19/// assert_eq!(s, "hello");
20/// ```
21#[derive(Default)]
22pub struct Allocator {
23    bump: Bump,
24}
25
26impl Allocator {
27    /// Creates a new allocator.
28    #[inline]
29    pub fn new() -> Self {
30        Self { bump: Bump::new() }
31    }
32
33    /// Creates a new allocator with the specified capacity.
34    #[inline]
35    pub fn with_capacity(capacity: usize) -> Self {
36        Self {
37            bump: Bump::with_capacity(capacity),
38        }
39    }
40
41    /// Allocates a string slice in the arena.
42    #[inline]
43    pub fn alloc_str(&self, s: &str) -> &str {
44        self.bump.alloc_str(s)
45    }
46
47    /// Returns a reference to the underlying bumpalo allocator.
48    ///
49    /// This is useful for interoperability with code that expects a raw `Bump`.
50    #[inline]
51    pub fn as_bump(&self) -> &Bump {
52        &self.bump
53    }
54
55    /// Resets the allocator, freeing all allocated memory.
56    ///
57    /// This allows reusing the allocator for a new compilation without
58    /// deallocating the underlying memory.
59    #[inline]
60    pub fn reset(&mut self) {
61        self.bump.reset();
62    }
63
64    /// Returns the number of bytes currently allocated in the arena.
65    #[inline]
66    pub fn allocated_bytes(&self) -> usize {
67        self.bump.allocated_bytes()
68    }
69}
70
71impl Deref for Allocator {
72    type Target = Bump;
73
74    #[inline]
75    fn deref(&self) -> &Self::Target {
76        &self.bump
77    }
78}
79
80// Allow using Allocator where Bump is expected via AsRef
81impl AsRef<Bump> for Allocator {
82    #[inline]
83    fn as_ref(&self) -> &Bump {
84        &self.bump
85    }
86}
87
88#[cfg(test)]
89mod tests {
90    use super::*;
91
92    #[test]
93    fn test_allocator_new() {
94        let allocator = Allocator::new();
95        assert_eq!(allocator.allocated_bytes(), 0);
96    }
97
98    #[test]
99    fn test_allocator_default() {
100        let allocator = Allocator::default();
101        assert_eq!(allocator.allocated_bytes(), 0);
102    }
103
104    #[test]
105    fn test_alloc_str() {
106        let allocator = Allocator::new();
107        let s = allocator.alloc_str("hello world");
108        assert_eq!(s, "hello world");
109    }
110
111    #[test]
112    fn test_reset() {
113        let mut allocator = Allocator::new();
114        let _ = allocator.alloc_str("hello");
115        assert!(allocator.allocated_bytes() > 0);
116        allocator.reset();
117        // Note: allocated_bytes may not be 0 after reset due to chunk reuse
118    }
119}