#[macro_export]
macro_rules! __define_person_property_common {
($person_property:ident, $value:ty, $compute_fn:expr, $is_required:expr, $display_impl:expr) => {
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct $person_property;
impl $crate::people::PersonProperty for $person_property {
type Value = $value;
type CanonicalValue = $value;
fn compute(
_context: &$crate::context::Context,
_person: $crate::people::PersonId,
) -> Self::CanonicalValue {
$compute_fn(_context, _person)
}
fn make_canonical(value: Self::Value) -> Self::CanonicalValue {
value
}
fn make_uncanonical(value: Self::CanonicalValue) -> Self::Value {
value
}
fn is_required() -> bool {
$is_required
}
fn get_instance() -> Self {
$person_property
}
fn name() -> &'static str {
stringify!($person_property)
}
fn get_display(value: &Self::CanonicalValue) -> String {
$display_impl(value)
}
}
};
}
#[macro_export]
macro_rules! define_person_property {
($person_property:ident, Option<$value:ty>, $initialize:expr) => {
$crate::__define_person_property_common!(
$person_property,
Option<$value>,
$initialize,
false,
|&value| {
match value {
Some(v) => format!("{:?}", v),
None => "None".to_string(),
}
}
);
};
($person_property:ident, $value:ty, $initialize:expr) => {
$crate::__define_person_property_common!(
$person_property,
$value,
$initialize,
false,
|&value| format!("{:?}", value)
);
};
($person_property:ident, Option<$value:ty>) => {
$crate::__define_person_property_common!(
$person_property,
Option<$value>,
|_, _| panic!("Property not initialized when person created."),
true,
|&value| {
match value {
Some(v) => format!("{:?}", v),
None => "None".to_string(),
}
}
);
};
($person_property:ident, $value:ty) => {
$crate::__define_person_property_common!(
$person_property,
$value,
|_, _| panic!("Property not initialized when person created."),
true,
|&value| format!("{:?}", value)
);
};
}
pub use define_person_property;
#[macro_export]
macro_rules! define_person_property_with_default {
($person_property:ident, Option<$value:ty>, $default:expr) => {
$crate::define_person_property!(
$person_property,
Option<$value>,
|_context, _person_id| { $default }
);
};
($person_property:ident, $value:ty, $default:expr) => {
$crate::define_person_property!($person_property, $value, |_context, _person_id| {
$default
});
};
}
pub use define_person_property_with_default;
#[macro_export]
macro_rules! __define_derived_property_common {
(
$derived_property:ident,
$value:ty,
$canonical_value:ty,
$compute_canonical_impl:expr,
$compute_uncanonical_impl:expr,
$at_dependency_registration:expr,
[$($dependency:ident),*],
[$($global_dependency:ident),*],
|$($param:ident),+| $derive_fn:expr,
$display_impl:expr,
$hash_fn:expr,
$type_id_impl:expr
) => {
#[derive(Debug, Copy, Clone)]
pub struct $derived_property;
impl $crate::people::PersonProperty for $derived_property {
type Value = $value;
type CanonicalValue = $canonical_value;
fn compute(context: &$crate::context::Context, person_id: $crate::people::PersonId) -> Self::Value {
#[allow(unused_imports)]
use $crate::global_properties::ContextGlobalPropertiesExt;
#[allow(unused_parens)]
let ($($param,)*) = (
$(context.get_person_property(person_id, $dependency)),*,
$(
context.get_global_property_value($global_dependency)
.expect(&format!("Global property {} not initialized", stringify!($global_dependency)))
),*
);
#[allow(non_snake_case)]
(|$($param),+| $derive_fn)($($param),+)
}
fn make_canonical(value: Self::Value) -> Self::CanonicalValue {
($compute_canonical_impl)(value)
}
fn make_uncanonical(value: Self::CanonicalValue) -> Self::Value {
($compute_uncanonical_impl)(value)
}
fn is_derived() -> bool { true }
fn dependencies() -> Vec<Box<dyn $crate::people::PersonPropertyHolder>> {
vec![$(
Box::new($dependency) as Box<dyn $crate::people::PersonPropertyHolder>
),*]
}
fn register_dependencies(context: &$crate::context::Context) {
$at_dependency_registration
$(context.register_property::<$dependency>();)+
}
fn get_instance() -> Self {
$derived_property
}
fn name() -> &'static str {
stringify!($derived_property)
}
fn get_display(value: &Self::CanonicalValue) -> String {
$display_impl(value)
}
fn hash_property_value(value: &Self::CanonicalValue) -> u128 {
($hash_fn)(value)
}
fn type_id() -> std::any::TypeId {
$type_id_impl
}
}
};
}
#[macro_export]
macro_rules! define_derived_property {
(
$derived_property:ident,
$value:ty,
[$($dependency:ident),*],
[$($global_dependency:ident),*],
|$($param:ident),+| $derive_fn:expr
) => {
$crate::__define_derived_property_common!(
$derived_property,
$value,
$value,
|v| v,
|v| v,
{},
[$($dependency),*],
[$($global_dependency),*],
|$($param),+| $derive_fn,
|&value| format!("{:?}", value),
$crate::hashing::hash_serialized_128,
std::any::TypeId::of::<Self>()
);
};
(
$derived_property:ident,
$value:ty,
[$($dependency:ident),*],
|$($param:ident),+| $derive_fn:expr
) => {
$crate::__define_derived_property_common!(
$derived_property,
$value,
$value,
|v| v,
|v| v,
{},
[$($dependency),*],
[],
|$($param),+| $derive_fn,
|&value| format!("{:?}", value),
$crate::hashing::hash_serialized_128,
std::any::TypeId::of::<Self>()
);
};
}
pub use define_derived_property;
#[macro_export]
macro_rules! define_multi_property {
(
$person_property:ident,
( $($dependency:ident),+ )
) => {
$crate::paste::paste! {
$crate::__define_derived_property_common!(
// Name
$person_property,
// `PersonProperty::Value` type
( $(<$dependency as $crate::people::PersonProperty>::Value),+ ),
$crate::sorted_value_type!(( $($dependency),+ )),
$person_property::reorder_by_tag,
$person_property::unreorder_by_tag,
{
let type_ids = &mut [$($dependency::type_id()),+ ];
type_ids.sort();
$crate::people::register_type_ids_to_muli_property_id(type_ids, Self::type_id());
},
[$($dependency),+],
[],
|$( [<_ $dependency:lower>] ),+| {
( $( [<_ $dependency:lower>] ),+ )
},
|values_tuple: &Self::CanonicalValue| {
let values_tuple: Self::Value = Self::unreorder_by_tag(*values_tuple);
let mut displayed = String::from("(");
let ( $( [<_ $dependency:lower>] ),+ ) = values_tuple;
$(
displayed.push_str(<$dependency as $crate::PersonProperty>::get_display(
& <$dependency as $crate::PersonProperty>::make_canonical([<_ $dependency:lower>])
).as_str());
displayed.push_str(", ");
)+
displayed.truncate(displayed.len() - 2);
displayed.push_str(")");
displayed
},
$crate::hashing::hash_serialized_128,
std::any::TypeId::of::<$crate::sorted_tag!(( $($dependency),+ ))>()
);
$crate::impl_make_canonical!($person_property, ( $($dependency),+ ));
}
};
}
pub use define_multi_property;