1#![no_std]
49
50pub mod layout_of;
51
52use core::alloc::Layout;
53use core::cell::UnsafeCell;
54use core::fmt;
55use core::mem::{self, MaybeUninit};
56use core::ptr::{self, NonNull};
57
58pub struct BumpInto<'a> {
74 array: UnsafeCell<&'a mut [MaybeUninit<u8>]>,
75}
76
77mod sptr {
81 use core::mem::transmute;
82
83 #[inline]
85 pub(crate) fn addr_of<T>(source: *const T) -> usize {
86 unsafe { transmute::<*const T, usize>(source) }
87 }
88
89 #[inline]
92 pub(crate) fn invalid_with_addr<T>(addr: usize) -> *mut T {
93 unsafe { transmute::<usize, *mut T>(addr) }
94 }
95
96 #[inline]
99 pub(crate) unsafe fn with_addr<T>(source: *mut T, addr: usize) -> *mut T {
100 let source_addr = transmute::<*mut T, isize>(source);
101 let dest_addr = addr as isize;
102
103 let offset = dest_addr.wrapping_sub(source_addr);
104
105 source.cast::<u8>().offset(offset).cast::<T>()
119 }
120}
121
122macro_rules! alloc_copy_concat_impl {
125 ($self:ident, $xs_s:ident, [$t:ty] $(=> $from_slice:path)?) => {{
126 let total_len = match $xs_s
127 .iter()
128 .try_fold(0usize, |acc, xs| acc.checked_add(xs.len()))
129 {
130 Some(total_len) => total_len,
131 None => return None,
132 };
133
134 if mem::size_of::<$t>() == 0 {
135 unsafe {
136 return Some($($from_slice)?(core::slice::from_raw_parts_mut(
137 NonNull::dangling().as_ptr(),
138 total_len,
139 )));
140 }
141 }
142
143 let pointer = $self.alloc_space_for_n::<$t>(total_len);
144
145 if pointer.is_null() {
146 return None;
147 }
148
149 unsafe {
150 let mut dest_pointer = pointer;
151
152 for &xs in $xs_s {
153 ptr::copy_nonoverlapping(xs.as_ptr(), dest_pointer, xs.len());
154
155 dest_pointer = dest_pointer.add(xs.len());
156 }
157
158 Some($($from_slice)?(core::slice::from_raw_parts_mut(pointer, total_len)))
159 }
160 }};
161}
162
163impl<'a> BumpInto<'a> {
164 #[inline]
166 pub fn from_slice<S>(array: &'a mut [MaybeUninit<S>]) -> Self {
167 let size = mem::size_of_val(array);
168 let ptr = array.as_mut_ptr().cast();
169 let array = unsafe { core::slice::from_raw_parts_mut(ptr, size) };
170
171 BumpInto {
172 array: UnsafeCell::new(array),
173 }
174 }
175
176 #[inline]
178 pub fn available_bytes(&self) -> usize {
179 unsafe { (*self.array.get()).len() }
180 }
181
182 pub fn available_spaces<L: Into<Option<Layout>>>(&self, layout: L) -> usize {
199 let layout = match layout.into() {
200 Some(layout) => layout,
201 None => return 0,
202 };
203
204 let size = layout.size();
205 let align = layout.align();
206
207 if size == 0 {
208 return usize::MAX;
209 }
210
211 let array = unsafe { &*self.array.get() };
212
213 let array_start = sptr::addr_of(array.as_ptr());
214 let current_end = array_start + array.len();
215 let aligned_end = current_end & !(align - 1);
216
217 if aligned_end <= array_start {
218 return 0;
219 }
220
221 let usable_bytes = aligned_end - array_start;
222 usable_bytes / size
223 }
224
225 #[inline]
230 pub fn available_spaces_for<T>(&self) -> usize {
231 self.available_spaces(layout_of::Single::<T>::new())
232 }
233
234 pub fn alloc_space<L: Into<Option<Layout>>>(&self, layout: L) -> *mut MaybeUninit<u8> {
237 let layout = match layout.into() {
238 Some(layout) => layout,
239 None => return ptr::null_mut(),
240 };
241
242 let size = layout.size();
243 let align = layout.align();
244
245 if size == 0 {
246 return sptr::invalid_with_addr(align);
249 }
250
251 let array = unsafe { &mut *self.array.get() };
252
253 let array_start = sptr::addr_of(array.as_ptr());
256 let current_end = array_start + array.len();
257
258 let preferred_ptr = match current_end.checked_sub(size) {
260 Some(preferred_ptr) => preferred_ptr,
261 None => return ptr::null_mut(),
262 };
263
264 let aligned_ptr = preferred_ptr & !(align - 1);
266
267 if aligned_ptr < array_start {
268 ptr::null_mut()
270 } else {
271 let (remaining_space, allocated_space) = array.split_at_mut(aligned_ptr - array_start);
276
277 *array = remaining_space;
278
279 unsafe { sptr::with_addr(allocated_space.as_mut_ptr(), aligned_ptr) }
280 }
281 }
282
283 #[inline]
287 pub fn alloc_space_for<T>(&self) -> *mut T {
288 self.alloc_space(layout_of::Single::<T>::new()).cast()
289 }
290
291 pub fn alloc_space_for_n<T>(&self, count: usize) -> *mut T {
295 if mem::size_of::<T>() == 0 {
296 return NonNull::dangling().as_ptr();
297 }
298
299 self.alloc_space(layout_of::Array::<T>::from_len(count))
300 .cast()
301 }
302
303 pub fn alloc_space_to_limit_for<T>(&self) -> (NonNull<T>, usize) {
311 if mem::size_of::<T>() == 0 {
312 return (NonNull::dangling(), usize::MAX);
313 }
314
315 let count = self.available_spaces(layout_of::Single::<T>::new());
316
317 let pointer = self
318 .alloc_space(layout_of::Array::<T>::from_len(count))
319 .cast();
320
321 unsafe { (NonNull::new_unchecked(pointer), count) }
322 }
323
324 #[inline]
332 pub fn alloc<T>(&self, x: T) -> Result<&'a mut T, T> {
333 let pointer = self.alloc_space_for::<T>();
334
335 if pointer.is_null() {
336 return Err(x);
337 }
338
339 unsafe {
340 ptr::write(pointer, x);
341
342 Ok(&mut *pointer)
343 }
344 }
345
346 pub fn alloc_with<T, F: FnOnce() -> T>(&self, f: F) -> Result<&'a mut T, F> {
358 #[inline(always)]
359 unsafe fn eval_and_write<T, F: FnOnce() -> T>(pointer: *mut T, f: F) {
360 ptr::write(pointer, f());
364 }
365
366 let pointer = self.alloc_space_for::<T>();
367
368 if pointer.is_null() {
369 return Err(f);
370 }
371
372 unsafe {
373 eval_and_write(pointer, f);
374
375 Ok(&mut *pointer)
376 }
377 }
378
379 #[inline]
386 pub fn alloc_copy<T: Copy>(&self, x: &T) -> Option<&'a mut T> {
387 let pointer = self.alloc_space_for::<T>();
388
389 if pointer.is_null() {
390 return None;
391 }
392
393 unsafe {
394 ptr::copy_nonoverlapping(x, pointer, 1);
395
396 Some(&mut *pointer)
397 }
398 }
399
400 #[inline]
407 pub fn alloc_copy_slice<T: Copy>(&self, xs: &[T]) -> Option<&'a mut [T]> {
408 if mem::size_of::<T>() == 0 {
409 unsafe {
410 return Some(core::slice::from_raw_parts_mut(
411 NonNull::dangling().as_ptr(),
412 xs.len(),
413 ));
414 }
415 }
416
417 let pointer = self
418 .alloc_space(layout_of::Array::<T>::from_len(xs.len()))
419 .cast::<T>();
420
421 if pointer.is_null() {
422 return None;
423 }
424
425 unsafe {
426 ptr::copy_nonoverlapping(xs.as_ptr(), pointer, xs.len());
427
428 Some(core::slice::from_raw_parts_mut(pointer, xs.len()))
429 }
430 }
431
432 #[inline]
456 pub fn alloc_copy_concat_slices<T: Copy>(&self, xs_s: &[&[T]]) -> Option<&'a mut [T]> {
457 alloc_copy_concat_impl!(self, xs_s, [T])
458 }
459
460 #[inline]
484 pub fn alloc_copy_concat_strs(&self, strs: &[&str]) -> Option<&'a mut str> {
485 alloc_copy_concat_impl!(self, strs, [u8] => core::str::from_utf8_unchecked_mut)
486 }
487
488 #[inline]
505 pub fn alloc_n_with<T, I: IntoIterator<Item = T>>(
506 &self,
507 count: usize,
508 iter: I,
509 ) -> Result<&'a mut [T], I> {
510 let pointer = self.alloc_space_for_n::<T>(count);
511
512 if pointer.is_null() {
513 return Err(iter);
514 }
515
516 let iter = iter.into_iter();
517
518 unsafe { Ok(Self::alloc_n_with_inner(pointer, count, iter)) }
519 }
520
521 unsafe fn alloc_n_with_inner<'b, T, I: Iterator<Item = T>>(
531 pointer: *mut T,
532 count: usize,
533 mut iter: I,
534 ) -> &'b mut [T] {
535 #[inline(always)]
536 unsafe fn iter_and_write<T, I: Iterator<Item = T>>(pointer: *mut T, mut iter: I) -> bool {
537 match iter.next() {
538 Some(item) => {
539 ptr::write(pointer, item);
540
541 false
542 }
543 None => true,
544 }
545 }
546
547 for index in 0..count {
548 if iter_and_write(pointer.add(index), &mut iter) {
549 return core::slice::from_raw_parts_mut(pointer, index);
551 }
552 }
553
554 core::slice::from_raw_parts_mut(pointer, count)
555 }
556
557 #[inline]
575 pub fn alloc_down_with<T, I: IntoIterator<Item = T>>(&mut self, iter: I) -> &'a mut [T] {
576 unsafe { self.alloc_down_with_shared(iter) }
577 }
578
579 #[inline]
591 pub unsafe fn alloc_down_with_shared<T, I: IntoIterator<Item = T>>(
592 &self,
593 iter: I,
594 ) -> &'a mut [T] {
595 unsafe fn alloc_down_with_shared_inner<'a, T, I: Iterator<Item = T>>(
596 bump_into: &BumpInto<'a>,
597 mut iter: I,
598 array_start: usize,
599 mut cur_space: usize,
600 ) -> &'a mut [T] {
601 let array = (*bump_into.array.get()).as_mut_ptr();
602
603 let mut count = 0;
604
605 loop {
606 let next_space = cur_space.checked_sub(mem::size_of::<T>());
607
608 let finished = match next_space {
609 Some(next_space) if next_space >= array_start => {
610 *bump_into.array.get() =
616 core::slice::from_raw_parts_mut(array, cur_space - array_start);
617
618 match iter.next() {
619 Some(item) => {
620 cur_space = next_space;
621
622 ptr::write(sptr::with_addr(array, cur_space).cast(), item);
623
624 false
625 }
626 None => true,
627 }
628 }
629 _ => true,
630 };
631
632 if finished {
633 *bump_into.array.get() =
634 core::slice::from_raw_parts_mut(array, cur_space - array_start);
635
636 return core::slice::from_raw_parts_mut(
637 sptr::with_addr(array, cur_space).cast(),
638 count,
639 );
640 }
641
642 count += 1;
643 }
644 }
645
646 let iter = iter.into_iter();
647
648 if mem::size_of::<T>() == 0 {
649 return Self::alloc_n_with_inner(NonNull::dangling().as_ptr(), usize::MAX, iter);
657 }
658
659 let (array_start, current_end) = {
660 let array = &*self.array.get();
661
662 let array_start = sptr::addr_of(array.as_ptr());
665 let current_end = array_start + array.len();
666
667 (array_start, current_end)
668 };
669
670 let aligned_end = current_end & !(mem::align_of::<T>() - 1);
671
672 if aligned_end <= array_start {
673 return &mut [];
674 }
675
676 alloc_down_with_shared_inner(self, iter, array_start, aligned_end)
677 }
678}
679
680impl<'a> fmt::Debug for BumpInto<'a> {
681 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
682 write!(f, "BumpInto {{ {} bytes free }}", self.available_bytes())
683 }
684}
685
686#[macro_export]
708macro_rules! space_uninit {
709 ($capacity:expr) => {{
710 extern crate core;
711
712 let outer_maybe_uninit = core::mem::MaybeUninit::<
713 [core::mem::MaybeUninit<core::primitive::u8>; $capacity],
714 >::uninit();
715
716 unsafe { outer_maybe_uninit.assume_init() }
717 }};
718
719 ($like_ty:ty; $capacity:expr) => {{
720 extern crate core;
721
722 let outer_maybe_uninit =
723 core::mem::MaybeUninit::<[core::mem::MaybeUninit<$like_ty>; $capacity]>::uninit();
724
725 unsafe { outer_maybe_uninit.assume_init() }
726 }};
727}
728
729#[macro_export]
751macro_rules! space_zeroed {
752 ($capacity:expr) => {{
753 extern crate core;
754
755 let outer_maybe_uninit = core::mem::MaybeUninit::<
756 [core::mem::MaybeUninit<core::primitive::u8>; $capacity],
757 >::zeroed();
758
759 unsafe { outer_maybe_uninit.assume_init() }
760 }};
761
762 ($like_ty:ty; $capacity:expr) => {{
763 extern crate core;
764
765 let outer_maybe_uninit =
766 core::mem::MaybeUninit::<[core::mem::MaybeUninit<$like_ty>; $capacity]>::zeroed();
767
768 unsafe { outer_maybe_uninit.assume_init() }
769 }};
770}
771
772#[macro_export]
793macro_rules! space_uninit_aligned {
794 (size: $size:expr, align: $align:literal $(,)?) => {{
795 extern crate core;
796
797 #[repr(C, align($align))]
798 struct __BUMP_INTO_Space {
799 _contents: [core::primitive::u8; $size],
800 }
801
802 unsafe {
803 core::mem::MaybeUninit::<[core::mem::MaybeUninit<__BUMP_INTO_Space>; 1]>::uninit()
804 .assume_init()
805 }
806 }};
807}
808
809#[macro_export]
830macro_rules! space_zeroed_aligned {
831 (size: $size:expr, align: $align:literal $(,)?) => {{
832 extern crate core;
833
834 #[repr(C, align($align))]
835 struct __BUMP_INTO_Space {
836 _contents: [core::primitive::u8; $size],
837 }
838
839 unsafe {
840 core::mem::MaybeUninit::<[core::mem::MaybeUninit<__BUMP_INTO_Space>; 1]>::zeroed()
841 .assume_init()
842 }
843 }};
844}
845
846#[cfg(test)]
847mod tests {
848 use crate::*;
849
850 use core::alloc::Layout;
851
852 #[test]
853 fn alloc() {
854 let mut space = space_uninit!(128);
855 let bump_into = BumpInto::from_slice(&mut space[..]);
856
857 let something1 = bump_into.alloc(123u64).expect("allocation 1 failed");
858
859 assert_eq!(*something1, 123u64);
860
861 let something2 = bump_into.alloc(7775u16).expect("allocation 2 failed");
862
863 assert_eq!(*something1, 123u64);
864 assert_eq!(*something2, 7775u16);
865
866 let something3 = bump_into
867 .alloc_with(|| 251222u64)
868 .ok()
869 .expect("allocation 3 failed");
870
871 assert_eq!(*something1, 123u64);
872 assert_eq!(*something2, 7775u16);
873 assert_eq!(*something3, 251222u64);
874
875 let something4 = bump_into
876 .alloc_copy(&289303u32)
877 .expect("allocation 4 failed");
878
879 assert_eq!(*something1, 123u64);
880 assert_eq!(*something2, 7775u16);
881 assert_eq!(*something3, 251222u64);
882 assert_eq!(*something4, 289303u32);
883
884 if bump_into.alloc_with(|| [0u32; 128]).is_ok() {
885 panic!("allocation 5 succeeded");
886 }
887
888 let something6 = bump_into.alloc(123523u32).expect("allocation 6 failed");
889
890 assert_eq!(*something1, 123u64);
891 assert_eq!(*something2, 7775u16);
892 assert_eq!(*something3, 251222u64);
893 assert_eq!(*something4, 289303u32);
894 assert_eq!(*something6, 123523u32);
895
896 let something7 = bump_into.alloc_space(Layout::from_size_align(17, 8).unwrap());
897
898 assert!(!something7.is_null());
899 assert_eq!(sptr::addr_of(something7) & 7, 0);
900 assert!(sptr::addr_of(something7).checked_add(17).unwrap() <= sptr::addr_of(something6));
901
902 unsafe {
904 ptr::write(something7.cast::<i64>(), -1);
905 }
906
907 assert_eq!(*something1, 123u64);
908 assert_eq!(*something2, 7775u16);
909 assert_eq!(*something3, 251222u64);
910 assert_eq!(*something4, 289303u32);
911 assert_eq!(*something6, 123523u32);
912 }
913
914 #[test]
915 fn alloc_n() {
916 let mut space = space_uninit!(1024);
917 let bump_into = BumpInto::from_slice(&mut space[..]);
918
919 let something1 = bump_into
920 .alloc_copy_slice(&[1u32, 258909, 1000])
921 .expect("allocation 1 failed");
922
923 assert_eq!(something1, &[1u32, 258909, 1000]);
924
925 let something2 = bump_into
926 .alloc_copy_slice(&[1u64, 258909, 1000, 0])
927 .expect("allocation 2 failed");
928
929 assert_eq!(something1, &[1u32, 258909, 1000]);
930 assert_eq!(something2, &[1u64, 258909, 1000, 0]);
931
932 let something3 = bump_into
933 .alloc_n_with(5, core::iter::repeat(61921u16))
934 .expect("allocation 3 failed");
935
936 assert_eq!(something1, &[1u32, 258909, 1000]);
937 assert_eq!(something2, &[1u64, 258909, 1000, 0]);
938 assert_eq!(something3, &[61921u16; 5]);
939
940 let something4 = bump_into
941 .alloc_n_with(6, core::iter::once(71u64))
942 .expect("allocation 4 failed");
943
944 assert_eq!(something1, &[1u32, 258909, 1000]);
945 assert_eq!(something2, &[1u64, 258909, 1000, 0]);
946 assert_eq!(something3, &[61921u16; 5]);
947 assert_eq!(something4, &[71u64]);
948
949 if bump_into.alloc_n_with::<u64, _>(1000, None).is_ok() {
950 panic!("allocation 5 succeeded");
951 }
952
953 let something6 = bump_into
954 .alloc_n_with::<u64, _>(6, None)
955 .expect("allocation 6 failed");
956
957 assert_eq!(something1, &[1u32, 258909, 1000]);
958 assert_eq!(something2, &[1u64, 258909, 1000, 0]);
959 assert_eq!(something3, &[61921u16; 5]);
960 assert_eq!(something4, &[71u64]);
961 assert_eq!(something6, &[]);
962
963 let something7 = bump_into
964 .alloc_copy_concat_slices(&[&[1u32, 258909, 1000]])
965 .expect("allocation 7 failed");
966
967 assert_eq!(something7, &[1u32, 258909, 1000]);
968
969 let something8 = bump_into
970 .alloc_copy_concat_slices(&[&[1u32, 258909, 1000], &[9999], &[]])
971 .expect("allocation 8 failed");
972
973 assert_eq!(something8, &[1u32, 258909, 1000, 9999]);
974
975 let something9 = bump_into
976 .alloc_copy_concat_slices(&[something7, something7, &[1, 2, 3], something7])
977 .expect("allocation 9 failed");
978
979 assert_eq!(
980 something9,
981 &[1u32, 258909, 1000, 1u32, 258909, 1000, 1, 2, 3, 1u32, 258909, 1000],
982 );
983
984 if !bump_into
987 .alloc_space_for_n::<u32>(usize::MAX / 4 + 2)
988 .is_null()
989 {
990 panic!("allocation 10 succeeded");
991 }
992
993 let something11 = bump_into
1001 .alloc_copy_concat_strs(&["สวัสดี"])
1002 .expect("allocation 11 failed");
1003
1004 assert_eq!(something11, "สวัสดี");
1005
1006 let something12 = bump_into
1007 .alloc_copy_concat_strs(&["你好", "\\", ""])
1008 .expect("allocation 12 failed");
1009
1010 assert_eq!(something12, "你好\\");
1011
1012 let something13 = bump_into
1013 .alloc_copy_concat_strs(&[
1014 something11,
1015 something11,
1016 " \n (this parenthetical—is in English!)\r\n",
1017 something11,
1018 ])
1019 .expect("allocation 13 failed");
1020
1021 assert_eq!(
1022 something13,
1023 "สวัสดีสวัสดี \n (this parenthetical—is in English!)\r\nสวัสดี",
1024 );
1025 }
1026
1027 #[cfg(target_pointer_width = "32")]
1028 #[test]
1029 fn alloc_copy_concat_strs_overflow() {
1030 const THIRTY_TWO_MIBS_OF_ZEROES: &'static [u8] = &[0; 1 << 25];
1031
1032 let mut space = space_uninit!(1024);
1033 let bump_into = BumpInto::from_slice(&mut space[..]);
1034
1035 let thirty_two_mib_string =
1040 unsafe { core::str::from_utf8_unchecked(THIRTY_TWO_MIBS_OF_ZEROES) };
1041
1042 if bump_into
1043 .alloc_copy_concat_strs(&[thirty_two_mib_string; 128])
1044 .is_some()
1045 {
1046 panic!("allocation succeeded");
1047 }
1048 }
1049
1050 #[test]
1051 fn available_bytes() {
1052 const LAYOUT_U8: Layout = Layout::new::<u8>();
1053
1054 let mut space = space_uninit!(32);
1055
1056 {
1057 let mut bump_into = BumpInto::from_slice(&mut space[..]);
1058
1059 assert_eq!(
1062 bump_into.available_spaces(layout_of::Array::<u32>::from_len(usize::MAX / 4 + 2)),
1063 0
1064 );
1065
1066 assert_eq!(bump_into.available_bytes(), 32);
1067 assert_eq!(bump_into.available_spaces(LAYOUT_U8), 32);
1068 assert_eq!(bump_into.available_spaces_for::<u8>(), 32);
1069
1070 bump_into.alloc(0u8).expect("allocation 1 failed");
1071
1072 assert_eq!(bump_into.available_bytes(), 31);
1073 assert_eq!(bump_into.available_spaces(LAYOUT_U8), 31);
1074 assert_eq!(bump_into.available_spaces_for::<u8>(), 31);
1075
1076 let spaces_for_u32 = bump_into.available_spaces_for::<u32>();
1077
1078 bump_into.alloc(0u32).expect("allocation 2 failed");
1079
1080 assert_eq!(bump_into.available_spaces_for::<u32>(), spaces_for_u32 - 1);
1081
1082 bump_into.alloc(0u8).expect("allocation 3 failed");
1083
1084 assert_eq!(bump_into.available_spaces_for::<u32>(), spaces_for_u32 - 2);
1085
1086 {
1087 let rest = bump_into.alloc_down_with(core::iter::repeat(0u32));
1088
1089 assert_eq!(rest.len(), spaces_for_u32 - 2);
1090 assert!(rest.len() >= 5);
1091
1092 for &x in rest.iter() {
1093 assert_eq!(x, 0u32);
1094 }
1095 }
1096
1097 assert_eq!(bump_into.available_spaces_for::<u32>(), 0);
1098 assert!(bump_into.available_bytes() < 4);
1099 }
1100
1101 {
1102 let bump_into = BumpInto::from_slice(&mut space[..]);
1103
1104 assert_eq!(bump_into.available_bytes(), 32);
1105 assert_eq!(bump_into.available_spaces(LAYOUT_U8), 32);
1106 assert_eq!(bump_into.available_spaces_for::<u8>(), 32);
1107
1108 let something4 = bump_into.alloc(0u8).expect("allocation 5 failed");
1109
1110 assert_eq!(*something4, 0);
1111
1112 let (pointer, count) = bump_into.alloc_space_to_limit_for::<i64>();
1113
1114 assert_eq!(bump_into.available_spaces_for::<i64>(), 0);
1115 assert!(bump_into.available_bytes() < 8);
1116 assert!(count >= 3);
1117
1118 let pointer = pointer.as_ptr();
1119
1120 for x in 0..count {
1121 unsafe {
1122 core::ptr::write(pointer.add(x), -1);
1123 }
1124 }
1125
1126 assert_eq!(*something4, 0);
1127 }
1128
1129 {
1130 let bump_into = BumpInto::from_slice(&mut space[..]);
1131
1132 assert_eq!(bump_into.available_bytes(), 32);
1133 assert_eq!(bump_into.available_spaces(LAYOUT_U8), 32);
1134 assert_eq!(bump_into.available_spaces_for::<u8>(), 32);
1135
1136 let something6 = bump_into.alloc(0u8).expect("allocation 7 failed");
1137
1138 assert_eq!(*something6, 0);
1139
1140 let rest = unsafe {
1141 let mut count = 0u32;
1142
1143 bump_into.alloc_down_with_shared(core::iter::from_fn(|| {
1144 if bump_into.available_spaces_for::<u32>() > 1 {
1145 count += 1;
1146 Some(count)
1147 } else {
1148 None
1149 }
1150 }))
1151 };
1152
1153 assert_eq!(bump_into.available_spaces_for::<u32>(), 1);
1154 assert!(rest.len() >= 6);
1155
1156 for (a, b) in rest.iter().zip((0..rest.len() as u32).rev()) {
1157 assert_eq!(*a, b + 1);
1158 }
1159
1160 bump_into.alloc(0u32).expect("allocation 9 failed");
1161
1162 assert_eq!(bump_into.available_spaces_for::<u32>(), 0);
1163 assert!(bump_into.available_bytes() < 4);
1164 }
1165 }
1166
1167 #[test]
1168 fn space() {
1169 {
1170 let mut space = space_zeroed!(32);
1171 let bump_into = BumpInto::from_slice(&mut space[..]);
1172
1173 for _ in 0..32 {
1174 let something1 = bump_into.alloc_space_for::<u8>();
1175 if something1.is_null() {
1176 panic!("allocation 1 (in loop) failed");
1177 }
1178 unsafe {
1179 assert_eq!(*something1, 0);
1180 }
1181 }
1182 }
1183
1184 {
1185 let mut space = space_uninit!(u32; 32);
1186 let space_ptr = &space as *const _;
1187 let bump_into = BumpInto::from_slice(&mut space[..]);
1188
1189 let (something2_ptr, something2_size) = bump_into.alloc_space_to_limit_for::<u32>();
1190 let something2_ptr = something2_ptr.as_ptr() as *const u32;
1191 assert_eq!(space_ptr as *const u32, something2_ptr);
1192 assert_eq!(something2_size, 32);
1193 }
1194
1195 {
1196 let mut space = space_zeroed!(u32; 32);
1197 let space_ptr = &space as *const _;
1198 let bump_into = BumpInto::from_slice(&mut space[..]);
1199
1200 let (something3_ptr, something3_size) = bump_into.alloc_space_to_limit_for::<u32>();
1201 let something3_ptr = something3_ptr.as_ptr() as *const u32;
1202 assert_eq!(space_ptr as *const u32, something3_ptr);
1203 assert_eq!(something3_size, 32);
1204
1205 unsafe {
1206 for x in core::slice::from_raw_parts(something3_ptr, something3_size) {
1207 assert_eq!(*x, 0);
1208 }
1209 }
1210 }
1211
1212 {
1213 let mut space = space_uninit_aligned!(size: 32 * 4, align: 4);
1214 let space_ptr = &space as *const _;
1215 let bump_into = BumpInto::from_slice(&mut space[..]);
1216
1217 let (something4_ptr, something4_size) = bump_into.alloc_space_to_limit_for::<u32>();
1218 let something4_ptr = something4_ptr.as_ptr() as *const u32;
1219 assert_eq!(space_ptr as *const u32, something4_ptr);
1220 assert_eq!(something4_size, 32);
1221 }
1222
1223 {
1224 let mut space = space_zeroed_aligned!(size: 32 * 4, align: 4);
1225 let space_ptr = &space as *const _;
1226 let bump_into = BumpInto::from_slice(&mut space[..]);
1227
1228 let (something5_ptr, something5_size) = bump_into.alloc_space_to_limit_for::<u32>();
1229 let something5_ptr = something5_ptr.as_ptr() as *const u32;
1230 assert_eq!(space_ptr as *const u32, something5_ptr);
1231 assert_eq!(something5_size, 32);
1232
1233 unsafe {
1234 for x in core::slice::from_raw_parts(something5_ptr, something5_size) {
1235 assert_eq!(*x, 0);
1236 }
1237 }
1238 }
1239 }
1240
1241 #[test]
1242 fn single() {
1243 use core::mem::MaybeUninit;
1244
1245 let mut space = MaybeUninit::<u32>::uninit();
1246
1247 {
1248 let bump_into = BumpInto::from_slice(core::slice::from_mut(&mut space));
1249 let something1 = bump_into.alloc(0x8359u16).expect("allocation 1 failed");
1250 let something2 = bump_into.alloc(0x1312u16).expect("allocation 2 failed");
1251 assert_eq!(bump_into.available_bytes(), 0);
1252 assert_eq!(*something1, 0x8359);
1253 assert_eq!(*something2, 0x1312);
1254 *something1 = 0xACAB;
1255 assert_eq!(*something1, 0xACAB);
1256 assert_eq!(*something2, 0x1312);
1257 }
1258
1259 unsafe {
1260 #[cfg(target_endian = "little")]
1261 assert_eq!(space.assume_init(), 0xACAB1312);
1262 #[cfg(target_endian = "big")]
1263 assert_eq!(space.assume_init(), 0x1312ACAB);
1264 }
1265 }
1266
1267 #[test]
1268 fn moving() {
1269 let mut space = space_uninit!(32);
1270 let bump_into = BumpInto::from_slice(&mut space[..]);
1271
1272 let something1 = bump_into.alloc(123u64).expect("allocation 1 failed");
1273
1274 assert_eq!(*something1, 123u64);
1275
1276 core::mem::drop(bump_into);
1277
1278 assert_eq!(*something1, 123u64);
1279 }
1280
1281 #[test]
1282 fn alloc_inside_alloc_with() {
1283 let mut space = space_uninit!(u32; 8);
1284
1285 {
1286 let bump_into = BumpInto::from_slice(&mut space[..]);
1287
1288 let mut something2: Option<&mut [u32]> = None;
1289 let something1: &mut u32 = bump_into
1290 .alloc_with(|| {
1291 let inner_something = bump_into
1292 .alloc_n_with(bump_into.available_spaces_for::<u32>(), 0u32..)
1293 .expect("inner allocation failed");
1294
1295 let something1 = inner_something.iter().sum();
1296
1297 something2 = Some(inner_something);
1298
1299 something1
1300 })
1301 .ok()
1302 .expect("allocation 1 failed");
1303
1304 assert_eq!(*something1, (0..7).sum());
1305 assert_eq!(something2, Some(&mut [0, 1, 2, 3, 4, 5, 6][..]));
1306 }
1307
1308 {
1309 let bump_into = BumpInto::from_slice(&mut space[..]);
1310
1311 let mut something4: Option<&mut [u32]> = None;
1312 let something3: &mut [u32] = bump_into
1313 .alloc_n_with(
1314 4,
1315 core::iter::from_fn(|| {
1316 let inner_something = bump_into
1317 .alloc_n_with(bump_into.available_spaces_for::<u32>() / 2 + 1, 0u32..);
1318
1319 inner_something.ok().map(|inner_something| {
1320 let something3 = inner_something.iter().sum();
1321
1322 something4 = Some(inner_something);
1323
1324 something3
1325 })
1326 }),
1327 )
1328 .ok()
1329 .expect("allocation 3 failed");
1330
1331 assert_eq!(something3, &mut [(0..3).sum(), 0]);
1332 assert_eq!(something4, Some(&mut [0][..]));
1333 }
1334 }
1335
1336 #[derive(Debug)]
1337 struct ZstWithDrop;
1338
1339 impl Drop for ZstWithDrop {
1340 fn drop(&mut self) {
1341 panic!("ZstWithDrop was dropped!");
1342 }
1343 }
1344
1345 fn zero_sized(space: &mut [MaybeUninit<u8>]) {
1346 let big_number = if cfg!(miri) { 0x100 } else { 0x10000 };
1347
1348 let space_len = space.len();
1349 let bump_into = BumpInto::from_slice(space);
1350
1351 assert_eq!(bump_into.available_bytes(), space_len);
1352 assert_eq!(
1353 bump_into.available_spaces(Layout::from_size_align(0, 0x100).unwrap()),
1354 usize::MAX
1355 );
1356 assert_eq!(bump_into.available_spaces_for::<ZstWithDrop>(), usize::MAX);
1357
1358 let (nothing1_ptr, nothing1_count) = bump_into.alloc_space_to_limit_for::<ZstWithDrop>();
1359 assert!(!nothing1_ptr.as_ptr().is_null());
1360 assert_eq!(nothing1_count, usize::MAX);
1361
1362 let _nothing2 = bump_into.alloc(ZstWithDrop).expect("allocation 2 failed");
1363
1364 let _nothing3 = bump_into
1365 .alloc_with(|| ZstWithDrop)
1366 .ok()
1367 .expect("allocation 3 failed");
1368
1369 let nothing4 = bump_into
1370 .alloc_copy_slice(&[(), (), (), ()])
1371 .expect("allocation 4 failed");
1372 assert_eq!(nothing4, &[(), (), (), ()]);
1373
1374 let nothing5 = bump_into
1375 .alloc_n_with(big_number, core::iter::repeat_with(|| ZstWithDrop))
1376 .ok()
1377 .expect("allocation 5 failed");
1378 assert_eq!(nothing5.len(), big_number);
1379
1380 let nothing6 = unsafe {
1381 bump_into
1382 .alloc_down_with_shared(core::iter::repeat_with(|| ZstWithDrop).take(big_number))
1383 };
1384 assert_eq!(nothing6.len(), big_number);
1385
1386 let nothing7_array = [(); usize::MAX];
1387 let nothing7 = bump_into
1388 .alloc_copy_slice(¬hing7_array)
1389 .expect("allocation 7 failed");
1390 assert_eq!(nothing7.len(), usize::MAX);
1391
1392 let nothing8 = bump_into
1393 .alloc_copy_concat_slices(&[&[(), ()], &[(), (), ()], &[]])
1394 .expect("allocation 8 failed");
1395 assert_eq!(nothing8, &[(), (), (), (), ()]);
1396
1397 let nothing9_array = [(); usize::MAX];
1398 let nothing9 = bump_into
1399 .alloc_copy_concat_slices(&[¬hing9_array])
1400 .expect("allocation 9 failed");
1401 assert_eq!(nothing9.len(), usize::MAX);
1402
1403 let nothing10_array = [(); usize::MAX >> 4];
1404 let nothing10 = bump_into
1405 .alloc_copy_concat_slices(&[¬hing10_array[..]; 16])
1406 .expect("allocation 10 failed");
1407 assert_eq!(nothing10.len(), usize::MAX & !15);
1408
1409 let nothing11_array = [(); usize::MAX];
1410 let nothing11 = bump_into.alloc_copy_concat_slices(&[¬hing11_array, &[(); 1][..]]);
1411 if nothing11.is_some() {
1412 panic!("allocation 11 succeeded");
1413 }
1414
1415 let nothing12_array = [(); usize::MAX];
1416 let nothing12 = bump_into.alloc_copy_concat_slices(&[¬hing12_array[..]; 2]);
1417 if nothing12.is_some() {
1418 panic!("allocation 12 succeeded");
1419 }
1420 }
1421
1422 #[test]
1423 fn zero_sized_0_space() {
1424 let mut space = space_uninit!(0);
1425 zero_sized(&mut space[..]);
1426 }
1427
1428 #[test]
1429 fn zero_sized_32_space() {
1430 let mut space = space_uninit!(32);
1431 zero_sized(&mut space[..]);
1432 }
1433
1434 #[test]
1435 #[ignore = "hangs when optimizations are off"]
1436 fn zero_sized_usize_max() {
1437 let mut space = space_uninit!(0);
1438 let mut bump_into = BumpInto::from_slice(&mut space[..]);
1439
1440 let nothing1 = bump_into
1441 .alloc_n_with(usize::MAX, core::iter::repeat_with(|| ZstWithDrop))
1442 .ok()
1443 .expect("allocation 1 failed");
1444 assert_eq!(nothing1.len(), usize::MAX);
1445
1446 let nothing2 = bump_into.alloc_down_with(core::iter::repeat_with(|| ZstWithDrop));
1447 assert_eq!(nothing2.len(), usize::MAX);
1448 }
1449
1450 #[test]
1451 fn iteration_count() {
1452 let mut space = space_uninit!(u32; 32);
1453 let mut bump_into = BumpInto::from_slice(&mut space[..]);
1454
1455 let mut iteration_count = 0u32;
1456 let something1 = bump_into
1457 .alloc_n_with(
1458 16,
1459 core::iter::repeat_with(|| {
1460 iteration_count += 1;
1461 iteration_count
1462 }),
1463 )
1464 .ok()
1465 .expect("allocation 1 failed");
1466 assert_eq!(
1467 something1,
1468 &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
1469 );
1470 assert_eq!(iteration_count, 16);
1471
1472 let mut iteration_count = 0usize;
1473 let nothing2 = bump_into
1474 .alloc_n_with(
1475 256,
1476 core::iter::repeat_with(|| {
1477 iteration_count += 1;
1478 ZstWithDrop
1479 }),
1480 )
1481 .ok()
1482 .expect("allocation 2 failed");
1483 assert_eq!(nothing2.len(), 256);
1484 assert_eq!(iteration_count, 256);
1485
1486 let mut iteration_count = 0u32;
1487 let something3 = bump_into.alloc_down_with(core::iter::repeat_with(|| {
1488 iteration_count += 1;
1489 iteration_count
1490 }));
1491 assert_eq!(
1492 something3,
1493 &[16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1],
1494 );
1495 assert_eq!(iteration_count, 16);
1496 }
1497
1498 #[test]
1499 #[ignore = "hangs when optimizations are off"]
1500 fn iteration_count_usize_max() {
1501 let mut space = space_uninit!(u32; 32);
1502 let mut bump_into = BumpInto::from_slice(&mut space[..]);
1503
1504 let mut iteration_count = 0u128;
1505 let nothing1 = bump_into
1506 .alloc_n_with(
1507 usize::MAX,
1508 core::iter::repeat_with(|| {
1509 iteration_count += 1;
1510 ZstWithDrop
1511 }),
1512 )
1513 .ok()
1514 .expect("allocation 1 failed");
1515 assert_eq!(nothing1.len(), usize::MAX);
1516 assert_eq!(iteration_count, usize::MAX as u128);
1517
1518 let mut iteration_count = 0u128;
1519 let nothing2 = bump_into.alloc_down_with(core::iter::repeat_with(|| {
1520 iteration_count += 1;
1521 ZstWithDrop
1522 }));
1523 assert_eq!(nothing2.len(), usize::MAX);
1524 assert_eq!(iteration_count, usize::MAX as u128);
1525 }
1526}