reactive_graph_graph/instances/properties/
property_instance.rs1use std::collections::BTreeMap;
2use std::hash::Hash;
3use std::hash::Hasher;
4use std::ops::Deref;
5use std::ops::DerefMut;
6
7use dashmap::DashMap;
8use dashmap::DashSet;
9use schemars::JsonSchema;
10use schemars::Schema;
11use schemars::SchemaGenerator;
12use schemars::json_schema;
13use serde::Deserialize;
14use serde::Serialize;
15use serde_json::Map;
16use serde_json::Value;
17use std::borrow::Cow;
18
19use crate::HashableValue;
20use crate::MutablePropertyInstanceSetter;
21use crate::PropertyInstanceGetter;
22use crate::PropertyTypes;
23
24pub struct ContainerPropertyInstance<IdType: Clone> {
25 pub id: IdType,
27
28 pub name: String,
30
31 pub value: Value,
33}
34
35impl<IdType: Clone> ContainerPropertyInstance<IdType> {
36 pub fn new<N: Into<String>>(id: IdType, name: N, value: Value) -> Self {
37 ContainerPropertyInstance { id, name: name.into(), value }
38 }
39}
40
41pub type PropertyNames = DashSet<String>;
42
43#[derive(Clone, Debug, Default, Serialize, Deserialize)]
46pub struct PropertyInstances(DashMap<String, Value>);
47
48impl PropertyInstances {
49 pub fn new() -> Self {
51 PropertyInstances(DashMap::new())
52 }
53
54 pub fn new_from_property_types_with_defaults(property_types: &PropertyTypes) -> Self {
57 let properties = Self::new();
58 for property_type in property_types.iter() {
59 properties.insert(property_type.key().clone(), property_type.data_type.default_value());
60 }
61 properties
62 }
63
64 pub fn property<N: Into<String>, V: Into<Value>>(self, name: N, value: V) -> Self {
67 self.insert(name.into(), value.into());
68 self
69 }
70
71 pub fn names(&self) -> PropertyNames {
73 self.iter().map(|property| property.key().clone()).collect()
74 }
75
76 pub fn to_map(&self) -> BTreeMap<String, Value> {
80 self.0.iter().map(|property| (property.key().clone(), property.value().clone())).collect()
81 }
85}
86
87impl PropertyInstanceGetter for PropertyInstances {
88 fn get<S: Into<String>>(&self, property_name: S) -> Option<Value> {
89 self.0.get(&property_name.into()).map(|property| property.value().clone())
90 }
91
92 fn as_bool<S: Into<String>>(&self, property_name: S) -> Option<bool> {
93 self.0.get(&property_name.into()).and_then(|p| p.as_bool())
94 }
95
96 fn as_u64<S: Into<String>>(&self, property_name: S) -> Option<u64> {
97 self.0.get(&property_name.into()).and_then(|p| p.as_u64())
98 }
99
100 fn as_i64<S: Into<String>>(&self, property_name: S) -> Option<i64> {
101 self.0.get(&property_name.into()).and_then(|p| p.as_i64())
102 }
103
104 fn as_f64<S: Into<String>>(&self, property_name: S) -> Option<f64> {
105 self.0.get(&property_name.into()).and_then(|p| p.as_f64())
106 }
107
108 fn as_string<S: Into<String>>(&self, property_name: S) -> Option<String> {
109 self.0.get(&property_name.into()).and_then(|p| p.as_str().map(|s| s.to_string()))
110 }
111
112 fn as_array<S: Into<String>>(&self, property_name: S) -> Option<Vec<Value>> {
113 self.0.get(&property_name.into()).and_then(|p| p.as_array().cloned())
114 }
115
116 fn as_object<S: Into<String>>(&self, property_name: S) -> Option<Map<String, Value>> {
117 self.0.get(&property_name.into()).and_then(|p| p.as_object().cloned())
118 }
119}
120
121impl MutablePropertyInstanceSetter for PropertyInstances {
122 fn set<S: Into<String>>(&mut self, property_name: S, value: Value) {
123 if let Some(mut property_value) = self.0.get_mut(&property_name.into()) {
124 let v = property_value.value_mut();
125 *v = value;
126 }
127 }
128}
129
130impl Deref for PropertyInstances {
131 type Target = DashMap<String, Value>;
132
133 fn deref(&self) -> &Self::Target {
134 &self.0
135 }
136}
137
138impl DerefMut for PropertyInstances {
139 fn deref_mut(&mut self) -> &mut Self::Target {
140 &mut self.0
141 }
142}
143
144impl IntoIterator for PropertyInstances {
145 type Item = (String, Value);
146 type IntoIter = dashmap::iter::OwningIter<String, Value>;
147 fn into_iter(self) -> Self::IntoIter {
148 self.0.into_iter()
149 }
150}
151
152impl PartialEq for PropertyInstances {
153 fn eq(&self, other: &Self) -> bool {
154 let this = self.to_map();
155 let other = other.to_map();
156 this.eq(&other)
157 }
158}
159
160impl Eq for PropertyInstances {}
161
162impl Hash for PropertyInstances {
163 fn hash<H: Hasher>(&self, hasher: &mut H) {
164 self.iter().for_each(|property| {
165 property.key().hash(hasher);
166 HashableValue(property.value()).hash(hasher);
167 });
168 }
169}
170
171impl JsonSchema for PropertyInstances {
172 fn schema_name() -> Cow<'static, str> {
173 "PropertyInstances".into()
174 }
175
176 fn json_schema(_: &mut SchemaGenerator) -> Schema {
177 json_schema!({
178 "type": "object",
179 "description": "Properties",
180 })
181 }
182}
183
184impl From<BTreeMap<String, Value>> for PropertyInstances {
197 fn from(tys: BTreeMap<String, Value>) -> Self {
198 PropertyInstances(tys.into_iter().collect())
199 }
200}
201
202impl From<PropertyInstances> for BTreeMap<String, Value> {
203 fn from(tys: PropertyInstances) -> Self {
204 tys.to_map()
205 }
206}
207
208impl From<&PropertyInstances> for BTreeMap<String, Value> {
209 fn from(tys: &PropertyInstances) -> Self {
210 tys.0.iter().map(|ty| (ty.key().clone(), ty.value().clone())).collect()
211 }
212}
213
214impl From<DashMap<String, Value>> for PropertyInstances {
215 fn from(tys: DashMap<String, Value>) -> Self {
216 PropertyInstances(tys)
217 }
218}
219
220impl From<&DashMap<String, Value>> for PropertyInstances {
221 fn from(tys: &DashMap<String, Value>) -> Self {
222 PropertyInstances(tys.clone())
223 }
224}
225
226impl From<PropertyInstances> for DashMap<String, Value> {
227 fn from(tys: PropertyInstances) -> Self {
228 tys.0
229 }
230}
231
232impl FromIterator<(String, Value)> for PropertyInstances {
239 fn from_iter<I: IntoIterator<Item = (String, Value)>>(iter: I) -> Self {
240 let properties = PropertyInstances::new();
241 for (property_name, property_value) in iter {
242 properties.insert(property_name, property_value);
243 }
244 properties
245 }
246}
247
248#[cfg(any(test, feature = "test"))]
249use crate::test_utils::default_from::DefaultFrom;
250#[cfg(any(test, feature = "test"))]
251use default_test::DefaultTest;
252#[cfg(any(test, feature = "test"))]
253use rand::Rng;
254#[cfg(any(test, feature = "test"))]
255use reactive_graph_utils_test::r_string;
256#[cfg(any(test, feature = "test"))]
257use serde_json::json;
258
259#[cfg(any(test, feature = "test"))]
260impl DefaultTest for PropertyInstances {
261 fn default_test() -> Self {
262 let property_instances = PropertyInstances::new();
263 let mut rng = rand::rng();
264 for _ in 0..rng.random_range(0..10) {
265 property_instances.insert(r_string(), json!(r_string()));
266 }
267 property_instances
268 }
269}
270
271#[cfg(any(test, feature = "test"))]
272impl DefaultFrom<PropertyTypes> for PropertyInstances {
273 fn default_from(property_types: &PropertyTypes) -> Self {
274 let properties = Self::new();
275 for property_type in property_types.iter() {
276 properties.insert(property_type.key().clone(), property_type.data_type.default_value_test());
277 }
278 properties
279 }
280}
281
282#[cfg(test)]
283mod tests {
284 }