rust / expert
Snippet
Designing Custom Dynamically Sized Types
Dynamically Sized Types (DSTs) like custom slices or header-prefixed arrays require manual memory allocation and fat pointer construction in Rust. We construct the layout dynamically, allocate raw memory, write components using raw pointer helper macros like `addr_of_mut!` to avoid creating invalid intermediate references, and convert it back to a `Box` via raw pointers.
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
28
use std::alloc::{alloc, handle_alloc_error, Layout};use std::ptr::addr_of_mut;#[repr(C)]struct CustomDst {header: u32,data: [u8],}impl CustomDst {unsafe fn new(header: u32, elements: &[u8]) -> Box<Self> {let count = elements.len();let layout = Layout::new::<u32>().extend(Layout::array::<u8>(count).unwrap()).unwrap().0.pad_to_align();let ptr = alloc(layout);if ptr.is_null() {handle_alloc_error(layout);}let fat_ptr = std::ptr::slice_from_raw_parts_mut(ptr, count) as *mut CustomDst;addr_of_mut!((*fat_ptr).header).write(header);let dst_data_ptr = addr_of_mut!((*fat_ptr).data) as *mut u8;std::ptr::copy_nonoverlapping(elements.as_ptr(), dst_data_ptr, count);Box::from_raw(fat_ptr)}}
Breakdown
1
struct CustomDst {
Defines a custom Dynamically Sized Type where the final field is an unsized slice.
2
let layout = Layout::new::<u32>().extend(...)
Calculates the dynamic size and alignment for the header struct followed by the byte elements.
3
let fat_ptr = std::ptr::slice_from_raw_parts_mut(ptr, count) as *mut CustomDst;
Synthesizes a fat pointer to the custom DST by casting a slice fat pointer.
4
addr_of_mut!((*fat_ptr).header).write(header);
Writes the header field using a raw write operation to prevent constructing uninitialized references.