1use crate::{
7 config::SecurityConfig,
8 domain::{DomainError, DomainResult},
9 parser::aligned_alloc::aligned_allocator,
10 security::SecurityValidator,
11};
12use dashmap::DashMap;
13use std::{
14 alloc::Layout,
15 mem,
16 ptr::{self, NonNull},
17 slice,
18 sync::Arc,
19 time::{Duration, Instant},
20};
21
22#[derive(Debug)]
24pub struct BufferPool {
25 pools: Arc<DashMap<BufferSize, BufferBucket>>,
26 config: PoolConfig,
27 stats: Arc<parking_lot::Mutex<PoolStats>>, }
29
30#[derive(Debug, Clone)]
32pub struct PoolConfig {
33 pub max_buffers_per_bucket: usize,
35 pub max_total_memory: usize,
37 pub buffer_ttl: Duration,
39 pub track_stats: bool,
41 pub simd_alignment: usize,
43 pub validator: SecurityValidator,
45}
46
47#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
49pub enum BufferSize {
50 Small = 1024,
52 Medium = 8192,
54 Large = 65536,
56 XLarge = 524288,
58 Huge = 4194304,
60}
61
62#[derive(Debug)]
64struct BufferBucket {
65 buffers: Vec<AlignedBuffer>,
66 last_access: Instant,
67}
68
69pub struct AlignedBuffer {
74 ptr: NonNull<u8>,
76 len: usize,
78 capacity: usize,
80 alignment: usize,
82 layout: Layout,
84 created_at: Instant,
86 last_used: Instant,
88}
89
90unsafe impl Send for AlignedBuffer {}
92
93unsafe impl Sync for AlignedBuffer {}
95
96impl std::fmt::Debug for AlignedBuffer {
97 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
98 f.debug_struct("AlignedBuffer")
99 .field("ptr", &format_args!("0x{:x}", self.ptr.as_ptr() as usize))
100 .field("len", &self.len)
101 .field("capacity", &self.capacity)
102 .field("alignment", &self.alignment)
103 .field("is_aligned", &self.is_aligned())
104 .field("created_at", &self.created_at)
105 .field("last_used", &self.last_used)
106 .finish()
107 }
108}
109
110#[derive(Debug, Clone)]
112pub struct PoolStats {
113 pub total_allocations: u64,
115 pub cache_hits: u64,
117 pub cache_misses: u64,
119 pub current_memory_usage: usize,
121 pub peak_memory_usage: usize,
123 pub cleanup_count: u64,
125}
126
127impl BufferPool {
128 pub fn new() -> Self {
130 Self::with_config(PoolConfig::default())
131 }
132
133 pub fn with_config(config: PoolConfig) -> Self {
135 Self {
136 pools: Arc::new(DashMap::new()),
137 config,
138 stats: Arc::new(parking_lot::Mutex::new(PoolStats::new())),
139 }
140 }
141
142 pub fn with_security_config(security_config: SecurityConfig) -> Self {
144 Self::with_config(PoolConfig::from(&security_config))
145 }
146
147 pub fn acquire(&self, size: BufferSize) -> DomainResult<PooledBuffer> {
149 self.config
151 .validator
152 .validate_buffer_size(size as usize)
153 .map_err(|e| DomainError::SecurityViolation(e.to_string()))?;
154
155 let current_usage = self.current_memory_usage().unwrap_or(0);
157 if current_usage + (size as usize) > self.config.max_total_memory {
158 return Err(DomainError::ResourceExhausted(format!(
159 "Adding buffer of size {} would exceed memory limit: current={}, limit={}",
160 size as usize, current_usage, self.config.max_total_memory
161 )));
162 }
163
164 if self.config.track_stats {
165 self.increment_allocations();
166 }
167
168 if let Some(mut bucket_ref) = self.pools.get_mut(&size)
170 && let Some(mut buffer) = bucket_ref.buffers.pop()
171 {
172 buffer.last_used = Instant::now();
173 bucket_ref.last_access = Instant::now();
174
175 if self.config.track_stats {
176 self.increment_cache_hits();
177 }
178
179 return Ok(PooledBuffer::new(
180 buffer,
181 Arc::clone(&self.pools),
182 size,
183 self.config.max_buffers_per_bucket,
184 ));
185 }
186
187 if self.config.track_stats {
189 self.increment_cache_misses();
190 }
191
192 let buffer = AlignedBuffer::new(size as usize, self.config.simd_alignment)?;
193 Ok(PooledBuffer::new(
194 buffer,
195 Arc::clone(&self.pools),
196 size,
197 self.config.max_buffers_per_bucket,
198 ))
199 }
200
201 pub fn acquire_with_capacity(&self, min_capacity: usize) -> DomainResult<PooledBuffer> {
203 let size = BufferSize::for_capacity(min_capacity);
204 self.acquire(size)
205 }
206
207 pub fn cleanup(&self) -> DomainResult<CleanupStats> {
209 let now = Instant::now();
210 let mut freed_buffers = 0;
211 let mut freed_memory = 0;
212
213 let mut keys_to_remove = Vec::new();
215
216 for mut entry in self.pools.iter_mut() {
217 let bucket = entry.value_mut();
218 let old_count = bucket.buffers.len();
219
220 bucket.buffers.retain(|buffer| {
221 let age = now.duration_since(buffer.last_used);
222 if age > self.config.buffer_ttl {
223 freed_memory += buffer.capacity;
224 false
225 } else {
226 true
227 }
228 });
229
230 freed_buffers += old_count - bucket.buffers.len();
231
232 if bucket.buffers.is_empty()
234 && now.duration_since(bucket.last_access) >= self.config.buffer_ttl
235 {
236 keys_to_remove.push(*entry.key());
237 }
238 }
239
240 for key in keys_to_remove {
242 self.pools.remove(&key);
243 }
244
245 if self.config.track_stats {
246 self.increment_cleanup_count();
247 self.update_current_memory_usage(-(freed_memory as i64));
248 }
249
250 Ok(CleanupStats {
251 freed_buffers,
252 freed_memory,
253 })
254 }
255
256 pub fn stats(&self) -> DomainResult<PoolStats> {
258 let stats = self.stats.lock();
259 Ok(stats.clone())
260 }
261
262 pub fn current_memory_usage(&self) -> DomainResult<usize> {
264 use rayon::prelude::*;
265
266 let usage = self
267 .pools
268 .iter()
269 .par_bridge()
270 .map(|entry| {
271 entry
272 .value()
273 .buffers
274 .par_iter()
275 .map(|b| b.capacity)
276 .sum::<usize>()
277 })
278 .sum();
279
280 Ok(usage)
281 }
282
283 fn increment_allocations(&self) {
286 let mut stats = self.stats.lock();
287 stats.total_allocations += 1;
288 }
289
290 fn increment_cache_hits(&self) {
291 let mut stats = self.stats.lock();
292 stats.cache_hits += 1;
293 }
294
295 fn increment_cache_misses(&self) {
296 let mut stats = self.stats.lock();
297 stats.cache_misses += 1;
298 }
299
300 fn increment_cleanup_count(&self) {
301 let mut stats = self.stats.lock();
302 stats.cleanup_count += 1;
303 }
304
305 fn update_current_memory_usage(&self, delta: i64) {
306 let mut stats = self.stats.lock();
307 stats.current_memory_usage = (stats.current_memory_usage as i64 + delta).max(0) as usize;
308 stats.peak_memory_usage = stats.peak_memory_usage.max(stats.current_memory_usage);
309 }
310}
311
312impl BufferSize {
313 pub fn for_capacity(capacity: usize) -> Self {
315 match capacity {
316 0..=1024 => BufferSize::Small,
317 1025..=8192 => BufferSize::Medium,
318 8193..=65536 => BufferSize::Large,
319 65537..=524288 => BufferSize::XLarge,
320 _ => BufferSize::Huge,
321 }
322 }
323
324 pub fn all_sizes() -> &'static [BufferSize] {
326 &[
327 BufferSize::Small,
328 BufferSize::Medium,
329 BufferSize::Large,
330 BufferSize::XLarge,
331 BufferSize::Huge,
332 ]
333 }
334}
335
336impl AlignedBuffer {
337 pub fn new(capacity: usize, alignment: usize) -> DomainResult<Self> {
347 if !alignment.is_power_of_two() {
349 return Err(DomainError::InvalidInput(format!(
350 "Alignment {} is not a power of 2",
351 alignment
352 )));
353 }
354
355 if alignment > 4096 {
357 return Err(DomainError::InvalidInput(format!(
358 "Alignment {} exceeds maximum of 4096",
359 alignment
360 )));
361 }
362
363 let alignment = alignment.max(mem::align_of::<usize>());
365
366 let rounded = capacity.checked_add(alignment - 1).ok_or_else(|| {
370 DomainError::InvalidInput(format!(
371 "Capacity {} overflows when rounding to alignment {}",
372 capacity, alignment
373 ))
374 })?;
375 let aligned_capacity = rounded & !(alignment - 1);
376
377 let aligned_capacity = aligned_capacity.max(alignment);
379
380 let layout = Layout::from_size_align(aligned_capacity, alignment).map_err(|e| {
382 DomainError::InvalidInput(format!(
383 "Invalid layout: capacity={}, alignment={}, error={}",
384 aligned_capacity, alignment, e
385 ))
386 })?;
387
388 let allocator = aligned_allocator();
390
391 let ptr = unsafe { allocator.alloc_aligned(aligned_capacity, alignment)? };
394
395 let now = Instant::now();
396 Ok(Self {
397 ptr,
398 len: 0,
399 capacity: aligned_capacity,
400 alignment,
401 layout,
402 created_at: now,
403 last_used: now,
404 })
405 }
406
407 pub fn new_sse(capacity: usize) -> DomainResult<Self> {
409 Self::new(capacity, 16) }
411
412 pub fn new_avx2(capacity: usize) -> DomainResult<Self> {
414 Self::new(capacity, 32) }
416
417 pub fn new_avx512(capacity: usize) -> DomainResult<Self> {
419 Self::new(capacity, 64) }
421
422 pub fn as_mut_slice(&mut self) -> &mut [u8] {
424 unsafe { slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len) }
429 }
430
431 pub fn as_slice(&self) -> &[u8] {
433 unsafe { slice::from_raw_parts(self.ptr.as_ptr(), self.len) }
438 }
439
440 pub fn as_mut_capacity_slice(&mut self) -> &mut [u8] {
442 unsafe { slice::from_raw_parts_mut(self.ptr.as_ptr(), self.capacity) }
447 }
448
449 pub unsafe fn set_len(&mut self, new_len: usize) {
454 debug_assert!(
455 new_len <= self.capacity,
456 "new_len {} exceeds capacity {}",
457 new_len,
458 self.capacity
459 );
460 self.len = new_len;
461 self.last_used = Instant::now();
462 }
463
464 pub fn reserve(&mut self, additional: usize) -> DomainResult<()> {
466 let new_capacity = self
467 .len
468 .checked_add(additional)
469 .ok_or_else(|| DomainError::InvalidInput("Capacity overflow".to_string()))?;
470
471 if new_capacity <= self.capacity {
472 return Ok(());
473 }
474
475 let rounded = new_capacity
480 .checked_add(self.alignment - 1)
481 .ok_or_else(|| {
482 DomainError::InvalidInput(format!(
483 "Capacity {} overflows when rounding to alignment {}",
484 new_capacity, self.alignment
485 ))
486 })?;
487 let aligned_capacity = rounded & !(self.alignment - 1);
488
489 if aligned_capacity == 0 || aligned_capacity > isize::MAX as usize {
493 return Err(DomainError::InvalidInput(format!(
494 "Aligned capacity {} is invalid (zero or exceeds isize::MAX)",
495 aligned_capacity
496 )));
497 }
498
499 let new_layout = Layout::from_size_align(aligned_capacity, self.alignment)
502 .map_err(|e| DomainError::InvalidInput(format!("Invalid layout: {}", e)))?;
503
504 let allocator = aligned_allocator();
506
507 let new_ptr =
514 unsafe { allocator.realloc_aligned(self.ptr, self.layout, aligned_capacity)? };
515
516 self.ptr = new_ptr;
517 self.capacity = aligned_capacity;
518 self.layout = new_layout;
519 self.last_used = Instant::now();
520
521 Ok(())
522 }
523
524 pub fn extend_from_slice(&mut self, data: &[u8]) -> DomainResult<()> {
526 let required_capacity = self
527 .len
528 .checked_add(data.len())
529 .ok_or_else(|| DomainError::InvalidInput("Length overflow".to_string()))?;
530
531 if required_capacity > self.capacity {
532 self.reserve(data.len())?;
533 }
534
535 unsafe {
541 ptr::copy_nonoverlapping(data.as_ptr(), self.ptr.as_ptr().add(self.len), data.len());
542 self.len += data.len();
543 }
544
545 self.last_used = Instant::now();
546 Ok(())
547 }
548
549 pub fn clear(&mut self) {
551 self.len = 0;
552 self.last_used = Instant::now();
553 }
554
555 pub fn capacity(&self) -> usize {
557 self.capacity
558 }
559
560 pub fn len(&self) -> usize {
562 self.len
563 }
564
565 pub fn is_empty(&self) -> bool {
567 self.len == 0
568 }
569
570 pub fn as_ptr(&self) -> *const u8 {
572 self.ptr.as_ptr()
573 }
574
575 pub fn as_mut_ptr(&mut self) -> *mut u8 {
577 self.ptr.as_ptr()
578 }
579
580 pub fn is_aligned(&self) -> bool {
585 let ptr_addr = self.ptr.as_ptr() as usize;
586 ptr_addr.is_multiple_of(self.alignment)
587 }
588
589 pub fn actual_alignment(&self) -> usize {
591 let ptr_addr = self.ptr.as_ptr() as usize;
592 if ptr_addr == 0 {
594 return usize::MAX; }
596
597 1 << ptr_addr.trailing_zeros()
599 }
600
601 pub fn is_simd_compatible(&self, simd_type: SimdType) -> bool {
603 let required_alignment = match simd_type {
604 SimdType::Sse => 16,
605 SimdType::Avx2 => 32,
606 SimdType::Avx512 => 64,
607 SimdType::Neon => 16,
608 };
609
610 self.actual_alignment() >= required_alignment
611 }
612}
613
614#[derive(Debug, Clone, Copy, PartialEq, Eq)]
616pub enum SimdType {
617 Sse,
619 Avx2,
621 Avx512,
623 Neon,
625}
626
627impl Drop for AlignedBuffer {
628 fn drop(&mut self) {
629 let allocator = aligned_allocator();
631
632 unsafe {
634 allocator.dealloc_aligned(self.ptr, self.layout);
635 }
636 }
637}
638
639impl Clone for AlignedBuffer {
640 fn clone(&self) -> Self {
641 let mut new_buffer =
643 Self::new(self.capacity, self.alignment).expect("Failed to clone buffer");
644
645 unsafe {
652 ptr::copy_nonoverlapping(self.ptr.as_ptr(), new_buffer.ptr.as_ptr(), self.len);
653 new_buffer.len = self.len;
654 }
655
656 new_buffer
657 }
658}
659
660pub struct PooledBuffer {
662 buffer: Option<AlignedBuffer>,
663 pool: Arc<DashMap<BufferSize, BufferBucket>>,
664 size: BufferSize,
665 max_buffers_per_bucket: usize,
666}
667
668impl PooledBuffer {
669 fn new(
670 buffer: AlignedBuffer,
671 pool: Arc<DashMap<BufferSize, BufferBucket>>,
672 size: BufferSize,
673 max_buffers_per_bucket: usize,
674 ) -> Self {
675 Self {
676 buffer: Some(buffer),
677 pool,
678 size,
679 max_buffers_per_bucket,
680 }
681 }
682
683 pub fn buffer_mut(&mut self) -> Option<&mut AlignedBuffer> {
685 self.buffer.as_mut()
686 }
687
688 pub fn buffer(&self) -> Option<&AlignedBuffer> {
690 self.buffer.as_ref()
691 }
692
693 pub fn capacity(&self) -> usize {
695 self.buffer.as_ref().map(|b| b.capacity()).unwrap_or(0)
696 }
697
698 pub fn clear(&mut self) {
700 if let Some(buffer) = &mut self.buffer {
701 buffer.clear();
702 }
703 }
704}
705
706impl Drop for PooledBuffer {
707 fn drop(&mut self) {
708 if let Some(mut buffer) = self.buffer.take() {
709 buffer.clear(); let mut bucket_ref = self.pool.entry(self.size).or_insert_with(|| BufferBucket {
713 buffers: Vec::new(),
714 last_access: Instant::now(),
715 });
716
717 if bucket_ref.buffers.len() < self.max_buffers_per_bucket {
719 bucket_ref.buffers.push(buffer);
720 bucket_ref.last_access = Instant::now();
721 }
722 }
723 }
724}
725
726#[derive(Debug, Clone)]
728pub struct CleanupStats {
729 pub freed_buffers: usize,
731 pub freed_memory: usize,
733}
734
735impl PoolConfig {
736 pub fn from_security_config(security_config: &SecurityConfig) -> Self {
738 Self::from(security_config)
739 }
740
741 pub fn simd_optimized() -> Self {
743 let mut config = Self::from(&SecurityConfig::high_throughput());
744 config.simd_alignment = 64; config
746 }
747
748 pub fn low_memory() -> Self {
750 let mut config = Self::from(&SecurityConfig::low_memory());
751 config.track_stats = false; config
753 }
754
755 pub fn development() -> Self {
757 Self::from(&SecurityConfig::development())
758 }
759}
760
761impl Default for PoolConfig {
762 fn default() -> Self {
763 let security_config = SecurityConfig::default();
764 Self {
765 max_buffers_per_bucket: security_config.buffers.max_buffers_per_bucket,
766 max_total_memory: security_config.buffers.max_total_memory,
767 buffer_ttl: security_config.buffer_ttl(),
768 track_stats: true,
769 simd_alignment: 32, validator: SecurityValidator::new(security_config),
771 }
772 }
773}
774
775impl From<&SecurityConfig> for PoolConfig {
776 fn from(security_config: &SecurityConfig) -> Self {
777 Self {
778 max_buffers_per_bucket: security_config.buffers.max_buffers_per_bucket,
779 max_total_memory: security_config.buffers.max_total_memory,
780 buffer_ttl: security_config.buffer_ttl(),
781 track_stats: true,
782 simd_alignment: 32, validator: SecurityValidator::new(security_config.clone()),
784 }
785 }
786}
787
788impl PoolStats {
789 fn new() -> Self {
790 Self {
791 total_allocations: 0,
792 cache_hits: 0,
793 cache_misses: 0,
794 current_memory_usage: 0,
795 peak_memory_usage: 0,
796 cleanup_count: 0,
797 }
798 }
799
800 pub fn hit_ratio(&self) -> f64 {
802 if self.total_allocations == 0 {
803 0.0
804 } else {
805 self.cache_hits as f64 / self.total_allocations as f64
806 }
807 }
808
809 pub fn memory_efficiency(&self) -> f64 {
811 if self.peak_memory_usage == 0 {
812 1.0
813 } else {
814 self.current_memory_usage as f64 / self.peak_memory_usage as f64
815 }
816 }
817}
818
819impl Default for BufferPool {
820 fn default() -> Self {
821 Self::new()
822 }
823}
824
825static GLOBAL_BUFFER_POOL: std::sync::OnceLock<BufferPool> = std::sync::OnceLock::new();
827
828pub fn global_buffer_pool() -> &'static BufferPool {
830 GLOBAL_BUFFER_POOL.get_or_init(BufferPool::new)
831}
832
833pub fn initialize_global_buffer_pool(config: PoolConfig) -> DomainResult<()> {
835 GLOBAL_BUFFER_POOL
836 .set(BufferPool::with_config(config))
837 .map_err(|_| {
838 DomainError::InternalError("Global buffer pool already initialized".to_string())
839 })?;
840 Ok(())
841}
842
843#[cfg(test)]
844mod tests {
845 use super::*;
846
847 #[test]
848 fn test_buffer_pool_creation() {
849 let pool = BufferPool::new();
850 assert!(pool.stats().is_ok());
851 }
852
853 #[test]
854 fn test_buffer_allocation() {
855 let pool = BufferPool::new();
856 let buffer = pool.acquire(BufferSize::Medium);
857 assert!(buffer.is_ok());
858
859 let buffer = buffer.unwrap();
860 assert!(buffer.capacity() >= BufferSize::Medium as usize);
861 }
862
863 #[test]
864 fn test_buffer_reuse() {
865 let pool = BufferPool::new();
866
867 {
869 let _buffer = pool.acquire(BufferSize::Small).unwrap();
870 }
871
872 let _buffer2 = pool.acquire(BufferSize::Small).unwrap();
874
875 let stats = pool.stats().unwrap();
877 assert!(stats.cache_hits > 0);
878 }
879
880 #[test]
881 fn test_buffer_size_selection() {
882 assert_eq!(BufferSize::for_capacity(500), BufferSize::Small);
883 assert_eq!(BufferSize::for_capacity(2000), BufferSize::Medium);
884 assert_eq!(BufferSize::for_capacity(50000), BufferSize::Large);
885 assert_eq!(BufferSize::for_capacity(100000), BufferSize::XLarge);
886 }
887
888 #[test]
889 fn test_aligned_buffer_creation_guaranteed() {
890 let test_cases = vec![
892 (1024, 16, "SSE alignment"),
893 (2048, 32, "AVX2 alignment"),
894 (4096, 64, "AVX-512 alignment"),
895 ];
896
897 for (capacity, alignment, description) in test_cases {
898 let buffer = AlignedBuffer::new(capacity, alignment).unwrap();
899
900 let ptr_addr = buffer.as_ptr() as usize;
902 assert_eq!(
903 ptr_addr % alignment,
904 0,
905 "{}: pointer 0x{:x} is not {}-byte aligned",
906 description,
907 ptr_addr,
908 alignment
909 );
910
911 assert!(
913 buffer.is_aligned(),
914 "{}: is_aligned() returned false for properly aligned buffer",
915 description
916 );
917
918 assert!(
920 buffer.capacity() >= capacity,
921 "{}: capacity {} is less than requested {}",
922 description,
923 buffer.capacity(),
924 capacity
925 );
926
927 assert!(
929 buffer.actual_alignment() >= alignment,
930 "{}: actual alignment {} is less than requested {}",
931 description,
932 buffer.actual_alignment(),
933 alignment
934 );
935 }
936 }
937
938 #[test]
939 fn test_buffer_operations() {
940 let mut buffer = AlignedBuffer::new(1024, 32).unwrap();
941
942 assert_eq!(buffer.len(), 0);
944 assert!(buffer.is_empty());
945 assert_eq!(buffer.capacity(), 1024);
946
947 let data = b"Hello, SIMD World!";
949 buffer.extend_from_slice(data).unwrap();
950 assert_eq!(buffer.len(), data.len());
951 assert_eq!(buffer.as_slice(), data);
952
953 buffer.clear();
955 assert_eq!(buffer.len(), 0);
956 assert!(buffer.is_empty());
957 assert_eq!(buffer.capacity(), 1024); unsafe {
961 let slice = buffer.as_mut_capacity_slice();
963 slice[0..5].copy_from_slice(b"SIMD!");
964 buffer.set_len(5);
965 }
966 assert_eq!(buffer.len(), 5);
967 assert_eq!(&buffer.as_slice()[0..5], b"SIMD!");
968 }
969
970 #[test]
971 fn test_buffer_reserve() {
972 let mut buffer = AlignedBuffer::new(64, 32).unwrap();
973 let _initial_alignment = buffer.actual_alignment();
974
975 unsafe {
977 buffer.set_len(32);
978 }
979
980 buffer.reserve(256).unwrap();
982 assert!(
983 buffer.capacity() >= 32 + 256,
984 "Expected capacity >= {}, got {}",
985 32 + 256,
986 buffer.capacity()
987 );
988
989 assert!(
991 buffer.actual_alignment() >= 32,
992 "Alignment not preserved after reserve"
993 );
994 assert!(buffer.is_aligned());
995
996 buffer.extend_from_slice(b"test data").unwrap();
998 let old_data = buffer.as_slice().to_vec();
999
1000 buffer.reserve(1024).unwrap();
1001 assert_eq!(buffer.as_slice(), &old_data[..]);
1002 }
1003
1004 #[test]
1005 fn test_reserve_rejects_capacity_exceeding_isize_max() {
1006 let mut buffer = AlignedBuffer::new(64, 32).unwrap();
1009
1010 let result = buffer.reserve(usize::MAX - 1000);
1011
1012 match result {
1013 Err(DomainError::InvalidInput(msg)) => {
1014 assert!(
1015 msg.contains("isize::MAX"),
1016 "unexpected error message: {}",
1017 msg
1018 );
1019 }
1020 other => panic!("expected InvalidInput error, got {:?}", other),
1021 }
1022
1023 assert_eq!(buffer.capacity(), 64);
1025 buffer.extend_from_slice(b"still usable").unwrap();
1026 assert_eq!(buffer.as_slice(), b"still usable");
1027 }
1028
1029 #[test]
1030 fn test_reserve_rejects_alignment_rounding_past_isize_max() {
1031 let mut buffer = AlignedBuffer::new(64, 32).unwrap();
1036
1037 let result = buffer.reserve(isize::MAX as usize);
1038
1039 assert!(
1040 matches!(result, Err(DomainError::InvalidInput(_))),
1041 "expected InvalidInput error due to alignment rounding overflow, got {:?}",
1042 result
1043 );
1044 }
1045
1046 #[test]
1047 fn test_reserve_rejects_usize_wraparound_in_alignment_rounding() {
1048 let mut buffer = AlignedBuffer::new(64, 32).unwrap();
1054
1055 let result = buffer.reserve(usize::MAX);
1056
1057 assert!(
1058 matches!(result, Err(DomainError::InvalidInput(_))),
1059 "expected InvalidInput error due to usize wraparound in alignment rounding, got {:?}",
1060 result
1061 );
1062
1063 assert_eq!(buffer.capacity(), 64);
1065 buffer.extend_from_slice(b"still usable").unwrap();
1066 assert_eq!(buffer.as_slice(), b"still usable");
1067 }
1068
1069 #[test]
1070 fn test_reserve_rejects_capacity_at_wraparound_boundary() {
1071 let mut buffer = AlignedBuffer::new(64, 32).unwrap();
1076 let boundary_additional = usize::MAX - 30;
1077
1078 let result = buffer.reserve(boundary_additional);
1079
1080 match result {
1081 Err(DomainError::InvalidInput(msg)) => {
1082 assert!(
1083 msg.contains("overflows"),
1084 "expected the checked-add overflow guard's message, got: {}",
1085 msg
1086 );
1087 }
1088 other => panic!("expected InvalidInput error, got {:?}", other),
1089 }
1090
1091 let result = buffer.reserve(boundary_additional - 1);
1095 match result {
1096 Err(DomainError::InvalidInput(msg)) => {
1097 assert!(
1098 msg.contains("isize::MAX"),
1099 "expected the isize::MAX bound guard's message, got: {}",
1100 msg
1101 );
1102 }
1103 other => panic!("expected InvalidInput error, got {:?}", other),
1104 }
1105 }
1106
1107 #[test]
1108 fn test_new_rejects_capacity_overflowing_alignment_rounding() {
1109 let result = AlignedBuffer::new(usize::MAX, 64);
1113
1114 assert!(
1115 matches!(result, Err(DomainError::InvalidInput(_))),
1116 "expected InvalidInput error due to usize wraparound in alignment rounding, got {:?}",
1117 result
1118 );
1119 }
1120
1121 #[test]
1122 fn test_new_zero_capacity_rounds_up_to_alignment() {
1123 let buffer = AlignedBuffer::new(0, 64).unwrap();
1127 assert_eq!(buffer.capacity(), 64);
1128 }
1129
1130 #[test]
1131 fn test_buffer_clone() {
1132 let mut original = AlignedBuffer::new(512, 64).unwrap();
1133 original.extend_from_slice(b"Original data").unwrap();
1134
1135 let cloned = original.clone();
1136
1137 assert_eq!(cloned.len(), original.len());
1139 assert_eq!(cloned.capacity(), original.capacity());
1140 assert_eq!(cloned.alignment, original.alignment);
1141 assert_eq!(cloned.as_slice(), original.as_slice());
1142
1143 assert_ne!(cloned.as_ptr(), original.as_ptr());
1145
1146 assert!(cloned.is_aligned());
1148 assert!(cloned.actual_alignment() >= 64);
1149 }
1150
1151 #[test]
1152 fn test_alignment_validation() {
1153 let valid_alignments = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096];
1155
1156 for &alignment in &valid_alignments {
1157 let result = AlignedBuffer::new(1024, alignment);
1158 assert!(result.is_ok(), "Alignment {} should be valid", alignment);
1159
1160 let buffer = result.unwrap();
1161 assert!(
1162 buffer.is_aligned(),
1163 "Buffer with alignment {} should be aligned",
1164 alignment
1165 );
1166 }
1167
1168 let invalid_alignments = [3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 17, 31, 33, 63, 65];
1170
1171 for &alignment in &invalid_alignments {
1172 let result = AlignedBuffer::new(1024, alignment);
1173 assert!(result.is_err(), "Alignment {} should be invalid", alignment);
1174 }
1175
1176 assert!(AlignedBuffer::new(1024, 8192).is_err());
1178 }
1179
1180 #[test]
1181 fn test_actual_alignment_calculation() {
1182 for &requested_align in &[16, 32, 64] {
1184 let buffer = AlignedBuffer::new(1024, requested_align).unwrap();
1185 let actual = buffer.actual_alignment();
1186
1187 assert!(
1188 actual >= requested_align,
1189 "Actual alignment {} is less than requested {}",
1190 actual,
1191 requested_align
1192 );
1193
1194 assert!(
1196 actual.is_power_of_two(),
1197 "Actual alignment {} is not a power of 2",
1198 actual
1199 );
1200 }
1201 }
1202
1203 #[test]
1204 fn test_simd_compatibility_check() {
1205 let sse_buffer = AlignedBuffer::new_sse(1024).unwrap();
1207 assert!(sse_buffer.is_simd_compatible(SimdType::Sse));
1208 assert!(sse_buffer.is_simd_compatible(SimdType::Neon)); let avx512_buffer = AlignedBuffer::new_avx512(1024).unwrap();
1212 assert!(avx512_buffer.is_simd_compatible(SimdType::Sse));
1213 assert!(avx512_buffer.is_simd_compatible(SimdType::Avx2));
1214 assert!(avx512_buffer.is_simd_compatible(SimdType::Avx512));
1215 assert!(avx512_buffer.is_simd_compatible(SimdType::Neon));
1216 }
1217
1218 #[test]
1219 fn test_zero_copy_verification() {
1220 let mut buffer = AlignedBuffer::new(1024, 32).unwrap();
1221
1222 let ptr_before = buffer.as_ptr();
1224
1225 buffer.clear();
1227 buffer.extend_from_slice(b"test").unwrap();
1228 unsafe {
1229 buffer.set_len(2);
1230 }
1231
1232 assert_eq!(
1234 ptr_before,
1235 buffer.as_ptr(),
1236 "Buffer was moved during operations (not zero-copy)"
1237 );
1238
1239 buffer.reserve(2048).unwrap();
1241 assert!(buffer.is_aligned());
1243 }
1244
1245 #[test]
1246 fn test_pool_cleanup() {
1247 let config = PoolConfig {
1248 buffer_ttl: Duration::from_millis(1),
1249 ..Default::default()
1250 };
1251 let pool = BufferPool::with_config(config);
1252
1253 {
1255 let _buffer = pool.acquire(BufferSize::Small).unwrap();
1256 }
1257
1258 std::thread::sleep(Duration::from_millis(10));
1260
1261 let cleanup_stats = pool.cleanup().unwrap();
1263 assert!(cleanup_stats.freed_buffers > 0);
1264 }
1265
1266 #[test]
1267 fn test_global_buffer_pool() {
1268 let pool = global_buffer_pool();
1269 let buffer = pool.acquire(BufferSize::Medium);
1270 assert!(buffer.is_ok());
1271 }
1272
1273 #[test]
1274 fn test_memory_limit_enforcement() {
1275 let config = PoolConfig {
1276 max_total_memory: 1024, max_buffers_per_bucket: 10,
1278 ..Default::default()
1279 };
1280 let pool = BufferPool::with_config(config);
1281
1282 let result = pool.acquire(BufferSize::Medium); assert!(result.is_err());
1286
1287 if let Err(e) = result {
1288 assert!(e.to_string().contains("memory limit"));
1289 }
1290 }
1291
1292 #[test]
1293 fn test_per_bucket_limit_enforcement() {
1294 let config = PoolConfig {
1295 max_buffers_per_bucket: 2, max_total_memory: 10 * 1024 * 1024, ..Default::default()
1298 };
1299 let pool = BufferPool::with_config(config);
1300
1301 for _ in 0..3 {
1303 let _buffer = pool.acquire(BufferSize::Small).unwrap();
1304 }
1306
1307 let stats = pool.stats().unwrap();
1309 assert!(stats.cache_hits <= 2, "Too many buffers retained in bucket");
1310 }
1311
1312 #[test]
1313 fn test_buffer_size_validation() {
1314 let pool = BufferPool::new();
1315
1316 for size in BufferSize::all_sizes() {
1318 let result = pool.acquire(*size);
1319 assert!(result.is_ok(), "Buffer size {:?} should be valid", size);
1320 }
1321 }
1322
1323 #[test]
1324 fn test_memory_safety() {
1325 for _ in 0..100 {
1328 let buffer = AlignedBuffer::new(1024, 64).unwrap();
1329 drop(buffer);
1330 }
1331
1332 for _ in 0..100 {
1334 let buffer = AlignedBuffer::new(512, 32).unwrap();
1335 let cloned = buffer.clone();
1336 drop(buffer);
1337 drop(cloned);
1338 }
1339 }
1340
1341 #[test]
1342 fn test_simd_specific_constructors() {
1343 let sse_buffer = AlignedBuffer::new_sse(1024).unwrap();
1345 assert!(sse_buffer.is_aligned());
1346 assert!(sse_buffer.is_simd_compatible(SimdType::Sse));
1347 assert_eq!(sse_buffer.alignment, 16);
1348
1349 let avx2_buffer = AlignedBuffer::new_avx2(1024).unwrap();
1351 assert!(avx2_buffer.is_aligned());
1352 assert!(avx2_buffer.is_simd_compatible(SimdType::Avx2));
1353 assert_eq!(avx2_buffer.alignment, 32);
1354
1355 let avx512_buffer = AlignedBuffer::new_avx512(1024).unwrap();
1357 assert!(avx512_buffer.is_aligned());
1358 assert!(avx512_buffer.is_simd_compatible(SimdType::Avx512));
1359 assert_eq!(avx512_buffer.alignment, 64);
1360 }
1361
1362 #[test]
1363 fn test_simd_alignment_compatibility() {
1364 let buffer_64 = AlignedBuffer::new(1024, 64).unwrap();
1365
1366 assert!(buffer_64.is_simd_compatible(SimdType::Sse)); assert!(buffer_64.is_simd_compatible(SimdType::Avx2)); assert!(buffer_64.is_simd_compatible(SimdType::Avx512)); assert!(buffer_64.is_simd_compatible(SimdType::Neon)); #[allow(clippy::assertions_on_constants)]
1376 {
1377 assert!(64 >= 16); assert!(64 >= 32); assert!(64 >= 64); assert!(64 >= 16); }
1382
1383 let buffer_16 = AlignedBuffer::new(1024, 16).unwrap();
1384
1385 assert_eq!(buffer_16.alignment, 16);
1387
1388 assert!(buffer_16.is_simd_compatible(SimdType::Sse));
1390 assert!(buffer_16.is_simd_compatible(SimdType::Neon));
1391
1392 #[allow(clippy::assertions_on_constants)]
1395 {
1396 assert!(16 >= 16); assert!(16 < 32); assert!(16 < 64); }
1400 }
1401
1402 #[test]
1403 fn test_actual_alignment_detection() {
1404 let buffer = AlignedBuffer::new(1024, 64).unwrap();
1405
1406 let actual_alignment = buffer.actual_alignment();
1407 assert!(
1408 actual_alignment >= 64,
1409 "Buffer has actual alignment of {}, expected at least 64",
1410 actual_alignment
1411 );
1412
1413 assert!(actual_alignment.is_power_of_two());
1415 assert!(actual_alignment >= buffer.alignment);
1416 }
1417
1418 #[test]
1419 fn test_simd_pool_configuration() {
1420 let config = PoolConfig {
1422 simd_alignment: 64, ..Default::default()
1424 };
1425 let pool = BufferPool::with_config(config);
1426
1427 let buffer = pool.acquire(BufferSize::Medium).unwrap();
1428 assert!(buffer.buffer().unwrap().is_aligned());
1429 assert!(
1430 buffer
1431 .buffer()
1432 .unwrap()
1433 .is_simd_compatible(SimdType::Avx512)
1434 );
1435 }
1436
1437 #[test]
1438 fn test_alignment_edge_cases() {
1439 let buffer_min = AlignedBuffer::new(64, 1).unwrap();
1441 assert!(buffer_min.is_aligned());
1442 assert!(buffer_min.alignment >= mem::align_of::<usize>());
1443
1444 assert!(AlignedBuffer::new(1024, 3).is_err());
1446 assert!(AlignedBuffer::new(1024, 17).is_err());
1447 assert!(AlignedBuffer::new(1024, 33).is_err());
1448
1449 assert!(AlignedBuffer::new(1024, 8192).is_err());
1451 }
1452
1453 #[test]
1454 fn test_simd_performance_oriented_allocation() {
1455 let buffer = AlignedBuffer::new_avx512(4096).unwrap();
1457
1458 let slice = unsafe { std::slice::from_raw_parts_mut(buffer.ptr.as_ptr(), buffer.capacity) };
1460
1461 for (i, byte) in slice.iter_mut().enumerate() {
1463 *byte = (i % 256) as u8;
1464 }
1465
1466 assert!(buffer.is_aligned());
1468 assert_eq!(slice[0], 0);
1469 assert_eq!(slice[255], 255);
1470 assert_eq!(slice[256], 0);
1471 }
1472}