avila_atom/
lib.rs

1//! # avila-atom
2//!
3//! **Atomic Computational Structures - Fundamental Data Structures**
4//!
5//! This library implements core data structures built from first principles,
6//! providing type-safe primitives for systems programming with zero-compromise
7//! performance characteristics.
8//!
9//! ## Available Structures
10//!
11//! - `Option<T>` - Optional value (presence/absence) - zero-cost abstraction
12//! - `Result<T, E>` - Result type (success/failure) - enum-based sum type
13//! - `DynamicArray<T>` - Contiguous growable array with amortized O(1) push
14//! - `AssociativeArray<K, V>` - Hash-based or tree-based key-value store
15//! - `StringBuffer` - UTF-8 encoded string with growable capacity
16//!
17//! ## Philosophy
18//!
19//! These structures are atomic computational primitives - stable elements
20//! that compose infinitely to build complex software systems.
21//!
22//! ### Performance Characteristics
23//!
24//! - **Zero-cost abstractions**: No runtime overhead vs manual implementation
25//! - **Memory locality**: Contiguous allocation for cache efficiency
26//! - **Compile-time optimization**: Monomorphization enables aggressive inlining
27//! - **Stack-preferred**: Structures optimize for stack allocation when possible
28//!
29//! ### no_std Compatibility
30//!
31//! All structures work in `no_std` environments with `alloc` feature:
32//! - `AssociativeArray` falls back to B-Tree (O(log n)) instead of HashMap (O(1))
33//! - Memory allocation via global allocator trait
34//! - Zero dependency on operating system primitives
35
36#![cfg_attr(not(feature = "std"), no_std)]
37#![warn(missing_docs)]
38
39#[cfg(feature = "std")]
40extern crate std;
41
42#[cfg(not(feature = "std"))]
43extern crate alloc;
44
45#[cfg(not(feature = "std"))]
46use alloc::{vec::Vec, string::String, collections::BTreeMap};
47
48#[cfg(feature = "std")]
49use std::{vec::Vec, string::String, collections::HashMap};
50
51/// Optional value type - represents presence or absence of a value
52/// 
53/// **Memory layout**: Single byte discriminant + value (if Some)
54/// **Size**: `size_of::<T>() + 1` (optimized to `size_of::<T>()` for nullable pointers)
55/// **Performance**: Zero-cost - compiles to same code as manual null checks
56pub use core::option::Option;
57
58/// Result type - represents success (Ok) or failure (Err)
59/// 
60/// **Memory layout**: Tagged union (discriminant + larger of Ok/Err)
61/// **Size**: `1 + max(size_of::<T>(), size_of::<E>())`
62/// **Performance**: Zero-cost abstraction, optimal enum representation
63pub use core::result::Result;
64
65/// Dynamic array with contiguous memory layout
66/// 
67/// **Complexity**:
68/// - Access: O(1) by index
69/// - Push: O(1) amortized (doubles capacity on realloc)
70/// - Insert/Remove: O(n) for arbitrary position
71/// 
72/// **Memory**: `ptr + len + capacity` (24 bytes on 64-bit)
73/// **Growth strategy**: Geometric progression (2x) for amortized O(1)
74#[cfg(feature = "std")]
75pub type DynamicArray<T> = Vec<T>;
76
77#[cfg(not(feature = "std"))]
78pub type DynamicArray<T> = Vec<T>;
79
80/// Hash map (std) or B-Tree map (no_std) for key-value storage
81/// 
82/// **std mode** (HashMap):
83/// - Lookup: O(1) average, O(n) worst case
84/// - Insert: O(1) amortized
85/// - Hasher: SipHash 1-3 (cryptographic, DoS resistant)
86/// - Load factor: Grows at 90% capacity
87/// 
88/// **no_std mode** (BTreeMap):
89/// - Lookup: O(log n)
90/// - Insert: O(log n)
91/// - Node size: Optimized for cache lines
92/// - Ordering: Requires `K: Ord`
93#[cfg(feature = "std")]
94pub type AssociativeArray<K, V> = HashMap<K, V>;
95
96#[cfg(not(feature = "std"))]
97pub type AssociativeArray<K, V> = BTreeMap<K, V>;
98
99/// UTF-8 encoded string buffer
100/// 
101/// **Guarantees**:
102/// - Valid UTF-8 at all times (invariant enforced by type system)
103/// - Contiguous memory layout
104/// - Growable capacity with geometric progression
105/// 
106/// **Memory**: `ptr + len + capacity` (24 bytes on 64-bit)
107/// **Validation**: All mutations validate UTF-8 boundaries
108pub type StringBuffer = String;
109
110/// Library version constant
111pub const VERSION: &str = env!("CARGO_PKG_VERSION");
112
113/// Compile-time size constants for common types
114pub mod sizes {
115    use core::mem::size_of;
116
117    /// Size of Option<T> for non-nullable T
118    pub const OPTION_OVERHEAD: usize = 1;
119    
120    /// Pointer size (32-bit: 4 bytes, 64-bit: 8 bytes)
121    pub const PTR_SIZE: usize = size_of::<usize>();
122    
123    /// Vec/String header size (ptr + len + cap)
124    pub const VEC_HEADER_SIZE: usize = 3 * PTR_SIZE;
125    
126    /// Default Vec capacity on first allocation
127    pub const VEC_DEFAULT_CAPACITY: usize = 4;
128}
129
130/// Specialized array types with compile-time known sizes
131pub mod fixed {
132    /// Fixed-size array wrapper for stack allocation
133    /// 
134    /// **Performance**: Zero heap allocation, inlined operations
135    /// **Use case**: When maximum size known at compile-time
136    #[repr(transparent)]
137    pub struct FixedArray<T, const N: usize>([T; N]);
138    
139    impl<T, const N: usize> FixedArray<T, N> {
140        /// Create from array (zero-cost)
141        #[inline(always)]
142        pub const fn new(array: [T; N]) -> Self {
143            Self(array)
144        }
145        
146        /// Get slice view
147        #[inline(always)]
148        pub const fn as_slice(&self) -> &[T] {
149            &self.0
150        }
151        
152        /// Get mutable slice view
153        #[inline(always)]
154        pub fn as_mut_slice(&mut self) -> &mut [T] {
155            &mut self.0
156        }
157        
158        /// Compile-time size
159        #[inline(always)]
160        pub const fn len(&self) -> usize {
161            N
162        }
163        
164        /// Unwrap into inner array
165        #[inline(always)]
166        pub fn into_inner(self) -> [T; N] {
167            self.0
168        }
169    }
170    
171    /// Small string optimization - stores up to 23 bytes inline
172    /// 
173    /// **Memory**: 24 bytes total (same as String header)
174    /// **Benefit**: No heap allocation for short strings
175    #[repr(C)]
176    pub union SmallString {
177        /// Inline storage for strings <= 23 bytes
178        inline: core::mem::ManuallyDrop<InlineString>,
179        /// Heap pointer for strings > 23 bytes
180        heap: core::mem::ManuallyDrop<HeapString>,
181    }
182    
183    #[repr(C)]
184    #[derive(Copy, Clone)]
185    struct InlineString {
186        data: [u8; 23],
187        len: u8, // MSB = 0 for inline
188    }
189    
190    #[repr(C)]
191    #[derive(Copy, Clone)]
192    struct HeapString {
193        ptr: *mut u8,
194        cap: usize,
195        len: usize, // MSB = 1 for heap
196    }
197}
198
199/// Iterator utilities and extensions
200pub mod iter {
201    use super::*;
202    
203    /// Trait for converting into iterator with size hint
204    pub trait IntoIteratorWithHint: IntoIterator {
205        /// Get size hint before consuming
206        fn size_hint_before(&self) -> (usize, Option<usize>);
207    }
208    
209    impl<T> IntoIteratorWithHint for DynamicArray<T> {
210        #[inline]
211        fn size_hint_before(&self) -> (usize, Option<usize>) {
212            let len = self.len();
213            (len, Some(len))
214        }
215    }
216}
217
218/// Macro for convenient map initialization with capacity hint
219/// 
220/// **Optimization**: Pre-allocates exact capacity to avoid rehashing
221/// 
222/// # Examples
223/// ```
224/// # use avila_atom::map;
225/// let m = map! {
226///     "key1" => "value1",
227///     "key2" => "value2",
228/// };
229/// assert_eq!(m.get("key1"), Some(&"value1"));
230/// ```
231#[macro_export]
232macro_rules! map {
233    ($($key:expr => $value:expr),* $(,)?) => {{
234        // Count entries at compile-time
235        const COUNT: usize = {
236            let mut count = 0;
237            $( let _ = $key; count += 1; )*
238            count
239        };
240        
241        let mut m = $crate::AssociativeArray::with_capacity(COUNT);
242        $(
243            m.insert($key, $value);
244        )*
245        m
246    }};
247}
248
249/// Macro for convenient vector initialization
250/// 
251/// **Note**: Delegates to stdlib `vec![]` which uses optimized inline assembly
252/// 
253/// # Examples
254/// ```
255/// # use avila_atom::list;
256/// let v = list![1, 2, 3, 4, 5];
257/// assert_eq!(v.len(), 5);
258/// ```
259#[macro_export]
260macro_rules! list {
261    ($($item:expr),* $(,)?) => {{
262        vec![$($item),*]
263    }};
264}
265
266/// Macro for creating fixed-size arrays with type inference
267/// 
268/// **Performance**: Stack-allocated, zero heap operations
269/// 
270/// # Examples
271/// ```
272/// # use avila_atom::array;
273/// let arr = array![1, 2, 3, 4];
274/// assert_eq!(arr.len(), 4);
275/// ```
276#[macro_export]
277macro_rules! array {
278    ($($item:expr),* $(,)?) => {{
279        $crate::fixed::FixedArray::new([$($item),*])
280    }};
281}
282
283/// Macro for compile-time size assertions
284/// 
285/// **Purpose**: Verify structure sizes match expectations for ABI compatibility
286/// 
287/// # Examples
288/// ```
289/// # use avila_atom::static_assert_size;
290/// static_assert_size!(Option<&str>, 16); // Two pointers on 64-bit
291/// ```
292#[macro_export]
293macro_rules! static_assert_size {
294    ($type:ty, $expected:expr) => {
295        const _: [(); $expected] = [(); ::core::mem::size_of::<$type>()];
296    };
297}
298
299#[cfg(test)]
300mod tests {
301    use super::*;
302
303    #[test]
304    fn test_option() {
305        let some: Option<i32> = Option::Some(42);
306        let none: Option<i32> = Option::None;
307
308        assert!(some.is_some());
309        assert!(none.is_none());
310    }
311
312    #[test]
313    fn test_result() {
314        let ok: Result<i32, &str> = Result::Ok(42);
315        let err: Result<i32, &str> = Result::Err("error");
316
317        assert!(ok.is_ok());
318        assert!(err.is_err());
319    }
320
321    #[test]
322    fn test_dynamic_array() {
323        let mut v: DynamicArray<i32> = DynamicArray::new();
324        assert_eq!(v.capacity(), 0); // Zero allocation initially
325        
326        v.push(1);
327        v.push(2);
328        v.push(3);
329
330        assert_eq!(v.len(), 3);
331        assert!(v.capacity() >= 3); // Capacity grows as needed
332    }
333
334    #[test]
335    fn test_dynamic_array_with_capacity() {
336        let v: DynamicArray<i32> = DynamicArray::with_capacity(100);
337        assert_eq!(v.capacity(), 100);
338        assert_eq!(v.len(), 0);
339    }
340
341    #[test]
342    #[cfg(feature = "std")]
343    fn test_associative_array() {
344        let m = map! {
345            "key1" => "value1",
346            "key2" => "value2",
347        };
348
349        assert_eq!(m.get("key1"), Some(&"value1"));
350        assert_eq!(m.get("key2"), Some(&"value2"));
351        assert_eq!(m.len(), 2);
352    }
353
354    #[test]
355    fn test_string_buffer() {
356        let s: StringBuffer = StringBuffer::from("Hello, Avila!");
357        assert_eq!(s.len(), 13);
358        assert!(s.is_ascii()); // Performance hint: ASCII-only allows SIMD
359    }
360    
361    #[test]
362    fn test_string_buffer_utf8() {
363        let s: StringBuffer = StringBuffer::from("Ávila 🚀");
364        assert_eq!(s.chars().count(), 7); // Character count
365        assert_eq!(s.len(), 11); // Byte count (UTF-8 encoded)
366    }
367    
368    #[test]
369    fn test_fixed_array() {
370        use crate::fixed::FixedArray;
371        
372        let arr = FixedArray::new([1, 2, 3, 4, 5]);
373        assert_eq!(arr.len(), 5);
374        assert_eq!(arr.as_slice()[0], 1);
375    }
376    
377    #[test]
378    fn test_option_size_optimization() {
379        use core::mem::size_of;
380        
381        // Null pointer optimization: Option<&T> same size as *const T
382        assert_eq!(size_of::<Option<&i32>>(), size_of::<&i32>());
383        assert_eq!(size_of::<Option<Box<i32>>>(), size_of::<Box<i32>>());
384    }
385    
386    #[test]
387    fn test_result_error_handling() {
388        fn divide(a: i32, b: i32) -> Result<i32, &'static str> {
389            if b == 0 {
390                Err("Division by zero")
391            } else {
392                Ok(a / b)
393            }
394        }
395        
396        assert_eq!(divide(10, 2), Ok(5));
397        assert_eq!(divide(10, 0), Err("Division by zero"));
398    }
399    
400    #[test]
401    fn test_iterator_performance() {
402        use crate::iter::IntoIteratorWithHint;
403        
404        let v = list![1, 2, 3, 4, 5];
405        let (lower, upper) = v.size_hint_before();
406        
407        assert_eq!(lower, 5);
408        assert_eq!(upper, Some(5));
409    }
410    
411    #[test]
412    #[cfg(feature = "std")]
413    fn test_map_macro_capacity() {
414        let m = map! {
415            1 => "one",
416            2 => "two",
417            3 => "three",
418        };
419        
420        // Map should be pre-allocated with exact capacity
421        assert!(m.capacity() >= 3);
422    }
423}