reactive_graph_reactive_model_impl/entities/
reactive_entity.rs

1use serde::Serialize;
2use serde::Serializer;
3use serde_json::Map;
4use serde_json::Value;
5use std::fmt::Display;
6use std::fmt::Formatter;
7use std::ops::Deref;
8use std::sync::Arc;
9use typed_builder::TypedBuilder;
10use uuid::Uuid;
11
12use reactive_graph_behaviour_model_api::BehaviourTypeId;
13use reactive_graph_behaviour_model_api::BehaviourTypeIds;
14use reactive_graph_behaviour_model_api::BehaviourTypesContainer;
15use reactive_graph_graph::Component;
16use reactive_graph_graph::ComponentContainer;
17use reactive_graph_graph::ComponentTypeId;
18use reactive_graph_graph::ComponentTypeIds;
19use reactive_graph_graph::EntityInstance;
20use reactive_graph_graph::EntityType;
21use reactive_graph_graph::EntityTypeId;
22use reactive_graph_graph::Extensions;
23use reactive_graph_graph::JsonSchemaId;
24use reactive_graph_graph::Mutability;
25use reactive_graph_graph::Mutability::Mutable;
26use reactive_graph_graph::NamespacedTypeGetter;
27use reactive_graph_graph::PropertyInstanceGetter;
28use reactive_graph_graph::PropertyInstanceSetter;
29use reactive_graph_graph::PropertyInstances;
30use reactive_graph_graph::PropertyType;
31use reactive_graph_graph::TypeDefinition;
32use reactive_graph_graph::TypeDefinitionGetter;
33use reactive_graph_graph::instances::named::NamedInstanceContainer;
34
35use crate::ReactiveProperties;
36use crate::ReactiveProperty;
37use reactive_graph_reactive_model_api::ReactiveInstance;
38use reactive_graph_reactive_model_api::ReactivePropertyContainer;
39
40#[derive(TypedBuilder)]
41#[builder(
42    build_method(vis="pub", into=ReactiveEntity),
43    builder_method(vis = ""),
44    builder_type(vis="pub", name=ReactiveEntityInstanceBuilder),
45)]
46pub struct ReactiveEntityInstance {
47    /// The type definition of the entity type.
48    #[builder(setter(into))]
49    pub ty: EntityTypeId,
50
51    /// The unique identifier of the entity instance.
52    #[builder(default=Uuid::new_v4())]
53    pub id: Uuid,
54
55    /// The name of the entity instance.
56    #[builder(default, setter(into))]
57    pub name: String,
58
59    /// Textual description of the entity instance.
60    #[builder(default, setter(into))]
61    pub description: String,
62
63    /// The reactive properties.
64    #[builder(default, setter(into))]
65    pub properties: ReactiveProperties<Uuid>,
66
67    /// The names of the components which are applied on this entity instance.
68    #[builder(default, setter(into))]
69    pub components: ComponentTypeIds,
70
71    /// The names of the behaviours which are applied on this entity instance.
72    #[builder(default, setter(into))]
73    pub behaviours: BehaviourTypeIds,
74}
75
76#[derive(Clone)]
77pub struct ReactiveEntity(Arc<ReactiveEntityInstance>);
78
79impl ReactiveEntity {
80    pub fn builder() -> ReactiveEntityInstanceBuilder {
81        ReactiveEntityInstance::builder()
82    }
83
84    /// Creates a builder from the given entity type.
85    /// Generates an id for the reactive entity.
86    /// Converts property types into reactive properties and initializes the properties with default values.
87    #[allow(clippy::type_complexity)]
88    pub fn builder_from_entity_type(
89        entity_type: &EntityType,
90    ) -> ReactiveEntityInstanceBuilder<((EntityTypeId,), (Uuid,), (), (), (ReactiveProperties<Uuid>,), (), ())> {
91        let id = Uuid::new_v4();
92        let properties = PropertyInstances::new_from_property_types_with_defaults(&entity_type.properties);
93        let reactive_properties = ReactiveProperties::new_with_id_from_properties(id, properties);
94        ReactiveEntity::builder().ty(&entity_type.ty).id(id).properties(reactive_properties)
95    }
96}
97
98impl NamedInstanceContainer for ReactiveEntity {
99    fn name(&self) -> String {
100        self.name.clone()
101    }
102
103    fn description(&self) -> String {
104        self.description.clone()
105    }
106}
107
108impl Deref for ReactiveEntity {
109    type Target = Arc<ReactiveEntityInstance>;
110
111    fn deref(&self) -> &Self::Target {
112        &self.0
113    }
114}
115
116impl ReactiveInstance<Uuid> for ReactiveEntity {
117    fn id(&self) -> Uuid {
118        self.id
119    }
120}
121
122impl ReactivePropertyContainer for ReactiveEntity {
123    fn tick_checked(&self) {
124        for property in self.properties.iter() {
125            property.tick_checked();
126        }
127    }
128
129    fn tick(&self) {
130        for property in self.properties.iter() {
131            property.tick();
132        }
133    }
134
135    fn has_property(&self, name: &str) -> bool {
136        self.properties.contains_key(name)
137    }
138
139    fn add_property<S: Into<String>>(&self, name: S, mutability: Mutability, value: Value) {
140        let name = name.into();
141        if !self.properties.contains_key(&name) {
142            let property_instance = ReactiveProperty::new(self.id, name.clone(), mutability, value);
143            self.properties.insert(name, property_instance);
144        }
145    }
146
147    fn add_property_by_type(&self, property: &PropertyType) {
148        let property_instance = ReactiveProperty::new(self.id, &property.name, property.mutability, property.data_type.default_value());
149        self.properties.insert(property.name.clone(), property_instance);
150    }
151
152    fn remove_property<S: Into<String>>(&self, name: S) {
153        let name = name.into();
154        self.properties.retain(|property_name, _| property_name != &name);
155    }
156
157    fn observe_with_handle<F>(&self, name: &str, subscriber: F, handle_id: u128)
158    where
159        F: FnMut(&Value) + 'static + Send,
160    {
161        if let Some(property_instance) = self.properties.get(name) {
162            property_instance.stream.read().unwrap().observe_with_handle(subscriber, handle_id);
163        }
164    }
165
166    fn remove_observer(&self, name: &str, handle_id: u128) {
167        if let Some(property_instance) = self.properties.get(name) {
168            property_instance.stream.read().unwrap().remove(handle_id);
169        }
170    }
171
172    fn remove_observers(&self, name: &str) {
173        if let Some(property_instance) = self.properties.get(name) {
174            property_instance.stream.read().unwrap().clear();
175        }
176    }
177
178    fn remove_all_observers(&self) {
179        for property_instance in self.properties.iter() {
180            property_instance.stream.read().unwrap().clear();
181        }
182    }
183}
184
185impl ComponentContainer for ReactiveEntity {
186    fn get_components(&self) -> ComponentTypeIds {
187        self.components.clone()
188        // self.components.iter().map(|c| c.key().clone()).collect()
189    }
190
191    fn add_component(&self, ty: ComponentTypeId) {
192        self.components.insert(ty);
193    }
194
195    fn add_component_with_properties(&self, component: &Component) {
196        self.add_component(component.ty.clone());
197        for property_type in component.properties.iter() {
198            if !self.properties.contains_key(&property_type.name) {
199                self.add_property_by_type(&property_type);
200            }
201        }
202    }
203
204    fn remove_component(&self, ty: &ComponentTypeId) {
205        self.components.remove(ty);
206    }
207
208    fn is_a(&self, ty: &ComponentTypeId) -> bool {
209        self.components.contains(ty)
210    }
211}
212
213impl BehaviourTypesContainer for ReactiveEntity {
214    fn get_behaviours(&self) -> Vec<BehaviourTypeId> {
215        self.behaviours.iter().map(|b| b.key().clone()).collect()
216    }
217
218    fn add_behaviour(&self, ty: BehaviourTypeId) {
219        self.behaviours.insert(ty);
220    }
221
222    fn remove_behaviour(&self, ty: &BehaviourTypeId) {
223        self.behaviours.remove(ty);
224    }
225
226    fn behaves_as(&self, ty: &BehaviourTypeId) -> bool {
227        self.behaviours.contains(ty)
228    }
229}
230
231impl PropertyInstanceGetter for ReactiveEntity {
232    fn get<S: Into<String>>(&self, property_name: S) -> Option<Value> {
233        self.properties.get(&property_name.into()).map(|p| p.get())
234    }
235
236    fn as_bool<S: Into<String>>(&self, property_name: S) -> Option<bool> {
237        self.properties.get(&property_name.into()).and_then(|p| p.as_bool())
238    }
239
240    fn as_u64<S: Into<String>>(&self, property_name: S) -> Option<u64> {
241        self.properties.get(&property_name.into()).and_then(|p| p.as_u64())
242    }
243
244    fn as_i64<S: Into<String>>(&self, property_name: S) -> Option<i64> {
245        self.properties.get(&property_name.into()).and_then(|p| p.as_i64())
246    }
247
248    fn as_f64<S: Into<String>>(&self, property_name: S) -> Option<f64> {
249        self.properties.get(&property_name.into()).and_then(|p| p.as_f64())
250    }
251
252    fn as_string<S: Into<String>>(&self, property_name: S) -> Option<String> {
253        self.properties.get(&property_name.into()).and_then(|p| p.as_string())
254    }
255
256    fn as_array<S: Into<String>>(&self, property_name: S) -> Option<Vec<Value>> {
257        self.properties.get(&property_name.into()).and_then(|p| p.as_array())
258    }
259
260    fn as_object<S: Into<String>>(&self, property_name: S) -> Option<Map<String, Value>> {
261        self.properties.get(&property_name.into()).and_then(|p| p.as_object())
262    }
263}
264
265impl PropertyInstanceSetter for ReactiveEntity {
266    fn set_checked<S: Into<String>>(&self, property_name: S, value: Value) {
267        if let Some(instance) = self.properties.get(&property_name.into()) {
268            instance.set_checked(value);
269        }
270    }
271
272    fn set<S: Into<String>>(&self, property_name: S, value: Value) {
273        if let Some(instance) = self.properties.get(&property_name.into()) {
274            instance.set(value);
275        }
276    }
277
278    fn set_no_propagate_checked<S: Into<String>>(&self, property_name: S, value: Value) {
279        if let Some(instance) = self.properties.get(&property_name.into()) {
280            instance.set_no_propagate_checked(value);
281        }
282    }
283
284    fn set_no_propagate<S: Into<String>>(&self, property_name: S, value: Value) {
285        if let Some(instance) = self.properties.get(&property_name.into()) {
286            instance.set_no_propagate(value);
287        }
288    }
289
290    fn mutability<S: Into<String>>(&self, property_name: S) -> Option<Mutability> {
291        self.properties.get(&property_name.into()).map(|p| p.value().mutability)
292    }
293
294    fn set_mutability<S: Into<String>>(&self, property_name: S, mutability: Mutability) {
295        if let Some(mut property_instance) = self.properties.get_mut(&property_name.into()) {
296            property_instance.set_mutability(mutability);
297        }
298    }
299
300    // TODO: fn set(&self, Map<String, Value>
301    // TODO: Set values transactional: first set all values internally, then send all affected streams
302}
303
304impl NamespacedTypeGetter for ReactiveEntity {
305    fn namespace(&self) -> String {
306        self.ty.namespace()
307    }
308
309    fn type_name(&self) -> String {
310        self.ty.type_name()
311    }
312}
313
314impl TypeDefinitionGetter for ReactiveEntity {
315    fn type_definition(&self) -> TypeDefinition {
316        self.ty.type_definition()
317    }
318}
319
320impl TypeDefinitionGetter for &ReactiveEntity {
321    fn type_definition(&self) -> TypeDefinition {
322        self.ty.type_definition()
323    }
324}
325
326impl Display for ReactiveEntity {
327    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
328        write!(f, "{}__{}", &self.ty, self.id)
329    }
330}
331
332impl From<ReactiveEntity> for EntityInstance {
333    fn from(entity: ReactiveEntity) -> Self {
334        EntityInstance {
335            ty: entity.ty.clone(),
336            id: entity.id,
337            name: entity.name.clone(),
338            description: entity.description.clone(),
339            properties: PropertyInstances::from(&entity.properties),
340            components: entity.components.clone(),
341            extensions: Extensions::new(),
342        }
343    }
344}
345
346impl From<&ReactiveEntity> for EntityInstance {
347    fn from(entity: &ReactiveEntity) -> Self {
348        EntityInstance {
349            ty: entity.ty.clone(),
350            id: entity.id,
351            name: entity.name.clone(),
352            description: entity.description.clone(),
353            properties: PropertyInstances::from(&entity.properties),
354            components: entity.components.clone(),
355            extensions: Extensions::new(),
356        }
357    }
358}
359
360impl From<ReactiveEntityInstance> for ReactiveEntity {
361    fn from(reactive_entity: ReactiveEntityInstance) -> Self {
362        ReactiveEntity(Arc::new(reactive_entity))
363    }
364}
365
366impl From<EntityInstance> for ReactiveEntity {
367    fn from(instance: EntityInstance) -> Self {
368        let properties: ReactiveProperties<Uuid> = instance
369            .properties
370            .iter()
371            .map(|property| ReactiveProperty::new(instance.id, property.key(), Mutable, property.value().clone()))
372            .collect();
373
374        let entity_instance = ReactiveEntityInstance {
375            ty: instance.ty.clone(),
376            id: instance.id,
377            name: instance.name.clone(),
378            description: instance.description,
379            properties,
380            components: ComponentTypeIds::new(),
381            behaviours: BehaviourTypeIds::new(),
382        };
383        entity_instance.into()
384    }
385}
386
387impl Serialize for ReactiveEntity {
388    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
389    where
390        S: Serializer,
391    {
392        let property_instances = PropertyInstances::from(&self.properties);
393        property_instances.insert("$id".to_string(), JsonSchemaId::from(&self).into());
394        property_instances.insert("id".to_string(), Value::String(self.id.to_string()));
395        serializer.collect_map(property_instances)
396    }
397}