diff --git a/examples/load-people/vaccine.rs b/examples/load-people/vaccine.rs index 9ab4c8ef..0de3aaff 100644 --- a/examples/load-people/vaccine.rs +++ b/examples/load-people/vaccine.rs @@ -12,7 +12,9 @@ define_property!( }, Person ); -define_property!(struct VaccineEfficacy(f64), Person); +#[derive(Debug, PartialEq, Clone, Copy, serde::Serialize, serde::Deserialize)] +pub struct VaccineEfficacy(pub f64); +impl_property!(VaccineEfficacy, Person); define_property!(struct VaccineDoses(u8), Person); pub trait ContextVaccineExt: ContextRandomExt { diff --git a/examples/time-varying-infection/population_loader.rs b/examples/time-varying-infection/population_loader.rs index f235c51f..7177ed3f 100644 --- a/examples/time-varying-infection/population_loader.rs +++ b/examples/time-varying-infection/population_loader.rs @@ -14,11 +14,9 @@ define_property!( default_const = DiseaseStatus::S ); -define_property!( - struct InfectionTime(Option), - Person, - default_const = InfectionTime(None) -); +#[derive(Debug, PartialEq, Clone, Copy, serde::Serialize, serde::Deserialize)] +pub struct InfectionTime(pub Option); +impl_property!(InfectionTime, Person, default_const = InfectionTime(None)); pub fn init(context: &mut Context) { let parameters = context diff --git a/src/entity/property_impl_tests.rs b/src/entity/property_impl_tests.rs index 5a00e72a..5971e152 100644 --- a/src/entity/property_impl_tests.rs +++ b/src/entity/property_impl_tests.rs @@ -14,14 +14,18 @@ define_property!(struct Pu32(u32), Person, default_const = Pu32(0)); define_property!(struct POu32(Option), Person, default_const = POu32(None)); define_property!(struct Name(&'static str), Person, default_const = Name("")); define_property!(struct Age(u8), Person, default_const = Age(0)); -define_property!(struct Weight(f64), Person, default_const = Weight(0.0)); +#[derive(Debug, PartialEq, Clone, Copy, serde::Serialize, serde::Deserialize)] +struct Weight(f64); +impl_property!(Weight, Person, default_const = Weight(0.0)); // A struct with named fields -define_property!( - struct Innocculation { - time: f64, - dose: u8, - }, +#[derive(Debug, PartialEq, Clone, Copy, serde::Serialize, serde::Deserialize)] +struct Innocculation { + time: f64, + dose: u8, +} +impl_property!( + Innocculation, Person, default_const = Innocculation { time: 0.0, dose: 0 } ); diff --git a/src/macros/property_impl.rs b/src/macros/property_impl.rs index 4ab57deb..1a2b6206 100644 --- a/src/macros/property_impl.rs +++ b/src/macros/property_impl.rs @@ -5,7 +5,7 @@ Macros for implementing properties. # [`define_property!`][macro@crate::define_property] For the most common cases, use the [`define_property!`][macro@crate::define_property] macro. This macro defines a struct or enum -with the standard derives required by the [`Property`][crate::entity::property::Property] trait and implements [`Property`][crate::entity::property::Property] (via +with a standard set of derives and implements [`Property`][crate::entity::property::Property] (via [`impl_property!`][macro@crate::impl_property]) for you. ```rust,ignore @@ -26,8 +26,8 @@ Notice the convenient `default_const = ` keyword argument that al define a compile-time constant default value for the property. This is an optional argument. If it is omitted, a value for the property must be supplied upon entity creation. -The primary advantage of using this macro is that it automatically derives the list of traits every -[`Property`][crate::entity::property::Property] needs to derive for you. You don't have to remember them. You also get a cute syntax for +The primary advantage of using this macro is that it automatically derives the standard property traits for you. You +don't have to remember them. You also get a cute syntax for specifying the default value, but it's not much harder to specify default values using other macros. Notice you need to use the `struct` or `enum` keywords, but you don't need to @@ -38,7 +38,9 @@ and to inner fields of tuple structs in the expansion. You can implement [`Property`][crate::entity::property::Property] for existing types using the [`impl_property!`][macro@crate::impl_property] macro. This macro defines the [`Property`][crate::entity::property::Property] trait implementation for you but doesn't take care of the `#[derive(..)]` boilerplate, so you -have to remember to `derive` all of `Copy, Clone, Debug, PartialEq, Serialize` in your type declaration. +have to remember to derive the traits your type needs. At minimum, property types must satisfy the +[`AnyProperty`][crate::entity::property::AnyProperty] bound (`Copy`, `Clone`, `Debug`, `PartialEq`, `Serialize`). +If you want consistency with the auto-generated `define_property!` derives, also add `Deserialize` and `Hash`. Some examples: @@ -48,15 +50,16 @@ define_entity!(Person); // The `define_property!` automatically adds `pub` visibility to the struct and its tuple // fields. If we want to restrict the visibility of our `Property` type, we can use the // `impl_property!` macro instead. The only -// catch is, we have to remember to `derive` all of `Copy, Clone, Debug, PartialEq, Serialize`. -#[derive(Copy, Clone, Debug, PartialEq, Serialize)] +// catch is, we have to remember to `derive` all of +// `Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Hash`. +#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Hash)] struct Age(pub u8); impl_property!(Age, Person); // Here we derive `Default`, which also requires an attribute on one // of the variants. (`Property` has its own independent mechanism for // assigning default values for entities unrelated to the `Default` trait.) -#[derive(Copy, Clone, Debug, PartialEq, Default, Serialize)] +#[derive(Copy, Clone, Debug, PartialEq, Default, Serialize, Deserialize, Hash)] enum InfectionStatus { #[default] Susceptible, @@ -68,7 +71,7 @@ impl_property!(InfectionStatus, Person, default_const = InfectionStatus::Suscept // Exactly equivalent to // `define_property!(struct Vaccinated(pub bool), Person, default_const = Vaccinated(false));` -#[derive(Copy, Clone, Debug, PartialEq, Serialize)] +#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Hash)] pub struct Vaccinated(pub bool); impl_property!(Vaccinated, Person, default_const = Vaccinated(false)); ``` @@ -102,10 +105,10 @@ you also must provide a conversion function to and from the canonical type. ```rust,ignore define_entity!(WeatherStation); -#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize)] +#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize, Hash)] pub struct DegreesFahrenheit(pub f64); -#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize)] +#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize, Hash)] pub struct DegreesCelsius(pub f64); // Custom canonical type @@ -136,9 +139,9 @@ impl_property!( /// Expands to: /// ```rust /// # use ixa::{impl_property, define_entity}; -/// # use serde::Serialize; +/// # use serde::{Deserialize, Serialize}; /// # define_entity!(Person); -/// #[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize)] +/// #[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize, Hash)] /// pub struct Age(u8); /// impl_property!(Age, Person); /// ``` @@ -157,9 +160,9 @@ impl_property!( /// Expands to: /// ```rust /// # use ixa::{impl_property, define_entity}; -/// # use serde::Serialize; +/// # use serde::{Deserialize, Serialize}; /// # define_entity!(Person); -/// #[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize)] +/// #[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize, Hash)] /// pub struct Coordinates { x: i32, y: i32 } /// impl_property!(Coordinates, Person); /// ``` @@ -180,9 +183,9 @@ impl_property!( /// Expands to: /// ```rust /// # use ixa::{impl_property, define_entity}; -/// # use serde::Serialize; +/// # use serde::{Deserialize, Serialize}; /// # define_entity!(Person); -/// #[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize)] +/// #[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize, Hash)] /// pub enum InfectionStatus { /// Susceptible, /// Infectious, @@ -194,7 +197,7 @@ impl_property!( /// ### Notes /// /// - The generated type always derives the following traits: -/// `Debug`, `PartialEq`, `Eq`, `Clone`, `Copy`, and `Serialize`. +/// `Debug`, `PartialEq`, `Clone`, `Copy`, `Serialize`, `Deserialize`, and `Hash`. /// - Use the optional `default_const = ` argument to define a compile-time constant /// default for the property. /// - If you need a more complex type definition (e.g., generics, attributes, or non-`Copy` @@ -207,7 +210,7 @@ macro_rules! define_property { $entity:ident $(, $($extra:tt)+),* ) => { - #[derive(Debug, PartialEq, Clone, Copy, serde::Serialize)] + #[derive(Debug, PartialEq, Clone, Copy, serde::Serialize, serde::Deserialize, Hash)] pub struct $name(pub Option<$inner_ty>); // Use impl_property! to provide a custom display implementation @@ -230,7 +233,7 @@ macro_rules! define_property { $entity:ident $(, $($extra:tt)+),* ) => { - #[derive(Debug, PartialEq, Clone, Copy, serde::Serialize)] + #[derive(Debug, PartialEq, Clone, Copy, serde::Serialize, serde::Deserialize, Hash)] pub struct $name($(pub $field_ty),*); $crate::impl_property!($name, $entity $(, $($extra)+)*); }; @@ -241,7 +244,7 @@ macro_rules! define_property { $entity:ident $(, $($extra:tt)+),* ) => { - #[derive(Debug, PartialEq, Clone, Copy, serde::Serialize)] + #[derive(Debug, PartialEq, Clone, Copy, serde::Serialize, serde::Deserialize, Hash)] pub struct $name { $(pub $field_name : $field_ty),* } $crate::impl_property!($name, $entity $(, $($extra)+)*); }; @@ -254,7 +257,7 @@ macro_rules! define_property { $entity:ident $(, $($extra:tt)+),* ) => { - #[derive(Debug, PartialEq, Clone, Copy, serde::Serialize)] + #[derive(Debug, PartialEq, Clone, Copy, serde::Serialize, serde::Deserialize, Hash)] pub enum $name { $($variant),* } @@ -278,9 +281,9 @@ macro_rules! define_property { /// /// ```rust /// # use ixa::{impl_property, define_entity}; -/// # use serde::Serialize; +/// # use serde::{Deserialize, Serialize}; /// # define_entity!(Person); -/// #[derive(Default, Debug, PartialEq, Eq, Clone, Copy, Serialize)] +/// #[derive(Default, Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize, Hash)] /// pub enum InfectionStatus { /// #[default] /// Susceptible, @@ -539,7 +542,7 @@ macro_rules! define_derived_property { // For `canonical_value` implementations: $(, $($extra:tt)+),* ) => { - #[derive(Debug, PartialEq, Eq, Clone, Copy, serde::Serialize)] + #[derive(Debug, PartialEq, Eq, Clone, Copy, serde::Serialize, serde::Deserialize, Hash)] pub struct $name(pub Option<$inner_ty>); // Use impl_derived_property! to provide a custom display implementation @@ -569,7 +572,7 @@ macro_rules! define_derived_property { // For `canonical_value` implementations: $(, $($extra:tt)+),* ) => { - #[derive(Debug, PartialEq, Eq, Clone, Copy, serde::Serialize)] + #[derive(Debug, PartialEq, Eq, Clone, Copy, serde::Serialize, serde::Deserialize, Hash)] pub struct $name( $(pub $field_ty),* ); $crate::impl_derived_property!( @@ -592,7 +595,7 @@ macro_rules! define_derived_property { // For `canonical_value` implementations: $(, $($extra:tt)+),* ) => { - #[derive(Debug, PartialEq, Eq, Clone, Copy, serde::Serialize)] + #[derive(Debug, PartialEq, Eq, Clone, Copy, serde::Serialize, serde::Deserialize, Hash)] pub struct $name { $($visibility $field_name : $field_ty),* } $crate::impl_derived_property!( @@ -617,7 +620,7 @@ macro_rules! define_derived_property { // For `canonical_value` implementations: $(, $($extra:tt)+),* ) => { - #[derive(Debug, PartialEq, Eq, Clone, Copy, serde::Serialize)] + #[derive(Debug, PartialEq, Eq, Clone, Copy, serde::Serialize, serde::Deserialize, Hash)] pub enum $name { $($variant),* } @@ -836,14 +839,18 @@ mod tests { define_property!(struct POu32(Option), Person, default_const = POu32(None)); define_property!(struct Name(&'static str), Person, default_const = Name("")); define_property!(struct Age(u8), Person, default_const = Age(0)); - define_property!(struct Weight(f64), Person, default_const = Weight(0.0)); + #[derive(Debug, PartialEq, Clone, Copy, serde::Serialize, serde::Deserialize)] + struct Weight(f64); + impl_property!(Weight, Person, default_const = Weight(0.0)); // A struct with named fields - define_property!( - struct Innocculation { - time: f64, - dose: u8, - }, + #[derive(Debug, PartialEq, Clone, Copy, serde::Serialize, serde::Deserialize)] + struct Innocculation { + time: f64, + dose: u8, + } + impl_property!( + Innocculation, Person, default_const = Innocculation { time: 0.0, dose: 0 } );