relay_protocol/
traits.rs

1use std::collections::BTreeMap;
2use std::fmt::Debug;
3
4use crate::annotated::{Annotated, MetaMap, MetaTree};
5use crate::value::{Object, Val, Value};
6
7/// A value that can be empty.
8pub trait Empty {
9    /// Returns whether this value is empty.
10    fn is_empty(&self) -> bool;
11
12    /// Returns whether this value is empty or all of its descendants are empty.
13    ///
14    /// This only needs to be implemented for containers by calling `Empty::is_deep_empty` on all
15    /// children. The default implementation calls `Empty::is_empty`.
16    ///
17    /// For containers of `Annotated` elements, this must call `Annotated::skip_serialization`.
18    #[inline]
19    fn is_deep_empty(&self) -> bool {
20        self.is_empty()
21    }
22}
23
24/// Defines behavior for skipping the serialization of fields.
25///
26/// This behavior is configured via the `skip_serialization` attribute on fields of structs. It is
27/// passed as parameter to `ToValue::skip_serialization` of the corresponding field.
28///
29/// The default for fields in derived structs is `SkipSerialization::Null(true)`, which will skips
30/// `null` values under the field recursively. Newtype structs (`MyType(T)`) and enums pass through
31/// to their inner type and variant, respectively.
32///
33/// ## Example
34///
35/// ```ignore
36/// #[derive(Debug, Empty, ToValue)]
37/// struct Helper {
38///     #[metastructure(skip_serialization = "never")]
39///     items: Annotated<Array<String>>,
40/// }
41/// ```
42#[derive(Copy, Clone, Debug, PartialEq, Eq)]
43pub enum SkipSerialization {
44    /// Serialize all values. Missing values will be serialized as `null`.
45    Never,
46
47    /// Do not serialize `null` values but keep empty collections.
48    ///
49    /// If the `bool` flag is set to `true`, this applies to all descendants recursively; if it is
50    /// set to `false`, this only applies to direct children and does not propagate down.
51    Null(bool),
52
53    /// Do not serialize empty objects as indicated by the `Empty` trait.
54    ///
55    /// If the `bool` flag is set to `true`, this applies to all descendants recursively; if it is
56    /// set to `false`, this only applies to direct children and does not propagate down.
57    Empty(bool),
58}
59
60impl SkipSerialization {
61    /// Returns the serialization behavior for child elements.
62    ///
63    /// Shallow behaviors - `Null(false)` and `Empty(false)` - propagate as `Never`, all others
64    /// remain the same. This allows empty containers to be skipped while their contents will
65    /// serialize with `null` values.
66    pub fn descend(self) -> Self {
67        match self {
68            SkipSerialization::Null(false) => SkipSerialization::Never,
69            SkipSerialization::Empty(false) => SkipSerialization::Never,
70            other => other,
71        }
72    }
73}
74
75impl Default for SkipSerialization {
76    fn default() -> Self {
77        SkipSerialization::Null(true)
78    }
79}
80
81/// Implemented for all meta structures.
82pub trait FromValue: Debug {
83    /// Creates a meta structure from an annotated boxed value.
84    fn from_value(value: Annotated<Value>) -> Annotated<Self>
85    where
86        Self: Sized;
87}
88
89/// Implemented for all meta structures which can be created from an object.
90///
91/// Only meta structures which implement [`FromObjectRef`] can be flattened.
92pub trait FromObjectRef: FromValue {
93    /// Creates a meta structure from key value pairs.
94    ///
95    /// The implementation is supposed remove used fields from the passed `value`.
96    fn from_object_ref(value: &mut Object<Value>) -> Self
97    where
98        Self: Sized;
99}
100
101/// Implemented for all meta structures.
102pub trait IntoValue: Debug + Empty {
103    /// Boxes the meta structure back into a value.
104    fn into_value(self) -> Value
105    where
106        Self: Sized;
107
108    /// Extracts children meta map out of a value.
109    fn extract_child_meta(&self) -> MetaMap
110    where
111        Self: Sized,
112    {
113        MetaMap::new()
114    }
115
116    /// Efficiently serializes the payload directly.
117    fn serialize_payload<S>(&self, s: S, behavior: SkipSerialization) -> Result<S::Ok, S::Error>
118    where
119        Self: Sized,
120        S: serde::Serializer;
121
122    /// Extracts the meta tree out of annotated value.
123    ///
124    /// This should not be overridden by implementators, instead `extract_child_meta`
125    /// should be provided instead.
126    fn extract_meta_tree(value: &Annotated<Self>) -> MetaTree
127    where
128        Self: Sized,
129    {
130        MetaTree {
131            meta: value.1.clone(),
132            children: match value.0 {
133                Some(ref value) => IntoValue::extract_child_meta(value),
134                None => BTreeMap::default(),
135            },
136        }
137    }
138}
139
140/// Implemented for all meta structures which can be serialized into an object.
141///
142/// Instead of creating a new [`Value`] as done with [`IntoValue::into_value`],
143/// this trait assumes the underlying value is an object like (struct) and
144/// can be directly serialized into an object without creating an intermediate
145/// object first.
146///
147/// Only meta structures which implement [`IntoObjectRef`] can be flattened.
148pub trait IntoObjectRef: IntoValue {
149    /// Boxes the meta structure back into an object of values.
150    ///
151    /// All fields contained need to be added to the passed `obj`.
152    /// This is the inverse operation to [`FromObjectRef::from_object_ref`].
153    fn into_object_ref(self, obj: &mut Object<Value>);
154}
155
156/// A type-erased iterator over a collection of [`Getter`]s.
157///
158/// This type is usually returned from [`Getter::get_iter`].
159///
160/// # Example
161///
162/// ```
163/// use relay_protocol::{Getter, GetterIter, Val};
164///
165/// struct Nested {
166///     nested_value: String,
167/// }
168///
169/// impl Getter for Nested {
170///     fn get_value(&self, path: &str) -> Option<Val<'_>> {
171///         Some(match path {
172///             "nested_value" => self.nested_value.as_str().into(),
173///                _ => return None,
174///         })
175///     }
176/// }
177///
178/// struct Root {
179///     value_1: String,
180///     value_2: Vec<Nested>,
181/// }
182///
183/// impl Getter for Root {
184///     fn get_value(&self, path: &str) -> Option<Val<'_>> {
185///         Some(match path.strip_prefix("root.")? {
186///             "value_1" => self.value_1.as_str().into(),
187///             _ => {
188///                 return None;
189///             }
190///         })
191///     }
192///
193///     // `get_iter` should return a `GetterIter` that can be used for iterating on the
194///     // `Getter`(s).
195///     fn get_iter(&self, path: &str) -> Option<GetterIter<'_>> {
196///         Some(match path.strip_prefix("root.")? {
197///             "value_2" => GetterIter::new(self.value_2.iter()),
198///             _ => return None,
199///         })
200///     }
201/// }
202///
203/// // An example usage given an instance that implement `Getter`.
204/// fn matches<T>(instance: &T) -> bool
205///     where T: Getter + ?Sized
206/// {
207///     let Some(mut getter_iter) = instance.get_iter("root.value_2") else {
208///         return false;
209///     };
210///
211///     for getter in getter_iter {
212///         let nested_value = getter.get_value("nested_value");
213///     }
214///
215///     true
216/// }
217/// ```
218pub struct GetterIter<'a> {
219    iter: Box<dyn Iterator<Item = &'a dyn Getter> + 'a>,
220}
221
222impl<'a> GetterIter<'a> {
223    /// Creates a new [`GetterIter`] given an iterator of a type that implements [`Getter`].
224    pub fn new<I, T>(iterator: I) -> Self
225    where
226        I: Iterator<Item = &'a T> + 'a,
227        T: Getter + 'a,
228    {
229        Self {
230            iter: Box::new(iterator.map(|v| v as &dyn Getter)),
231        }
232    }
233
234    /// Creates a new [`GetterIter`] given a collection of
235    /// [`Annotated`]s whose type implement [`Getter`].
236    pub fn new_annotated<I, T>(iterator: I) -> Self
237    where
238        I: IntoIterator<Item = &'a Annotated<T>>,
239        I::IntoIter: 'a,
240        T: Getter + 'a,
241    {
242        Self::new(iterator.into_iter().filter_map(Annotated::value))
243    }
244}
245
246impl<'a> Iterator for GetterIter<'a> {
247    type Item = &'a dyn Getter;
248
249    fn next(&mut self) -> Option<Self::Item> {
250        self.iter.next()
251    }
252}
253
254/// A type that supports field access by paths.
255///
256/// This is the runtime version of [`get_value!`](crate::get_value!) and additionally supports
257/// indexing into [`Value`]. For typed access to static paths, use the macros instead.
258///
259/// # Syntax
260///
261/// The path identifies a value within the structure. A path consists of components separated by
262/// `.`, where each of the components is the name of a field to access. Every path starts with the
263/// name of the root level component, which must match for this type.
264///
265/// Special characters are escaped with a `\`. The two special characters are:
266///  - `\.` matches a literal dot in a path component.
267///  - `\\` matches a literal backslash in a path component.
268///
269/// # Implementation
270///
271/// Implementation of the `Getter` trait should follow a set of conventions to ensure the paths
272/// align with expectations based on the layout of the implementing type:
273///
274///  1. The name of the root component should be the lowercased version of the name of the
275///     structure. For example, a structure called `Event` would use `event` as the root component.
276///  2. All fields of the structure are referenced by the name of the field in the containing
277///     structure. This also applies to mappings such as `HashMap`, where the key should be used as
278///     field name. For recursive access, this translates transitively through the hierarchy.
279///  3. Newtypes and structured enumerations do not show up in paths. This especially applies to
280///     `Option`, which opaque in the path: `None` is simply propagated up.
281///
282/// In the future, a derive for the `Getter` trait will be added to simplify implementing the
283/// `Getter` trait.
284///
285/// # Example
286///
287/// ```
288/// use relay_protocol::{Getter, Val};
289///
290/// struct Root {
291///     a: u64,
292///     b: Nested,
293/// }
294///
295/// struct Nested {
296///     c: u64,
297/// }
298///
299/// impl Getter for Root {
300///     fn get_value(&self, path: &str) -> Option<Val<'_>> {
301///         match path.strip_prefix("root.")? {
302///             "a" => Some(self.a.into()),
303///             "b.c" => Some(self.b.c.into()),
304///             _ => None,
305///         }
306///     }
307/// }
308///
309///
310/// let root = Root {
311///   a: 1,
312///   b: Nested {
313///     c: 2,
314///   }
315/// };
316///
317/// assert_eq!(root.get_value("root.a"), Some(Val::U64(1)));
318/// assert_eq!(root.get_value("root.b.c"), Some(Val::U64(2)));
319/// assert_eq!(root.get_value("root.d"), None);
320/// ```
321pub trait Getter {
322    /// Returns the serialized value of a field pointed to by a `path`.
323    fn get_value(&self, path: &str) -> Option<Val<'_>>;
324
325    /// Returns an iterator over the array pointed to by a `path`.
326    ///
327    /// If the path does not exist or is not an array, this returns `None`. Note that `get_value` may not return a value for paths that expose an iterator.
328    fn get_iter(&self, _path: &str) -> Option<GetterIter<'_>> {
329        None
330    }
331}