Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion examples/load-people/vaccine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
8 changes: 3 additions & 5 deletions examples/time-varying-infection/population_loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,9 @@ define_property!(
default_const = DiseaseStatus::S
);

define_property!(
struct InfectionTime(Option<f64>),
Person,
default_const = InfectionTime(None)
);
#[derive(Debug, PartialEq, Clone, Copy, serde::Serialize, serde::Deserialize)]
pub struct InfectionTime(pub Option<f64>);
impl_property!(InfectionTime, Person, default_const = InfectionTime(None));

pub fn init(context: &mut Context) {
let parameters = context
Expand Down
16 changes: 10 additions & 6 deletions src/entity/property_impl_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,18 @@ define_property!(struct Pu32(u32), Person, default_const = Pu32(0));
define_property!(struct POu32(Option<u32>), 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 }
);
Expand Down
73 changes: 40 additions & 33 deletions src/macros/property_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -26,8 +26,8 @@ Notice the convenient `default_const = <default_value>` 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
Expand All @@ -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:

Expand All @@ -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,
Expand All @@ -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));
```
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
/// ```
Expand All @@ -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);
/// ```
Expand All @@ -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,
Expand All @@ -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 = <default_value>` 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`
Expand All @@ -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
Expand All @@ -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)+)*);
};
Expand All @@ -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)+)*);
};
Expand All @@ -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),*
}
Expand All @@ -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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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!(
Expand All @@ -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!(
Expand All @@ -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),*
}
Expand Down Expand Up @@ -836,14 +839,18 @@ mod tests {
define_property!(struct POu32(Option<u32>), 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 }
);
Expand Down