use crate::prelude_lib::*;
pub trait PropertyMarker: 'static + Register + Send + Sync {
const NAME: Name;
fn header() -> PropertyHeader;
}
#[derive(Debug)]
pub struct PropertyHeader {
pub name: Name,
pub property_type: TypeId,
pub inner_type: TypeId,
}
#[macro_export]
macro_rules! decl_property {
(
$(#[$meta:meta])*
$vis:vis $name:ident
$(: $local_type:ty)?
$(: ~$nonlocal_type:ty)?
) => {
$crate::decl_property! {
$(#[$meta])*
$vis $name
$(: $local_type)?
$(:~$nonlocal_type)?
= Default::default();
}
};
(
$(#[$meta:meta])*
$vis:vis $name:ident
$(: $local_type:ty)?
$(: ~$nonlocal_type:ty)?
= $init:expr;
) => {
$crate::paste::item! {
$(
#[doc(hidden)]
#[allow(non_camel_case_types)]
type [<_v9_property_type_ $name>] = $local_type;
)?
$(
#[doc(hidden)]
#[allow(non_camel_case_types)]
type [<_v9_property_type_ $name>] = $nonlocal_type;
)?
#[doc(hidden)]
#[allow(non_snake_case)]
fn [<_v9_property_init_ $name>]() -> [<_v9_property_type_ $name>] {
$init
}
$vis use self::[<_v9_property_mod_ $name>]::Prop as $name;
#[doc(hidden)]
#[allow(non_snake_case, dead_code, non_camel_case_types)]
mod [<_v9_property_mod_ $name>] {
use $crate::property::prelude::*;
use super::[<_v9_property_type_ $name>] as Type;
use super::[<_v9_property_init_ $name>] as init_fn;
$crate::decl_property!(@wrap_nonlocal $($nonlocal_type)*; $(#[$meta])*);
$(
$crate::decl_property!(@if $local_type);
pub type Prop = Type;
use self::init_fn as localized_init_fn;
unsafe impl Property for Prop {
}
impl AssertLocalType for Prop {}
)?
impl Register for Prop {
fn register(universe: &mut Universe) {
universe.add_mut(
TypeId::of::<Prop>(),
localized_init_fn(),
);
}
}
impl PropertyMarker for Prop {
const NAME: Name = stringify!($name);
fn header() -> PropertyHeader {
PropertyHeader {
name: Self::NAME,
property_type: TypeId::of::<Self>(),
inner_type: TypeId::of::<Type>(),
}
}
}
}
}
};
(@if $ty:ty) => {};
(@wrap_nonlocal ; $(#[$meta:meta])*) => {};
(@wrap_nonlocal $nonlocal_type:ty; $(#[$meta:meta])*) => {
$(#[$meta])*
#[repr(transparent)]
#[derive(Debug, Default)]
pub struct PropGeneric<T> {
pub inner: T,
}
pub type Prop = PropGeneric<Type>;
fn localized_init_fn() -> Prop {
Prop { inner: init_fn() }
}
impl Deref for Prop {
type Target = Type;
fn deref(&self) -> &Type { &self.inner }
}
impl DerefMut for Prop {
fn deref_mut(&mut self) -> &mut Type { &mut self.inner }
}
unsafe impl Property for Prop {}
};
}
pub unsafe trait Property: Any {}
unsafe impl<'a, X: Property> ExtractOwned for &'a X {
type Ty = X;
const ACC: Access = Access::Read;
unsafe fn extract(_universe: &Universe, rez: &mut Rez) -> Self {
rez.take_ref_downcast()
}
}
unsafe impl<'a, X: Property> ExtractOwned for &'a mut X {
type Ty = X;
const ACC: Access = Access::Write;
unsafe fn extract(_universe: &Universe, rez: &mut Rez) -> Self {
rez.take_mut_downcast()
}
}
#[doc(hidden)]
pub mod prelude {
pub use crate::prelude_lib::{Deref, DerefMut, Name, Any, TypeId, Universe};
pub use crate::prelude_lib::{Property, PropertyHeader, PropertyMarker, Register};
#[doc(hidden)]
#[allow(non_camel_case_types)]
pub trait AssertLocalType {}
}
#[cfg(test)]
mod test {
use crate::prelude_lib::*;
#[derive(Debug)]
pub struct MyProperty {
val: i32,
}
decl_property! {
MY_PROPERTY: MyProperty = MyProperty {
val: 27,
};
}
decl_property! {
pub SHORT_PROPERTY: ~i32
}
#[test]
fn property() {
let mut universe = Universe::new();
MY_PROPERTY::register(&mut universe);
universe.kmap(|prop: &MY_PROPERTY| {
println!("{:?}", prop);
});
}
}
#[cfg(test)]
#[allow(unused_imports)]
mod test_compiles {
#[allow(dead_code)]
pub struct Meh {
val: i32,
}
decl_property! { MY_PROPERTY: Meh = Meh { val: 42 }; }
decl_context! {
#[allow(dead_code)]
struct Stuff {
test: &MY_PROPERTY,
test2: &mut NON_LOCAL_PROPERTY,
}
}
decl_property! { NON_LOCAL_PROPERTY: ~i32 }
}