Skip to content

Instantly share code, notes, and snippets.

@kranfix
Created June 22, 2025 00:15
Show Gist options
  • Save kranfix/7242c3002bbe3d42118d9ae106aba33f to your computer and use it in GitHub Desktop.
Save kranfix/7242c3002bbe3d42118d9ae106aba33f to your computer and use it in GitHub Desktop.
use std::ptr::NonNull;
struct DynBox {
ptr: NonNull<()>,
drop_in_place: fn(NonNull<()>),
}
impl Drop for DynBox {
fn drop(&mut self) {
(self.drop_in_place)(self.ptr)
}
}
impl DynBox {
pub fn new<T>(value: T) -> DynBox {
let b = Box::new(value);
let ptr = unsafe { NonNull::new_unchecked(Box::into_raw(b)) };
fn drop_in_place<T>(ptr: NonNull<()>) {
let ptr = ptr.cast::<T>();
unsafe { drop(Box::from_raw(ptr.as_ptr())) }
}
DynBox {
ptr: ptr.cast::<()>(),
drop_in_place: drop_in_place::<T>,
}
}
pub unsafe fn as_ref<T>(&self) -> &T {
self.ptr.cast::<T>().as_ref()
}
pub unsafe fn as_mut<T>(&mut self) -> &mut T {
self.ptr.cast::<T>().as_mut()
}
pub unsafe fn into_value<T>(self) -> T {
let b = Box::from_raw(self.ptr.cast::<T>().as_ptr());
*b
}
}
pub trait Animal {
fn age(&self) -> f32;
fn name(&self) -> &str;
fn run(&mut self, meters: f32);
}
pub struct AnimalVTable {
__ptr: DynBox,
age_fn: fn(&DynBox) -> f32,
name_fn: fn(&DynBox) -> NonNull<str>,
run_fn: fn(&mut DynBox, meters: f32),
}
impl Animal for AnimalVTable {
fn age(&self) -> f32 {
(self.age_fn)(&self.__ptr)
}
fn name(&self) -> &str {
unsafe { (self.name_fn)(&self.__ptr).as_ref() }
}
fn run(&mut self, meters: f32) {
(self.run_fn)(&mut self.__ptr, meters)
}
}
impl AnimalVTable {
fn new<A: Animal>(animal: A) -> Self {
fn age<A: Animal>(ptr: &DynBox) -> f32 {
let animal = unsafe { ptr.as_ref::<A>() };
animal.age()
}
fn name<A: Animal>(ptr: &DynBox) -> NonNull<str> {
let animal = unsafe { ptr.as_ref::<A>() };
NonNull::from(animal.name())
}
fn run<A: Animal>(ptr: &mut DynBox, meters: f32) {
let animal = unsafe { ptr.as_mut::<A>() };
animal.run(meters)
}
AnimalVTable {
__ptr: DynBox::new(animal),
age_fn: age::<A>,
name_fn: name::<A>,
run_fn: run::<A>,
}
}
}
struct Dog {
pub age: f32,
pub name: String,
pub distance_run: f32,
}
impl Animal for Dog {
fn age(&self) -> f32 {
self.age
}
fn name(&self) -> &str {
&self.name
}
fn run(&mut self, meters: f32) {
self.distance_run += meters;
println!(
"{} ran {} meters. Total: {} meters.",
self.name, meters, self.distance_run
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment