Created
June 22, 2025 00:15
-
-
Save kranfix/7242c3002bbe3d42118d9ae106aba33f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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