reactive_graph_graph/types/extensions/
extension.rs1use 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#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema, TypedBuilder)]
43pub struct Extension {
44 #[serde(flatten)]
46 #[schemars(required)]
47 pub ty: ExtensionTypeId,
48
49 #[serde(default = "String::new")]
51 pub description: String,
52
53 pub extension: Value,
55}
56
57impl Extension {
58 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 }
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 }
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.hash(hasher);
268 });
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}