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}