1use crate::people::PeoplePlugin;
2use crate::{Context, ContextPeopleExt, IxaEvent, PersonId, PersonProperty};
3use ixa_derive::IxaEvent;
4
5#[derive(Clone, Copy, IxaEvent)]
8#[allow(clippy::manual_non_exhaustive)]
9pub struct PersonCreatedEvent {
10 pub person_id: PersonId,
12}
13
14#[derive(Copy, Clone)]
17#[allow(clippy::manual_non_exhaustive)]
18pub struct PersonPropertyChangeEvent<T: PersonProperty> {
19 pub person_id: PersonId,
21 pub current: T::Value,
23 pub previous: T::Value,
25}
26
27impl<T: PersonProperty> IxaEvent for PersonPropertyChangeEvent<T> {
28 fn on_subscribe(context: &mut Context) {
29 if T::is_derived() {
30 let _ = context.get_data_container_mut(PeoplePlugin); context.register_property::<T>();
32 }
33 }
34}
35
36#[cfg(test)]
37mod tests {
38 use crate::{
39 define_derived_property, define_global_property, define_person_property,
40 define_person_property_with_default, Context, ContextPeopleExt, PersonCreatedEvent,
41 PersonId, PersonPropertyChangeEvent,
42 };
43 use serde_derive::Serialize;
44 use std::cell::RefCell;
45 use std::rc::Rc;
46
47 define_person_property!(Age, u8);
48 #[derive(Serialize, Copy, Clone, Debug, PartialEq, Eq, Hash)]
49 pub enum AgeGroupValue {
50 Child,
51 Adult,
52 }
53 define_global_property!(Threshold, u8);
54 define_derived_property!(IsEligible, bool, [Age], [Threshold], |age, threshold| {
55 age >= threshold
56 });
57
58 define_derived_property!(AgeGroup, AgeGroupValue, [Age], |age| {
59 if age < 18 {
60 AgeGroupValue::Child
61 } else {
62 AgeGroupValue::Adult
63 }
64 });
65
66 #[derive(Serialize, Copy, Clone, PartialEq, Eq, Debug)]
67 pub enum RiskCategoryValue {
68 High,
69 Low,
70 }
71 define_person_property!(RiskCategory, RiskCategoryValue);
72 define_person_property_with_default!(IsRunner, bool, false);
73 define_person_property!(RunningShoes, u8, |context: &Context, person: PersonId| {
74 let is_runner = context.get_person_property(person, IsRunner);
75 if is_runner {
76 4
77 } else {
78 0
79 }
80 });
81
82 #[test]
83 fn observe_person_addition() {
84 let mut context = Context::new();
85
86 let flag = Rc::new(RefCell::new(false));
87 let flag_clone = flag.clone();
88 context.subscribe_to_event(move |_context, event: PersonCreatedEvent| {
89 *flag_clone.borrow_mut() = true;
90 assert_eq!(event.person_id.0, 0);
91 });
92
93 let _ = context.add_person(()).unwrap();
94 context.execute();
95 assert!(*flag.borrow());
96 }
97
98 #[test]
99 fn observe_person_property_change() {
100 let mut context = Context::new();
101
102 let flag = Rc::new(RefCell::new(false));
103 let flag_clone = flag.clone();
104 context.subscribe_to_event(
105 move |_context, event: PersonPropertyChangeEvent<RiskCategory>| {
106 *flag_clone.borrow_mut() = true;
107 assert_eq!(event.person_id.0, 0, "Person id is correct");
108 assert_eq!(
109 event.previous,
110 RiskCategoryValue::Low,
111 "Previous value is correct"
112 );
113 assert_eq!(
114 event.current,
115 RiskCategoryValue::High,
116 "Current value is correct"
117 );
118 },
119 );
120 let person_id = context
121 .add_person((RiskCategory, RiskCategoryValue::Low))
122 .unwrap();
123 context.set_person_property(person_id, RiskCategory, RiskCategoryValue::High);
124 context.execute();
125 assert!(*flag.borrow());
126 }
127
128 #[test]
129 fn observe_person_property_change_with_set() {
130 let mut context = Context::new();
131
132 let flag = Rc::new(RefCell::new(false));
133 let flag_clone = flag.clone();
134 context.subscribe_to_event(
135 move |_context, _event: PersonPropertyChangeEvent<RunningShoes>| {
136 *flag_clone.borrow_mut() = true;
137 },
138 );
139 let person_id = context.add_person(()).unwrap();
140 context.set_person_property(person_id, RunningShoes, 42);
142 context.execute();
143 assert!(*flag.borrow());
144 }
145
146 #[test]
147 fn get_person_property_change_event() {
148 let mut context = Context::new();
149 let person = context.add_person((Age, 17)).unwrap();
150
151 let flag = Rc::new(RefCell::new(false));
152
153 let flag_clone = flag.clone();
154 context.subscribe_to_event(
155 move |_context, event: PersonPropertyChangeEvent<AgeGroup>| {
156 assert_eq!(event.person_id.0, 0);
157 assert_eq!(event.previous, AgeGroupValue::Child);
158 assert_eq!(event.current, AgeGroupValue::Adult);
159 *flag_clone.borrow_mut() = true;
160 },
161 );
162 context.set_person_property(person, Age, 18);
163 context.execute();
164 assert!(*flag.borrow());
165 }
166
167 #[test]
168 fn test_person_property_change_event_no_people() {
169 let mut context = Context::new();
170 context.subscribe_to_event(|_context, _event: PersonPropertyChangeEvent<IsRunner>| {
172 unreachable!();
173 });
174
175 context.subscribe_to_event(|_context, _event: PersonPropertyChangeEvent<AgeGroup>| {
177 unreachable!();
178 });
179 }
180}