looking_glass/
instance.rs

1use crate::*;
2pub use bytes::Bytes;
3pub use smol_str::SmolStr;
4use std::collections::HashMap;
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 [`Option`]
215pub trait OptionInstance<'s>: Instance<'s> {
216    /// Returns a reference to a field in a reflected vec
217    fn value<'a>(&'a self) -> Option<Value<'a, 's>>
218    where
219        's: 'a;
220
221    /// Returns a clone of the instance in a [`Box`].
222    fn boxed_clone(&self) -> Box<dyn OptionInstance<'s> + 's>;
223
224    fn into_boxed_instance(self: Box<Self>) -> Box<dyn Instance<'s> + 's>;
225}
226
227impl<'s> std::fmt::Debug for dyn OptionInstance<'s> + 's {
228    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
229        let mut build = f.debug_tuple(&self.name());
230        if let Some(val) = self.value() {
231            build.field(&val);
232        }
233        build.finish()
234    }
235}
236
237impl<'s, T: Typed<'s> + Clone + 's> Typed<'s> for Option<T> {
238    fn ty() -> ValueTy {
239        ValueTy::Option(Box::new(T::ty()))
240    }
241
242    fn as_value<'a>(&'a self) -> Value<'a, 's>
243    where
244        's: 'a,
245    {
246        Value::from_option(self)
247    }
248}
249
250impl<'s> PartialEq for dyn OptionInstance<'s> + 's {
251    fn eq(&self, other: &Self) -> bool {
252        self.value() == other.value()
253    }
254}
255
256impl<'s> Clone for Box<dyn OptionInstance<'s> + 's> {
257    fn clone(&self) -> Self {
258        self.boxed_clone()
259    }
260}
261
262impl<'a, T: Typed<'a> + Clone + PartialEq + 'a> Instance<'a> for Vec<T> {
263    fn name(&self) -> SmolStr {
264        format!("Vec<{:?}>", T::ty()).into()
265    }
266
267    fn as_inst(&self) -> &(dyn Instance<'a> + 'a) {
268        self
269    }
270}
271
272impl<'s, T: Typed<'s> + Clone + 's + PartialEq> VecInstance<'s> for Vec<T> {
273    fn get_value<'a>(&'a self, i: usize) -> Option<Value<'a, 's>>
274    where
275        's: 'a,
276    {
277        let val = self.get(i)?.as_value();
278        Some(val)
279    }
280
281    fn values<'a>(&'a self) -> Vec<CowValue<'a, 's>>
282    where
283        's: 'a,
284    {
285        self.iter().map(|e| CowValue::Ref(e.as_value())).collect()
286    }
287
288    fn boxed_clone(&self) -> Box<dyn VecInstance<'s> + 's> {
289        Box::new(self.clone())
290    }
291
292    fn update<'a>(
293        &'a mut self,
294        update: &'a (dyn VecInstance<'s> + 's),
295        replace_repeated: bool,
296    ) -> Result<(), Error> {
297        if let Some(vec) = Value::from_vec(update).borrow::<&Vec<T>>() {
298            if replace_repeated {
299                let vec = vec.clone();
300                let _ = std::mem::replace(self as &mut Vec<T>, vec);
301            } else {
302                self.extend_from_slice(&vec[..]);
303            }
304        }
305        Ok(())
306    }
307
308    fn is_empty(&self) -> bool {
309        Vec::is_empty(self)
310    }
311
312    fn len(&self) -> usize {
313        Vec::len(self)
314    }
315
316    fn vec_eq(&self, inst: &(dyn VecInstance<'s> + 's)) -> bool {
317        inst.as_inst().downcast_ref::<Self>() == Some(self)
318    }
319
320    fn into_boxed_instance(self: Box<Self>) -> Box<dyn Instance<'s> + 's> {
321        self
322    }
323}
324
325impl<'s, T: Typed<'s> + Clone + 's + PartialEq> Typed<'s> for Vec<T> {
326    fn ty() -> ValueTy {
327        ValueTy::Vec(Box::new(T::ty()))
328    }
329
330    fn as_value<'a>(&'a self) -> Value<'a, 's>
331    where
332        's: 'a,
333    {
334        Value::from_vec(self)
335    }
336}
337
338impl<'s> Instance<'s> for String {
339    fn name(&self) -> SmolStr {
340        "String".into()
341    }
342
343    fn as_inst(&self) -> &(dyn Instance<'s> + 's) {
344        self
345    }
346}
347
348impl<'s> Instance<'s> for Bytes {
349    fn name(&self) -> SmolStr {
350        "Bytes".into()
351    }
352
353    fn as_inst(&self) -> &(dyn Instance<'s> + 's) {
354        self
355    }
356}