multiboot2_common/
boxed.rs1use crate::{ALIGNMENT, Header, MaybeDynSized, increase_to_alignment};
4use alloc::boxed::Box;
5use core::alloc::Layout;
6use core::ops::Deref;
7use core::ptr;
8
9#[must_use]
24pub fn new_boxed<T: MaybeDynSized<Metadata = usize> + ?Sized>(
25 mut header: T::Header,
26 additional_bytes_slices: &[&[u8]],
27) -> Box<T> {
28 let additional_size = additional_bytes_slices
29 .iter()
30 .map(|b| b.len())
31 .sum::<usize>();
32
33 let tag_size = size_of::<T::Header>() + additional_size;
34 header.set_size(tag_size);
35
36 let alloc_size = increase_to_alignment(tag_size);
39 let layout = Layout::from_size_align(alloc_size, ALIGNMENT).unwrap();
40 let heap_ptr = unsafe { alloc::alloc::alloc(layout) };
42 assert!(!heap_ptr.is_null());
43
44 {
46 let len = size_of::<T::Header>();
47 let ptr = &raw const header;
48 unsafe {
51 ptr::copy_nonoverlapping(ptr.cast::<u8>(), heap_ptr, len);
52 }
53 }
54
55 {
57 let mut write_offset = size_of::<T::Header>();
58 for &bytes in additional_bytes_slices {
59 let len = bytes.len();
60 let src = bytes.as_ptr();
61 let dst = heap_ptr.wrapping_add(write_offset);
62 unsafe {
65 ptr::copy_nonoverlapping(src, dst, len);
66 }
67 write_offset += len;
68 }
69 }
70
71 let ptr: *mut T = ptr_meta::from_raw_parts_mut(heap_ptr.cast(), T::dst_len(&header));
75 let reference = unsafe { Box::from_raw(ptr) };
77
78 assert_eq!(
81 size_of_val(reference.deref()),
82 alloc_size,
83 "Allocation should match Rusts expectation"
84 );
85
86 reference
87}
88
89#[must_use]
91pub fn clone_dyn<T: MaybeDynSized<Metadata = usize> + ?Sized>(tag: &T) -> Box<T> {
92 new_boxed(tag.header().clone(), &[tag.payload()])
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98 use crate::Tag;
99 use crate::test_utils::{DummyDstTag, DummyTestHeader};
100
101 #[test]
102 fn test_new_boxed() {
103 let header = DummyTestHeader::new(DummyDstTag::ID, 0);
104 let tag = new_boxed::<DummyDstTag>(header, &[&[0, 1, 2, 3]]);
105 assert_eq!(tag.header().typ(), 42);
106 assert_eq!(tag.payload(), &[0, 1, 2, 3]);
107
108 let header = DummyTestHeader::new(0xdead_beef, 0);
110 let tag = new_boxed::<DummyDstTag>(header, &[&[0], &[1], &[2, 3]]);
111 assert_eq!(tag.header().typ(), 0xdead_beef);
112 assert_eq!(tag.payload(), &[0, 1, 2, 3]);
113 }
114
115 #[test]
116 fn test_clone_tag() {
117 let header = DummyTestHeader::new(DummyDstTag::ID, 0);
118 let tag = new_boxed::<DummyDstTag>(header, &[&[0, 1, 2, 3]]);
119 assert_eq!(tag.header().typ(), 42);
120 assert_eq!(tag.payload(), &[0, 1, 2, 3]);
121
122 let _cloned = clone_dyn(tag.as_ref());
123 }
124}