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