Last active
April 29, 2024 04:13
-
-
Save Ryex/d48f8a5f857ab90bd003e89372a6aa8d to your computer and use it in GitHub Desktop.
This file contains 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 macro_rules_attribute::apply; | |
use macro_rules_attribute::derive; | |
macro_rules! object_trait { | |
(@intf $trait_name:ident $trt:path) => { | |
paste::paste! { | |
#[allow(missing_docs)] | |
pub type [<$trt Ref>]<'a, T> = &'a dyn $trt<ID = <T as $trait_name>::ID>; | |
#[allow(missing_docs)] | |
pub type [<$trt RefMut>]<'a, T> = &'a mut dyn $trt<ID = <T as $trait_name>::ID>; | |
} | |
}; | |
( $trait_name:ident {$($trt:path),*}) => { | |
$( | |
object_trait!{@intf $trait_name $trt} | |
)* | |
pub trait $trait_name { | |
type ID; | |
fn id(&self) -> &Self::ID; | |
fn as_object(&self) -> &dyn $trait_name<ID = Self::ID>; | |
fn as_object_mut(&mut self) -> &mut dyn $trait_name<ID = Self::ID>; | |
paste::paste!{$( | |
#[inline(always)] | |
fn [<as_ $trt:lower>](&self) -> Option<[<$trt Ref>]<Self>> { | |
None | |
} | |
#[inline(always)] | |
fn [<as_ $trt:lower _mut>](&mut self) -> Option<[<$trt RefMut>]<Self>> { | |
None | |
} | |
)*} | |
} | |
}; | |
} | |
pub(in crate) use object_trait; | |
macro_rules! ObjectInterface { | |
{ | |
#[custom(implements($trait_name:ident {$($trt:path),*}))] | |
$( #[$attr:meta] )* | |
$viz:vis struct $struct:ident { | |
$( | |
$(#[#field1:meta])* | |
$field1_viz:vis | |
$field1_name:ident : $field1_ty:ty, | |
),* | |
#[custom(object_id)] | |
$(#[$id_attr:meta])* | |
$id_viz:vis $field_id:ident: $id_typ:ty, | |
$( | |
$(#[#field2:meta])* | |
$field2_viz:vis | |
$field2_name:ident : $field2_ty:ty, | |
),* | |
} | |
} => { | |
impl $trait_name for $struct { | |
type ID = $id_typ; | |
fn id(&self) -> &Self::ID { | |
&self.$field_id | |
} | |
#[inline(always)] | |
fn as_object(&self) -> &dyn $trait_name<ID = Self::ID> { | |
self | |
} | |
#[inline(always)] | |
fn as_object_mut(&mut self) -> &mut dyn $trait_name<ID = Self::ID> { | |
self | |
} | |
paste::paste!{$( | |
#[inline(always)] | |
fn [<as_ $trt:lower>](&self) -> Option<[<$trt Ref>]<Self>> { | |
Some(self) | |
} | |
#[inline(always)] | |
fn [<as_ $trt:lower _mut>](&mut self) -> Option<[<$trt RefMut>]<Self>> { | |
Some(self) | |
} | |
)*} | |
} | |
}; | |
} | |
pub(in crate) use ObjectInterface; | |
macro_rules! ObjectTrait { | |
{ | |
#[custom(object_trait = $trait_name:ident)] | |
$(#[$attr:meta])* | |
$viz:vis trait $trt:ident $(: $($bound:path)* )? { | |
$($tbody:tt)* | |
} | |
} => { | |
$(#[$attr])* | |
$viz trait $trt: $($($bound)* +)? $trait_name { | |
$($tbody)* | |
} | |
}; | |
} | |
pub(in crate) use ObjectTrait; | |
object_trait!(Object {Greeter, Memory}); | |
#[apply(ObjectTrait!)] | |
#[custom(object_trait = Object)] | |
pub trait Greeter { | |
fn hello(&self) -> String; | |
} | |
#[apply(ObjectTrait!)] | |
#[custom(object_trait = Object)] | |
pub trait Memory { | |
fn get_memory(&self) -> &Vec<u32>; | |
fn set_memory(&mut self, index: usize, val: u32); | |
} | |
#[derive(ObjectInterface!)] | |
#[custom(implements(Object {Greeter}))] | |
struct TypeA { | |
#[custom(object_id)] | |
id: u32, | |
} | |
impl Greeter for TypeA { | |
fn hello(&self) -> String { | |
"hello World".to_owned() | |
} | |
} | |
#[derive(ObjectInterface!)] | |
#[custom(implements(Object {Memory, Greeter}))] | |
struct TypeB { | |
#[custom(object_id)] | |
id: u32, | |
pub mem: Vec<u32>, | |
} | |
impl Greeter for TypeB { | |
fn hello(&self) -> String { | |
"hello rachel".to_owned() | |
} | |
} | |
impl Memory for TypeB { | |
fn get_memory(&self) -> &Vec<u32> { | |
&self.mem | |
} | |
fn set_memory(&mut self, index: usize, val: u32) { | |
self.mem[index] = val; | |
} | |
} | |
#[derive(ObjectInterface!)] | |
#[custom(implements(Object {Memory}))] | |
struct TypeC { | |
#[custom(object_id)] | |
id: u32, | |
pub mem: Vec<u32>, | |
} | |
impl Memory for TypeC { | |
fn get_memory(&self) -> &Vec<u32> { | |
&self.mem | |
} | |
fn set_memory(&mut self, index: usize, val: u32) { | |
self.mem[index] = val; | |
} | |
} | |
fn main() { | |
let a = Box::new(TypeA { id: 1 }); | |
let b = Box::new(TypeB { | |
id: 2, | |
mem: vec![0, 2, 4], | |
}); | |
let c = Box::new(TypeC { | |
id: 3, | |
mem: vec![5, 7, 9], | |
}); | |
let mut container: Vec<Box<dyn Object<ID = u32>>> = vec![a, b, c]; | |
for obj in container.iter_mut() { | |
let greeter = obj.as_greeter(); | |
if let Some(greeter) = greeter { | |
println!("generic {}", greeter.hello()); | |
} else { | |
println!("no greeter"); | |
} | |
let memory = obj.as_memory_mut(); | |
if let Some(memory) = memory { | |
memory.set_memory(0, 200); | |
println!("generic {:?}", memory.get_memory()); | |
} else { | |
println!("no memory"); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment