title: “NonNull Reference Implementations” meta_description: “Complete reference implementations of Box, Vec, and intrusive list using NonNull.” keywords: [“nonnull implementation”, “box with nonnull”, “vec with nonnull”]
📚 Reinventing from Scratch: NonNull<T>
Chapter 11 — “Appendix: Reference Implementations”
“See it all come together.”
🎯 Complete Box Implementation
use std::alloc::{alloc, dealloc, Layout};
use std::ptr::NonNull;
pub struct MyBox<T> {
ptr: NonNull<T>,
}
impl<T> MyBox<T> {
pub fn new(value: T) -> Self {
let layout = Layout::new::<T>();
let ptr = unsafe {
let p = alloc(layout) as *mut T;
let nn = NonNull::new(p).expect("Allocation failed");
nn.as_ptr().write(value);
nn
};
Self { ptr }
}
pub fn into_raw(self) -> *mut T {
let ptr = self.ptr.as_ptr();
std::mem::forget(self);
ptr
}
pub unsafe fn from_raw(ptr: *mut T) -> Self {
Self {
ptr: NonNull::new_unchecked(ptr),
}
}
}
impl<T> std::ops::Deref for MyBox<T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { self.ptr.as_ref() }
}
}
impl<T> std::ops::DerefMut for MyBox<T> {
fn deref_mut(&mut self) -> &mut T {
unsafe { self.ptr.as_mut() }
}
}
impl<T> Drop for MyBox<T> {
fn drop(&mut self) {
unsafe {
std::ptr::drop_in_place(self.ptr.as_ptr());
let layout = Layout::new::<T>();
dealloc(self.ptr.as_ptr() as *mut u8, layout);
}
}
}
📦 Complete RawVec Implementation
pub struct RawVec<T> {
ptr: NonNull<T>,
cap: usize,
}
impl<T> RawVec<T> {
pub fn new() -> Self {
Self {
ptr: NonNull::dangling(),
cap: 0,
}
}
pub fn with_capacity(cap: usize) -> Self {
if cap == 0 {
return Self::new();
}
let layout = Layout::array::<T>(cap).unwrap();
let ptr = unsafe {
let p = alloc(layout) as *mut T;
NonNull::new(p).expect("Allocation failed")
};
Self { ptr, cap }
}
pub fn grow(&mut self) {
let new_cap = if self.cap == 0 { 4 } else { self.cap * 2 };
let new_layout = Layout::array::<T>(new_cap).unwrap();
let new_ptr = unsafe {
if self.cap == 0 {
alloc(new_layout)
} else {
let old_layout = Layout::array::<T>(self.cap).unwrap();
realloc(self.ptr.as_ptr() as *mut u8, old_layout, new_layout.size())
}
};
self.ptr = NonNull::new(new_ptr as *mut T).expect("Reallocation failed");
self.cap = new_cap;
}
pub fn ptr(&self) -> NonNull<T> {
self.ptr
}
}
impl<T> Drop for RawVec<T> {
fn drop(&mut self) {
if self.cap != 0 {
unsafe {
let layout = Layout::array::<T>(self.cap).unwrap();
dealloc(self.ptr.as_ptr() as *mut u8, layout);
}
}
}
}
🎉 Series Complete!
You’ve mastered NonNull:
✅ What it guarantees (and doesn’t)
✅ The complete API
✅ Provenance and aliasing
✅ Niche optimization
✅ Fat pointers and metadata
✅ Practical patterns
Now go build amazing data structures! 🦀
Series Complete! Check out other topics:
- Vec
— Dynamic arrays - HashMap — Hash tables
- Box
— Smart pointers