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