rust / expert
Snippet
Manually Allocating Custom Dynamically Sized Types on the Heap
Dynamically Sized Types (DSTs) like slices cannot be created on the stack easily. By using the standard allocator API, we can manually construct custom DSTs by merging layouts, allocating memory, and assembling a fat pointer using slice_from_raw_parts_mut.
snippet.rs
rust
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
use std::alloc::{alloc, Layout};use std::ptr;#[repr(C)]struct CustomBuffer {id: u64,data: [u8],}impl CustomBuffer {fn new(id: u64, slice: &[u8]) -> Box<Self> {let header_layout = Layout::new::<u64>();let array_layout = Layout::array::<u8>(slice.len()).unwrap();let (layout, _) = header_layout.extend(array_layout).unwrap();let layout = layout.pad_to_align();unsafe {let raw_ptr = alloc(layout);if raw_ptr.is_null() {std::alloc::handle_alloc_error(layout);}let dst_ptr = ptr::slice_from_raw_parts_mut(raw_ptr, slice.len()) as *mut CustomBuffer;ptr::write(ptr::addr_of_mut!((*dst_ptr).id), id);ptr::copy_nonoverlapping(slice.as_ptr(), ptr::addr_of_mut!((*dst_ptr).data) as *mut u8, slice.len());Box::from_raw(dst_ptr)}}}
Breakdown
1
let (layout, _) = header_layout.extend(array_layout).unwrap();
Combines the static header layout and the dynamic slice layout dynamically, checking for overflows.
2
let dst_ptr = ptr::slice_from_raw_parts_mut(raw_ptr, slice.len()) as *mut CustomBuffer;
Generates a fat pointer containing both the data address and the length of the slice tail.
3
Box::from_raw(dst_ptr)
Converts the raw fat pointer back into a managed Box, guaranteeing correct deallocation.