Files
ic10emu/ic10emu/src/vm/object/macros.rs
2024-05-14 16:26:23 -07:00

471 lines
14 KiB
Rust

macro_rules! object_trait {
(@intf {$trt:ident}) => {
paste::paste! {
#[allow(missing_docs, unused)]
pub type [<$trt Ref>]<'a> = &'a dyn $trt;
#[allow(missing_docs, unused)]
pub type [<$trt RefMut>]<'a> = &'a mut dyn $trt;
}
};
(@body $trait_name:ident { $($trt:ident),* }; ) => {
fn get_id(&self) -> crate::vm::object::ObjectID;
fn set_id(&mut self, id: crate::vm::object::ObjectID);
fn get_prefab(&self) -> &crate::vm::object::Name;
fn get_mut_prefab(&mut self) -> &mut crate::vm::object::Name;
fn get_name(&self) -> &crate::vm::object::Name;
fn get_mut_name(&mut self) -> &mut crate::vm::object::Name;
fn get_vm(&self) -> &std::rc::Rc<crate::vm::VM>;
fn set_vm(&mut self, vm: std::rc::Rc<crate::vm::VM>);
fn type_name(&self) -> &str;
fn as_object(&self) -> &dyn $trait_name;
fn as_mut_object(&mut self) -> &mut dyn $trait_name;
paste::paste! {
$(
#[inline(always)]
fn [<as_ $trt:snake>](&self) -> Option<[<$trt Ref>]> {
None
}
#[inline(always)]
fn [<as_mut_ $trt:snake>](&mut self) -> Option<[<$trt RefMut>]> {
None
}
)*
}
};
(@intf_struct $trait_name:ident { $($trt:ident),* };) => {
paste::paste! {
pub struct [<$trait_name Interfaces>]<'a> {
$(
pub [<$trt:snake>]: Option<[<$trt Ref>]<'a>>,
)*
}
impl<'a> [<$trait_name Interfaces>]<'a> {
pub fn [<from_ $trait_name:snake>](obj: &'a dyn $trait_name) -> [<$trait_name Interfaces>]<'a> {
[<$trait_name Interfaces>] {
$(
[<$trt:snake>]: obj.[<as_ $trt:snake>](),
)*
}
}
}
}
};
( $trait_name:ident $(: $($bound:tt)* )? {$($trt:ident),*}) => {
$(
$crate::vm::object::macros::object_trait!{@intf {$trt}}
)*
#[doc = concat!("Generated with: ", stringify!($($trt),*))]
pub trait $trait_name $(: $($bound)* )? {
$crate::vm::object::macros::object_trait!{@body $trait_name {$($trt),*}; }
}
$crate::vm::object::macros::object_trait!{@intf_struct $trait_name {$($trt),*}; }
};
}
pub(crate) use object_trait;
/// use macro_rules_attribute::derive to apply this macro to a struct
///
/// use `#[custom(object_id)]`, `#[custom(object_prefab)]`, `#[custom(object_name)]`, and `#[custom(object_vm_ref)]`
/// to tag struct fields appropriately
///
/// the tags for `id`, `prefab`, and `name` may appear in any order but `vm_ref` must come last
///
/// - `id` must be `crate::vm::object::ObjectID`
/// - `prefab` and `name` must be `crate::vm::object::Name`
/// - `vm_ref` must be `std::rc::Rc<crate::vm::VM>`
macro_rules! ObjectInterface {
{
@body_final
@trt $trait_name:ident; $struct:ident;
@impls $($trt:path),*;
@id $id_field:ident: $id_typ:ty;
@prefab $prefab_field:ident: $prefab_typ:ty;
@name $name_field:ident: $name_typ:ty;
@vm_ref $vm_ref_field:ident: $vm_ref_typ:ty;
} => {
impl $trait_name for $struct {
fn get_id(&self) -> crate::vm::object::ObjectID {
self.$id_field
}
fn set_id(&mut self, id: crate::vm::object::ObjectID) {
self.$id_field = id;
}
fn get_prefab(&self) -> &$prefab_typ {
&self.$prefab_field
}
fn get_mut_prefab(&mut self) -> &mut $prefab_typ {
&mut self.$prefab_field
}
fn get_name(&self) -> &$name_typ {
&self.$name_field
}
fn get_mut_name(&mut self) -> &mut $name_typ {
&mut self.$name_field
}
fn get_vm(&self) -> &std::rc::Rc<crate::vm::VM> {
&self.$vm_ref_field
}
fn set_vm(&mut self, vm: std::rc::Rc<crate::vm::VM>) {
self.$vm_ref_field = vm;
}
fn type_name(&self) -> &str {
std::any::type_name::<Self>()
}
#[inline(always)]
fn as_object(&self) -> &dyn $trait_name {
self
}
#[inline(always)]
fn as_mut_object(&mut self) -> &mut dyn $trait_name {
self
}
paste::paste!{$(
#[inline(always)]
fn [<as_ $trt:snake>](&self) -> Option<[<$trt Ref>]> {
Some(self)
}
#[inline(always)]
fn [<as_mut_ $trt:snake>](&mut self) -> Option<[<$trt RefMut>]> {
Some(self)
}
)*}
}
};
{
@body_final
@trt $trait_name:ident; $struct:ident;
@impls $($trt:path),*;
@id $id_field:ident: $id_typ:ty;
@name $name_field:ident: $name_typ:ty;
@prefab $prefab_field:ident: $prefab_typ:ty;
@vm_ref $vm_ref_field:ident: $vm_ref_typ:ty;
} => {
$crate::vm::object::macros::ObjectInterface!{
@body_final
@trt $trait_name; $struct;
@impls $($trt),*;
@id $id_field: $id_typ;
@prefab $prefab_field: $prefab_typ;
@name $name_field: $name_typ;
@vm_ref $vm_ref_field: $vm_ref_typ;
}
};
{
@body_final
@trt $trait_name:ident; $struct:ident;
@impls $($trt:path),*;
@prefab $prefab_field:ident: $prefab_typ:ty;
@name $name_field:ident: $name_typ:ty;
@id $id_field:ident: $id_typ:ty;
@vm_ref $vm_ref_field:ident: $vm_ref_typ:ty;
} => {
$crate::vm::object::macros::ObjectInterface!{
@body_final
@trt $trait_name; $struct;
@impls $($trt),*;
@id $id_field: $id_typ;
@prefab $prefab_field: $prefab_typ;
@name $name_field: $name_typ;
@vm_ref $vm_ref_field: $vm_ref_typ;
}
};
{
@body_final
@trt $trait_name:ident; $struct:ident;
@impls $($trt:path),*;
@prefab $prefab_field:ident: $prefab_typ:ty;
@id $id_field:ident: $id_typ:ty;
@name $name_field:ident: $name_typ:ty;
@vm_ref $vm_ref_field:ident: $vm_ref_typ:ty;
} => {
$crate::vm::object::macros::ObjectInterface!{
@body_final
@trt $trait_name; $struct;
@impls $($trt),*;
@id $id_field: $id_typ;
@prefab $prefab_field: $prefab_typ;
@name $name_field: $name_typ;
@vm_ref $vm_ref_field: $vm_ref_typ;
}
};
{
@body_final
@trt $trait_name:ident; $struct:ident;
@impls $($trt:path),*;
@name $name_field:ident: $name_typ:ty;
@prefab $prefab_field:ident: $prefab_typ:ty;
@id $id_field:ident: $id_typ:ty;
@vm_ref $vm_ref_field:ident: $vm_ref_typ:ty;
} => {
$crate::vm::object::macros::ObjectInterface!{
@body_final
@trt $trait_name; $struct;
@impls $($trt),*;
@id $id_field: $id_typ;
@prefab $prefab_field: $prefab_typ;
@name $name_field: $name_typ;
@vm_ref $vm_ref_field: $vm_ref_typ;
}
};
{
@body_final
@trt $trait_name:ident; $struct:ident;
@impls $($trt:path),*;
@name $name_field:ident: $name_typ:ty;
@id $id_field:ident: $id_typ:ty;
@prefab $prefab_field:ident: $prefab_typ:ty;
@vm_ref $vm_ref_field:ident: $vm_ref_typ:ty;
} => {
$crate::vm::object::macros::ObjectInterface!{
@body_final
@trt $trait_name; $struct;
@impls $($trt),*;
@id $id_field: $id_typ;
@prefab $prefab_field: $prefab_typ;
@name $name_field: $name_typ;
@vm_ref $vm_ref_field: $vm_ref_typ;
}
};{
@body
@trt $trait_name:ident; $struct:ident;
@impls $($trt:path),*;
@tags {
$(@$tag:tt $tag_field:ident: $tag_typ:ty;)*
};
#[custom(object_vm_ref)]
$(#[$vm_ref_attr:meta])*
$vm_ref_viz:vis $vm_ref_field:ident: $vm_ref_typ:ty,
$( $rest:tt )*
} => {
$crate::vm::object::macros::ObjectInterface!{
@body
@trt $trait_name; $struct;
@impls $($trt),*;
@tags {$(@$tag $tag_field: $tag_typ;)* @vm_ref $vm_ref_field: $vm_ref_typ;};
$( $rest )*
}
};
{
@body
@trt $trait_name:ident; $struct:ident;
@impls $($trt:path),*;
@tags {
$(@$tag:tt $tag_field:ident: $tag_typ:ty;)*
};
#[custom(object_name)]
$(#[$name_attr:meta])*
$name_viz:vis $name_field:ident: $name_typ:ty,
$( $rest:tt )*
} => {
$crate::vm::object::macros::ObjectInterface!{
@body
@trt $trait_name; $struct;
@impls $($trt),*;
@tags {$(@$tag $tag_field: $tag_typ;)* @name $name_field: $name_typ;};
$( $rest )*
}
};
{
@body
@trt $trait_name:ident; $struct:ident;
@impls $($trt:path),*;
@tags {
$(@$tag:tt $tag_field:ident: $tag_typ:ty;)*
};
#[custom(object_prefab)]
$(#[$prefab_attr:meta])*
$prefab_viz:vis $prefab_field:ident: $prefab_typ:ty,
$( $rest:tt )*
} => {
$crate::vm::object::macros::ObjectInterface!{
@body
@trt $trait_name; $struct;
@impls $($trt),*;
@tags {$(@$tag $tag_field: $tag_typ;)* @prefab $prefab_field: $prefab_typ;};
$( $rest )*
}
};
{
@body
@trt $trait_name:ident; $struct:ident;
@impls $($trt:path),*;
@tags {
$(@$tag:tt $tag_field:ident: $tag_typ:ty;)*
};
#[custom(object_id)]
$(#[$id_attr:meta])*
$id_viz:vis $id_field:ident: $id_typ:ty,
$( $rest:tt )*
} => {
$crate::vm::object::macros::ObjectInterface!{
@body
@trt $trait_name; $struct;
@impls $($trt),*;
@tags {$(@$tag $tag_field: $tag_typ;)* @id $id_field: $id_typ;};
$( $rest )*
}
};
{
@body
@trt $trait_name:ident; $struct:ident;
@impls $($trt:path),*;
@tags {
$(@$tag:tt $tag_field:ident: $tag_typ:ty;)*
};
$(#[$field:meta])*
$field_viz:vis
$field_name:ident : $field_ty:ty,
$( $rest:tt )*
} => {
$crate::vm::object::macros::ObjectInterface!{
@body
@trt $trait_name; $struct;
@impls $($trt),*;
@tags {$(@$tag $tag_field: $tag_typ;)*};
$( $rest )*
}
};
{
@body
@trt $trait_name:ident; $struct:ident;
@impls $($trt:path),*;
@tags {
$(@$tag:tt $tag_field:ident: $tag_typ:ty;)*
};
} => {
$crate::vm::object::macros::ObjectInterface!{
@body_final
@trt $trait_name; $struct;
@impls $($trt),*;
$(
@$tag $tag_field: $tag_typ;
)*
}
};
{
#[custom(implements($trait_name:ident {$($trt:path),*}))]
$( #[$attr:meta] )*
$viz:vis struct $struct:ident {
$( $body:tt )*
}
} => {
$crate::vm::object::macros::ObjectInterface!{
@body
@trt $trait_name; $struct;
@impls $($trt),*;
@tags {};
$( $body )*
}
};
}
pub(crate) use ObjectInterface;
#[allow(unused_macros)]
macro_rules! ObjectTrait {
{
#[custom(object_trait = $trait_name:ident)]
$(#[$attr:meta])*
$viz:vis trait $trt:ident $(: $($bound:tt)* )? {
$($tbody:tt)*
}
} => {
$(#[$attr])*
$viz trait $trt: $($($bound)* +)? $trait_name {
$($tbody)*
}
};
}
#[allow(unused_imports)]
pub(crate) use ObjectTrait;
macro_rules! tag_object_traits {
{
@tag
tag=$trt_name:ident $(: $($obj_bound:tt)* )?;
acc={ $($tagged_trt:ident,)* };
$(#[$attr:meta])*
$viz:vis trait $trt:ident $(: $trt_bound_first:tt $(+ $trt_bound_others:tt)* )? {
$($tbody:tt)*
}
$($used:tt)*
} => {
#[doc = concat!("Autotagged with ", stringify!($trt_name))]
$(#[$attr])*
$viz trait $trt : $( $trt_bound_first $(+ $trt_bound_others)* +)? $trt_name {
$($tbody)*
}
$crate::vm::object::macros::tag_object_traits!{
@tag
tag=$trt_name $(: $($obj_bound)* )?;
acc={ $($tagged_trt,)* $trt, };
$($used)*
}
};
{
@tag
tag=$trt_name:ident $(: $($obj_bound:tt)* )?;
acc={ $($tagged_trt:ident,)* };
impl $name:ident for $trt:path {
$($body:tt)*
}
$($used:tt)*
} => {
/// Untouched by tag macro
impl $name for $trt {
$($body)*
}
$crate::vm::object::macros::tag_object_traits!{
@tag
tag=$trt_name $(: $($obj_bound)* )?;
acc={ $($tagged_trt,)* };
$($used)*
}
};
{
@tag
tag=$trt_name:ident $(: $($obj_bound:tt)* )?;
acc={ $($tagged_trt:ident,)* };
} => {
// end tagged traits {$trt_name}
$crate::vm::object::macros::object_trait!($trt_name $(: $($obj_bound)* )? { $($tagged_trt),* });
};
{ #![object_trait($trt_name:ident $(: $($bound:tt)* )? )] $($tree:tt)* } => {
$crate::vm::object::macros::tag_object_traits!{ @tag tag=$trt_name; acc={}; $($tree)* }
};
}
pub(crate) use tag_object_traits;