reactive_graph_reactive_model_impl/entities/
reactive_entity.rs1use 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 #[builder(setter(into))]
49 pub ty: EntityTypeId,
50
51 #[builder(default=Uuid::new_v4())]
53 pub id: Uuid,
54
55 #[builder(default, setter(into))]
57 pub name: String,
58
59 #[builder(default, setter(into))]
61 pub description: String,
62
63 #[builder(default, setter(into))]
65 pub properties: ReactiveProperties<Uuid>,
66
67 #[builder(default, setter(into))]
69 pub components: ComponentTypeIds,
70
71 #[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 #[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 }
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 }
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}