reactive_graph_graph/types/extensions/
extension.rs

1use std::cmp::Ordering;
2use std::hash::Hash;
3use std::hash::Hasher;
4use std::ops::Deref;
5use std::ops::DerefMut;
6
7use dashmap::DashMap;
8use dashmap::iter::OwningIter;
9#[cfg(any(test, feature = "test"))]
10use default_test::DefaultTest;
11#[cfg(any(test, feature = "test"))]
12use rand::Rng;
13use schemars::JsonSchema;
14use schemars::Schema;
15use schemars::SchemaGenerator;
16use schemars::json_schema;
17use serde::Deserialize;
18use serde::Deserializer;
19use serde::Serialize;
20use serde::Serializer;
21use serde_json::Value;
22#[cfg(any(test, feature = "test"))]
23use serde_json::json;
24use std::borrow::Cow;
25use typed_builder::TypedBuilder;
26
27use crate::AddExtensionError;
28use crate::ExtensionContainer;
29use crate::ExtensionTypeId;
30use crate::ExtensionTypeIds;
31use crate::NamespacedTypeContainer;
32use crate::NamespacedTypeGetter;
33use crate::RemoveExtensionError;
34use crate::TypeDefinition;
35use crate::TypeDefinitionGetter;
36use crate::TypeIdType;
37use crate::UpdateExtensionError;
38#[cfg(any(test, feature = "test"))]
39use reactive_graph_utils_test::r_string;
40
41/// Extension on a type. The extension allows to extend information
42#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema, TypedBuilder)]
43pub struct Extension {
44    /// The type definition contains the namespace and the type name.
45    #[serde(flatten)]
46    #[schemars(required)]
47    pub ty: ExtensionTypeId,
48
49    /// Textual description of the extension.
50    #[serde(default = "String::new")]
51    pub description: String,
52
53    /// The extension as JSON representation.
54    pub extension: Value,
55}
56
57impl Extension {
58    /// Constructs an extension from the given namespaced type with the given description, components, properties and extensions.
59    pub fn new<T: Into<ExtensionTypeId>, S: Into<String>>(ty: T, description: S, extension: Value) -> Extension {
60        Extension {
61            ty: ty.into(),
62            description: description.into(),
63            extension,
64        }
65    }
66
67    pub fn new_from_type<S: Into<String>>(namespace: S, type_name: S, description: S, extension: Value) -> Extension {
68        Extension {
69            ty: ExtensionTypeId::new_from_type(namespace, type_name),
70            description: description.into(),
71            extension,
72        }
73    }
74}
75
76impl NamespacedTypeGetter for Extension {
77    fn namespace(&self) -> String {
78        self.ty.namespace()
79    }
80
81    fn type_name(&self) -> String {
82        self.ty.type_name()
83    }
84}
85
86impl TypeDefinitionGetter for Extension {
87    fn type_definition(&self) -> TypeDefinition {
88        self.ty.type_definition()
89    }
90}
91
92impl From<&Extension> for TypeDefinition {
93    fn from(extension: &Extension) -> Self {
94        TypeDefinition {
95            type_id_type: TypeIdType::Extension,
96            namespace: extension.namespace(),
97            type_name: extension.type_name(),
98        }
99    }
100}
101
102impl PartialEq<ExtensionTypeId> for Extension {
103    fn eq(&self, ty: &ExtensionTypeId) -> bool {
104        self.ty == *ty
105    }
106}
107
108impl PartialOrd<Self> for Extension {
109    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
110        Some(self.cmp(other))
111    }
112}
113
114impl Ord for Extension {
115    fn cmp(&self, other: &Self) -> Ordering {
116        self.ty.cmp(&other.ty)
117    }
118}
119
120impl Hash for Extension {
121    fn hash<H: Hasher>(&self, state: &mut H) {
122        self.ty.hash(state);
123        self.description.hash(state);
124        // Ignore the extension content (for now)
125        // let ext_str = serde_json::to_string(&self.extension);
126        // ext_str.hash(state);
127    }
128}
129
130#[derive(Clone, Debug, Default)]
131pub struct Extensions(DashMap<ExtensionTypeId, Extension>);
132
133impl Extensions {
134    pub fn new() -> Self {
135        Extensions(DashMap::new())
136    }
137
138    pub fn extension<E: Into<Extension>>(self, extension: E) -> Self {
139        self.push(extension);
140        self
141    }
142
143    // pub fn push<E: Into<Extension>>(&self, extension: E) {
144    //     let extension = extension.into();
145    //     self.0.insert(extension.ty.clone(), extension);
146    // }
147    //
148    // // TODO: Impl templated free function
149    // // TODO: Rename to values() ?
150    // pub fn to_vec(&self) -> Vec<Extension> {
151    //     let mut extensions: Vec<Extension> = self.0.iter().map(|extension| extension.value().clone()).collect();
152    //     extensions.sort();
153    //     extensions
154    // }
155}
156
157impl ExtensionContainer for Extensions {
158    fn has_own_extension(&self, ty: &ExtensionTypeId) -> bool {
159        self.0.contains_key(ty)
160    }
161
162    fn get_own_extension(&self, ty: &ExtensionTypeId) -> Option<Extension> {
163        self.0.get(ty).map(|e| e.value().clone())
164    }
165
166    fn add_extension<E: Into<Extension>>(&self, extension: E) -> Result<ExtensionTypeId, AddExtensionError> {
167        let extension = extension.into();
168        let ty = extension.ty.clone();
169        if self.0.contains_key(&ty) {
170            return Err(AddExtensionError::ExtensionAlreadyExist(ty));
171        }
172        self.push(extension);
173        Ok(ty)
174    }
175
176    fn update_extension<T: Into<ExtensionTypeId>, E: Into<Extension>>(&self, ty: T, extension: E) -> Result<Extension, UpdateExtensionError> {
177        let ty = ty.into();
178        if !self.0.contains_key(&ty) {
179            return Err(UpdateExtensionError::ExtensionDoesNotExist(ty));
180        }
181        let _ = self.0.remove(&ty);
182        let extension = extension.into();
183        self.push(extension.clone());
184        Ok(extension)
185    }
186
187    fn remove_extension<T: Into<ExtensionTypeId>>(&self, ty: T) -> Result<Extension, RemoveExtensionError> {
188        let ty = ty.into();
189        self.0
190            .remove(&ty)
191            .map(|(_, extension)| extension)
192            .ok_or(RemoveExtensionError::ExtensionDoesNotExist(ty))
193    }
194
195    fn merge_extensions<E: Into<Extensions>>(&mut self, extensions_to_merge: E) {
196        let extensions_to_merge = extensions_to_merge.into();
197        for (ty, extension_to_merge) in extensions_to_merge {
198            if !self.0.contains_key(&ty) {
199                self.push(extension_to_merge);
200            } else if let Some(mut existing_extension) = self.0.get_mut(&ty) {
201                existing_extension.description = extension_to_merge.description.clone();
202                existing_extension.extension = extension_to_merge.extension.clone();
203            }
204        }
205    }
206}
207
208impl NamespacedTypeContainer for Extensions {
209    type TypeId = ExtensionTypeId;
210    type TypeIds = ExtensionTypeIds;
211    type Type = Extension;
212
213    fn new() -> Self {
214        Self(DashMap::new())
215    }
216
217    fn push<E: Into<Extension>>(&self, extension: E) {
218        let extension = extension.into();
219        self.insert(extension.ty.clone(), extension);
220    }
221}
222
223impl Deref for Extensions {
224    type Target = DashMap<ExtensionTypeId, Extension>;
225
226    fn deref(&self) -> &Self::Target {
227        &self.0
228    }
229}
230
231impl DerefMut for Extensions {
232    fn deref_mut(&mut self) -> &mut Self::Target {
233        &mut self.0
234    }
235}
236
237impl IntoIterator for Extensions {
238    type Item = (ExtensionTypeId, Extension);
239    type IntoIter = OwningIter<ExtensionTypeId, Extension>;
240
241    fn into_iter(self) -> Self::IntoIter {
242        self.0.into_iter()
243    }
244}
245
246impl PartialEq for Extensions {
247    fn eq(&self, other: &Self) -> bool {
248        self.iter().all(|self_extension| {
249            other
250                .get(self_extension.key())
251                .filter(|other_extension| other_extension.value() == self_extension.value())
252                .is_some()
253        }) && other.iter().all(|other_extension| {
254            self.get(other_extension.key())
255                .filter(|self_extension| self_extension.value() == other_extension.value())
256                .is_some()
257        })
258    }
259}
260
261impl Eq for Extensions {}
262
263impl Hash for Extensions {
264    fn hash<H: Hasher>(&self, hasher: &mut H) {
265        self.to_vec().iter().for_each(|extension| {
266            // extension.name.hash(hasher);
267            extension.hash(hasher);
268            // TODO: hash extension.extension
269        });
270    }
271}
272
273impl Serialize for Extensions {
274    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
275    where
276        S: Serializer,
277    {
278        serializer.collect_seq(self.iter())
279    }
280}
281
282impl<'de> Deserialize<'de> for Extensions {
283    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
284    where
285        D: Deserializer<'de>,
286    {
287        Ok(Vec::<Extension>::deserialize(deserializer)?.into())
288    }
289}
290
291impl JsonSchema for Extensions {
292    fn schema_name() -> Cow<'static, str> {
293        "Extensions".into()
294    }
295
296    fn json_schema(schema_generator: &mut SchemaGenerator) -> Schema {
297        let sub_schema: Schema = schema_generator.subschema_for::<Extension>();
298        json_schema!({
299            "type": "array",
300            "items": sub_schema,
301            "description": "Extensions",
302        })
303    }
304}
305
306impl From<Vec<Extension>> for Extensions {
307    fn from(extensions: Vec<Extension>) -> Self {
308        extensions.into_iter().collect()
309    }
310}
311
312impl From<Extensions> for Vec<Extension> {
313    fn from(extensions: Extensions) -> Self {
314        extensions.into_iter().map(|(_, extension)| extension).collect()
315    }
316}
317
318impl FromIterator<Extension> for Extensions {
319    fn from_iter<I: IntoIterator<Item = Extension>>(iter: I) -> Self {
320        let extensions = Extensions::new();
321        for extension in iter {
322            extensions.push(extension);
323        }
324        extensions
325    }
326}
327
328#[cfg(any(test, feature = "test"))]
329impl DefaultTest for Extension {
330    fn default_test() -> Self {
331        Extension::builder()
332            .ty(ExtensionTypeId::generate_random())
333            .description(r_string())
334            .extension(json!(r_string()))
335            .build()
336    }
337}
338
339#[cfg(any(test, feature = "test"))]
340impl DefaultTest for Extensions {
341    fn default_test() -> Self {
342        let extensions = Extensions::new();
343        let mut rng = rand::rng();
344        for _ in 0..rng.random_range(0..10) {
345            extensions.push(Extension::default_test());
346        }
347        extensions
348    }
349}
350
351#[cfg(test)]
352mod tests {
353    use schemars::schema_for;
354
355    use crate::Extension;
356
357    #[test]
358    fn extension_json_schema() {
359        let schema = schema_for!(Extension);
360        println!("{}", serde_json::to_string_pretty(&schema).unwrap());
361    }
362}