Skip to main content

looking_glass/
instance.rs

1use crate::*;
2pub use bytes::Bytes;
3pub use smol_str::SmolStr;
4use std::{collections::HashMap, fmt::Debug, hash::BuildHasher};
5
6/// Any reflected type
7pub trait Instance<'ty>: TypedObj + Send + Sync {
8    /// Returns the name of a instance
9    fn name(&self) -> SmolStr;
10
11    fn as_inst(&self) -> &(dyn Instance<'ty> + 'ty);
12}
13
14impl<'ty> dyn Instance<'ty> + 'ty {
15    /// Downcasts to a concere type
16    #[inline]
17    pub fn downcast_ref<'val, 't, T: Typed<'ty> + 'ty>(&'val self) -> Option<&'val T>
18    where
19        'ty: 'val,
20    {
21        if self.inst_ty() == T::ty() {
22            // Safety: This is essentially a copy from `Any` and follows much the same logic.
23            // The major difference is that we allow non-static casts.
24            // The above check makes sure that the lifetime erased type T, and Self are the same.
25            // However that does not ensure that the lifetimes match.
26            // We ensure that saftey through the lifetime bounds. The lifetime bound `T: 'ty`
27            // ensures that we only ever give out a lifetime that 'val (the lifetime of the parent struct) out lives.
28            // Which is equivalent to a safe Rust cast (&'a () as &'b () where 'a: 'b).
29            Some(unsafe { &*(self as *const dyn Instance<'ty> as *const T) })
30        } else {
31            None
32        }
33    }
34}
35
36/// A extension trait that provides downcasting
37pub trait DowncastExt<'ty> {
38    /// Downcasts to a boxed concrete type
39    fn downcast<T: Typed<'ty> + 'ty>(self) -> Option<Box<T>>;
40}
41impl<'ty> DowncastExt<'ty> for Box<dyn Instance<'ty> + 'ty> {
42    fn downcast<T: Typed<'ty> + 'ty>(self) -> Option<Box<T>> {
43        if self.inst_ty() == T::ty() {
44            unsafe {
45                // Safety: This is also a copy from `Any`, and its lifetime saftey is guarenteed in
46                // same way as [`Instance::downcast_ref`]
47                let raw: *mut (dyn Instance<'ty> + 'ty) = Box::into_raw(self);
48                Some(Box::from_raw(raw as *mut T))
49            }
50        } else {
51            None
52        }
53    }
54}
55
56/// A reflected struct
57pub trait StructInstance<'s>: Instance<'s> {
58    /// Returns a reference to a field in a struct
59    fn get_value<'a>(&'a self, field: &str) -> Option<CowValue<'a, 's>>
60    where
61        's: 'a;
62
63    /// Updates an instance based on the instance passed in. If a field mask is specified only the fields passed with the mask will be updated.
64    fn update<'a>(
65        &'a mut self,
66        update: &'a (dyn StructInstance<'s> + 's),
67        field_mask: Option<&FieldMask>,
68        replace_repeated: bool,
69    ) -> Result<(), Error>;
70
71    /// Returns a HashMap containing all the attributes of the instance.
72    fn values<'a>(&'a self) -> HashMap<SmolStr, CowValue<'a, 's>>;
73
74    /// Returns a clone of the instance in a [`Box`].
75    fn boxed_clone(&self) -> Box<dyn StructInstance<'s> + 's>;
76
77    /// Casts `Self` to a `Box<dyn Instance>`
78    fn into_boxed_instance(self: Box<Self>) -> Box<dyn Instance<'s> + 's>;
79}
80
81impl<'s> std::fmt::Debug for dyn StructInstance<'s> + 's {
82    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
83        let mut builder = f.debug_struct(&self.name());
84        for (name, val) in self.values() {
85            builder.field(&name, &val);
86        }
87        builder.finish()
88    }
89}
90
91impl<'s> PartialEq for dyn StructInstance<'s> + 's {
92    fn eq(&self, other: &Self) -> bool {
93        self.values() == other.values()
94    }
95}
96
97impl<'s> Clone for Box<dyn StructInstance<'s> + 's> {
98    fn clone(&self) -> Self {
99        self.boxed_clone()
100    }
101}
102
103/// A reflected enum
104pub trait EnumInstance<'s>: Instance<'s> {
105    /// Returns a clone of the instance in a [`Box`].
106    fn boxed_clone(&self) -> Box<dyn EnumInstance<'s> + 's>;
107    /// Returns the current value of the reflected enum.
108    fn field<'a>(&'a self) -> EnumField<'a, 's>
109    where
110        's: 'a;
111
112    fn into_boxed_instance(self: Box<Self>) -> Box<dyn Instance<'s>>;
113}
114
115/// A reflected field of an enum
116#[derive(PartialEq, Clone, Debug)]
117pub enum EnumField<'a, 's> {
118    Unit(SmolStr),
119    Tuple {
120        name: SmolStr,
121        fields: Vec<CowValue<'a, 's>>,
122    },
123    Struct {
124        name: SmolStr,
125        fields: HashMap<SmolStr, CowValue<'a, 's>>,
126    },
127}
128
129impl<'s> PartialEq for dyn EnumInstance<'s> + 's {
130    fn eq(&self, other: &Self) -> bool {
131        self.field() == other.field()
132    }
133}
134
135impl<'s> std::fmt::Debug for dyn EnumInstance<'s> + 's {
136    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
137        match self.field() {
138            EnumField::Unit(name) => f.write_str(name.as_str()),
139            EnumField::Tuple { name, fields } => {
140                let mut tuple = f.debug_tuple(name.as_str());
141                for field in fields {
142                    tuple.field(&field);
143                }
144                tuple.finish()
145            }
146            EnumField::Struct { name, fields } => {
147                let mut s = f.debug_struct(&name);
148                for (name, field) in fields {
149                    s.field(&name, &field);
150                }
151                s.finish()
152            }
153        }
154    }
155}
156
157impl<'s> Clone for Box<dyn EnumInstance<'s> + 's> {
158    fn clone(&self) -> Self {
159        self.boxed_clone()
160    }
161}
162
163/// A reflected [`Vec`]
164pub trait VecInstance<'s>: Instance<'s> + 's {
165    /// Returns a reference to a field in a reflected vec
166    fn get_value<'a>(&'a self, i: usize) -> Option<Value<'a, 's>>
167    where
168        's: 'a;
169
170    /// Returns a Vec containing all the attributes of the instance.
171    fn values<'a>(&'a self) -> Vec<CowValue<'a, 's>>
172    where
173        's: 'a;
174
175    /// Returns a clone of the instance in a [`Box`].
176    fn boxed_clone(&self) -> Box<dyn VecInstance<'s> + 's>;
177
178    /// Updates an instance based on the instance passed in. If a field mask is specified only the fields passed with the mask will be updated.
179    fn update<'a>(
180        &'a mut self,
181        update: &'a (dyn VecInstance<'s> + 's),
182        replace_repeated: bool,
183    ) -> Result<(), Error>;
184
185    /// Returns whether the vec is empty
186    fn is_empty(&self) -> bool;
187
188    /// Returns whether the length of the vec;
189    fn len(&self) -> usize;
190
191    fn vec_eq(&self, inst: &(dyn VecInstance<'s> + 's)) -> bool;
192
193    fn into_boxed_instance(self: Box<Self>) -> Box<dyn Instance<'s> + 's>;
194}
195
196impl<'s> std::fmt::Debug for dyn VecInstance<'s> {
197    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
198        f.debug_list().entries(self.values().iter()).finish()
199    }
200}
201
202impl<'s> PartialEq for dyn VecInstance<'s> + 's {
203    fn eq(&self, other: &Self) -> bool {
204        self.vec_eq(other)
205    }
206}
207
208impl<'s> Clone for Box<dyn VecInstance<'s> + 's> {
209    fn clone(&self) -> Self {
210        self.boxed_clone()
211    }
212}
213
214/// A reflected [`HashMap`]
215pub trait HashMapInstance<'s>: Instance<'s> + 's {
216    fn get_value<'a>(&'a self, key: &str) -> Option<Value<'a, 's>>
217    where
218        's: 'a;
219
220    fn is_empty(&self) -> bool;
221
222    fn len(&self) -> usize;
223
224    /// Returns a clone of the instance in a [`Box`].
225    fn boxed_clone(&self) -> Box<dyn HashMapInstance<'s> + 's>;
226
227    /// Updates an instance based on the instance passed in. If a field mask is specified only the fields passed with the mask will be updated.
228    fn update<'a>(
229        &'a mut self,
230        update: &'a (dyn HashMapInstance<'s> + 's),
231        field_mask: Option<&FieldMask>,
232        replace_repeated: bool,
233    ) -> Result<(), Error>;
234
235    /// Returns a HashMap containing all the attributes of the instance.
236    fn values<'a>(&'a self) -> HashMap<String, CowValue<'a, 's>>
237    where
238        's: 'a;
239
240    fn hashmap_eq(&self, inst: &(dyn HashMapInstance<'s> + 's)) -> bool;
241
242    fn contains(&self, sub_inst: &(dyn HashMapInstance<'s> + 's)) -> bool {
243        sub_inst.values().into_iter().all(|(k, v)| {
244            self.get_value(&k).map_or(false, |sv| v.as_ref().slow_eq(&sv))
245        })
246    }
247
248    fn into_boxed_instance(self: Box<Self>) -> Box<dyn Instance<'s> + 's>;
249}
250
251impl<'s> std::fmt::Debug for dyn HashMapInstance<'s> + 's {
252    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
253        let mut builder = f.debug_map();
254        for (k, v) in self.values() {
255            builder.entry(&k, &v);
256        }
257        builder.finish()
258    }
259}
260
261impl<'s> PartialEq for dyn HashMapInstance<'s> + 's {
262    fn eq(&self, other: &Self) -> bool {
263        self.hashmap_eq(other)
264    }
265}
266
267impl<'s> Clone for Box<dyn HashMapInstance<'s> + 's> {
268    fn clone(&self) -> Self {
269        self.boxed_clone()
270    }
271}
272
273/// A reflected [`Option`]
274pub trait OptionInstance<'s>: Instance<'s> {
275    /// Returns a reference to a field in a reflected vec
276    fn value<'a>(&'a self) -> Option<Value<'a, 's>>
277    where
278        's: 'a;
279
280    /// Returns a clone of the instance in a [`Box`].
281    fn boxed_clone(&self) -> Box<dyn OptionInstance<'s> + 's>;
282
283    fn into_boxed_instance(self: Box<Self>) -> Box<dyn Instance<'s> + 's>;
284}
285
286impl<'s> std::fmt::Debug for dyn OptionInstance<'s> + 's {
287    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
288        let mut build = f.debug_tuple(&self.name());
289        if let Some(val) = self.value() {
290            build.field(&val);
291        }
292        build.finish()
293    }
294}
295
296impl<'s, T: Typed<'s> + Clone + 's> Typed<'s> for Option<T> {
297    fn ty() -> ValueTy {
298        ValueTy::Option(Box::new(T::ty()))
299    }
300
301    fn as_value<'a>(&'a self) -> Value<'a, 's>
302    where
303        's: 'a,
304    {
305        Value::from_option(self)
306    }
307}
308
309impl<'s> PartialEq for dyn OptionInstance<'s> + 's {
310    fn eq(&self, other: &Self) -> bool {
311        self.value() == other.value()
312    }
313}
314
315impl<'s> Clone for Box<dyn OptionInstance<'s> + 's> {
316    fn clone(&self) -> Self {
317        self.boxed_clone()
318    }
319}
320
321impl<'a, T: Typed<'a> + Clone + PartialEq + 'a> Instance<'a> for Vec<T> {
322    fn name(&self) -> SmolStr {
323        format!("Vec<{:?}>", T::ty()).into()
324    }
325
326    fn as_inst(&self) -> &(dyn Instance<'a> + 'a) {
327        self
328    }
329}
330
331impl<'s, T: Typed<'s> + Clone + 's + PartialEq> VecInstance<'s> for Vec<T> {
332    fn get_value<'a>(&'a self, i: usize) -> Option<Value<'a, 's>>
333    where
334        's: 'a,
335    {
336        let val = self.get(i)?.as_value();
337        Some(val)
338    }
339
340    fn values<'a>(&'a self) -> Vec<CowValue<'a, 's>>
341    where
342        's: 'a,
343    {
344        self.iter().map(|e| CowValue::Ref(e.as_value())).collect()
345    }
346
347    fn boxed_clone(&self) -> Box<dyn VecInstance<'s> + 's> {
348        Box::new(self.clone())
349    }
350
351    fn update<'a>(
352        &'a mut self,
353        update: &'a (dyn VecInstance<'s> + 's),
354        replace_repeated: bool,
355    ) -> Result<(), Error> {
356        if let Some(vec) = Value::from_vec(update).borrow::<&Vec<T>>() {
357            if replace_repeated {
358                let vec = vec.clone();
359                let _ = std::mem::replace(self as &mut Vec<T>, vec);
360            } else {
361                self.extend_from_slice(&vec[..]);
362            }
363        }
364        Ok(())
365    }
366
367    fn is_empty(&self) -> bool {
368        Vec::is_empty(self)
369    }
370
371    fn len(&self) -> usize {
372        Vec::len(self)
373    }
374
375    fn vec_eq(&self, inst: &(dyn VecInstance<'s> + 's)) -> bool {
376        inst.as_inst().downcast_ref::<Self>() == Some(self)
377    }
378
379    fn into_boxed_instance(self: Box<Self>) -> Box<dyn Instance<'s> + 's> {
380        self
381    }
382}
383
384impl<'s, T: Typed<'s> + Clone + 's + PartialEq> Typed<'s> for Vec<T> {
385    fn ty() -> ValueTy {
386        ValueTy::Vec(Box::new(T::ty()))
387    }
388
389    fn as_value<'a>(&'a self) -> Value<'a, 's>
390    where
391        's: 'a,
392    {
393        Value::from_vec(self)
394    }
395}
396
397impl<'s, T> Instance<'s> for HashMap<String, T>
398where
399    T: Typed<'s> + Clone + 's + PartialEq,
400{
401    fn name(&self) -> SmolStr {
402        format!("HashMap<String, {:?}>", T::ty()).into() 
403    }
404
405    fn as_inst(&self) -> &(dyn Instance<'s> + 's) {
406        self
407    }
408}
409
410impl<'s, T> HashMapInstance<'s> for HashMap<String, T>
411where
412    T: Typed<'s> + Clone + 's + PartialEq,
413{
414    fn get_value<'a>(&'a self, key: &str) -> Option<Value<'a, 's>>
415    where
416        's: 'a,
417    {
418        let val = self.get(key)?.as_value();
419        Some(val)
420    }
421
422    fn update<'a>(
423        &'a mut self,
424        update: &'a (dyn HashMapInstance<'s> + 's),
425        field_mask: Option<&FieldMask>,
426        replace_repeated: bool,
427    ) -> Result<(), Error> {
428        if let Some(map) = Value::from_hashmap(update).borrow::<&HashMap<String, T>>() {
429            match (replace_repeated, field_mask) {
430                (true, None) => {
431                    let _ = std::mem::replace(self as &mut HashMap<String, T>, map.clone());
432                }
433                (true, Some(mask)) => {
434                    let masked_keys_to_remove: Vec<String> = self
435                        .keys()
436                        .filter(|k| {
437                            let in_mask = mask.child(&SmolStr::new(k.as_str())).is_some();
438                            let in_update = map.contains_key(k.as_str());
439                            in_mask && !in_update
440                        })
441                        .cloned()
442                        .collect();
443                    for key in masked_keys_to_remove {
444                        self.remove(&key);
445                    }
446                    for (key, value) in map.iter() {
447                        if mask.child(&SmolStr::new(key.as_str())).is_some() {
448                            self.insert(key.clone(), value.clone());
449                        }
450                    }
451                }
452                (false, None) => {
453                    for (key, value) in map.iter() {
454                        self.insert(key.clone(), value.clone());
455                    }
456                }
457                (false, Some(mask)) => {
458                    for (key, value) in map.iter() {
459                        if mask.child(&SmolStr::new(key.as_str())).is_some() {
460                            self.insert(key.clone(), value.clone());
461                        }
462                    }
463                }
464            }
465        }
466        Ok(())
467    }
468
469    fn values<'a>(&'a self) -> HashMap<String, CowValue<'a, 's>>
470    where
471        's: 'a,
472    {
473        self.iter()
474            .map(|(k, v)| {
475                let key_str = k.clone(); 
476                let cow_val = CowValue::Ref(v.as_value());
477                (key_str, cow_val)
478            })
479            .collect()
480    }
481
482    fn boxed_clone(&self) -> Box<dyn HashMapInstance<'s> + 's> {
483        Box::new(self.clone())
484    }
485
486    fn is_empty(&self) -> bool {
487        HashMap::is_empty(self)
488    }
489
490    fn len(&self) -> usize {
491        HashMap::len(self)
492    }
493
494    fn hashmap_eq(&self, inst: &(dyn HashMapInstance<'s> + 's)) -> bool {
495        inst.as_inst().downcast_ref::<Self>() == Some(self)
496    }
497
498    fn contains(&self, sub_inst: &(dyn HashMapInstance<'s> + 's)) -> bool {
499        if let Some(other) = sub_inst.as_inst().downcast_ref::<Self>() {
500            return other.iter().all(|(k, v)| self.get(k) == Some(v));
501        }
502
503        sub_inst.values().into_iter().all(|(field, sub_inst_value)| {
504            self.get(&field)
505                .map_or(false, |self_value| sub_inst_value.as_ref().slow_eq(&self_value.as_value()))
506        })
507    }
508        
509    fn into_boxed_instance(self: Box<Self>) -> Box<dyn Instance<'s> + 's> {
510        self
511    }
512}
513
514impl<'s, T> Typed<'s> for HashMap<String, T>
515where
516    T: Typed<'s> + Clone + 's + PartialEq,
517{
518    fn ty() -> ValueTy {
519        ValueTy::HashMap(Box::new(T::ty()))
520    }
521
522    fn as_value<'a>(&'a self) -> Value<'a, 's>
523    where
524        's: 'a,
525    {
526        Value::from_hashmap(self)
527    }
528}
529
530impl<'s> Instance<'s> for String {
531    fn name(&self) -> SmolStr {
532        "String".into()
533    }
534
535    fn as_inst(&self) -> &(dyn Instance<'s> + 's) {
536        self
537    }
538}
539
540impl<'s> Instance<'s> for Bytes {
541    fn name(&self) -> SmolStr {
542        "Bytes".into()
543    }
544
545    fn as_inst(&self) -> &(dyn Instance<'s> + 's) {
546        self
547    }
548}