Skip to content

Instantly share code, notes, and snippets.

@jpastuszek
Forked from rust-play/playground.rs
Last active February 8, 2021 15:09
Show Gist options
  • Save jpastuszek/06b5dc4d3ab267c0f7a0d379a415c199 to your computer and use it in GitHub Desktop.
Save jpastuszek/06b5dc4d3ab267c0f7a0d379a415c199 to your computer and use it in GitHub Desktop.
Using vtable dispatch to work with owned type behind Box<dyn> trait
use std::any::{Any, TypeId};
use std::fmt::Debug;
pub trait Resource: Any + Debug {
// this returns correct function for the Self to work on Box so that it can be casted and unboxed
fn combine_fn(&self) -> fn(left: Box<dyn Resource>, right: Box<dyn Resource>) -> Box<dyn Resource>;
}
#[derive(Debug)]
struct File(u32);
impl File {
fn combine(left: File, right: File) -> File {
File(left.0 + right.0)
}
}
// taken from Box::downcast as I cannot cast Box<dyn Resource> to Box<dyn Any>
// https://github.com/rust-lang/rfcs/issues/2765#issuecomment-703950666
pub fn downcast<T: Resource>(res: Box<dyn Resource>) -> Result<Box<T>, Box<dyn Resource>> {
if <dyn Resource>::type_id(&*res) == TypeId::of::<T>() {
unsafe {
let raw: *mut (dyn Resource) = Box::into_raw(res);
Ok(Box::from_raw(raw as *mut T))
}
} else {
Err(res)
}
}
impl Resource for File {
fn combine_fn(&self) -> fn(left: Box<dyn Resource>, right: Box<dyn Resource>) -> Box<dyn Resource> {
fn dyn_combine(left: Box<dyn Resource>, right: Box<dyn Resource>) -> Box<dyn Resource> {
let left: File = *downcast::<File>(left).unwrap();
let right: File = *downcast::<File>(right).unwrap();
Box::new(File::combine(left, right))
}
dyn_combine
}
}
fn main() {
let a = File(1);
let b = File(10);
let a: Box<dyn Resource> = Box::new(a);
let b: Box<dyn Resource> = Box::new(b);
let c = a.combine_fn()(a,b);
dbg![c];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment