relay_protocol/
meta.rs

1use std::fmt;
2use std::str::FromStr;
3
4use serde::ser::SerializeSeq;
5use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
6use smallvec::SmallVec;
7
8use crate::traits::IntoValue;
9use crate::value::{Map, Value};
10
11/// The start (inclusive) and end (exclusive) indices of a `Remark`.
12pub type Range = (usize, usize);
13
14/// Gives an indication about the type of remark.
15#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
16pub enum RemarkType {
17    /// The remark just annotates a value but the value did not change.
18    #[serde(rename = "a")]
19    Annotated,
20    /// The original value was removed entirely.
21    #[serde(rename = "x")]
22    Removed,
23    /// The original value was substituted by a replacement value.
24    #[serde(rename = "s")]
25    Substituted,
26    /// The original value was masked.
27    #[serde(rename = "m")]
28    Masked,
29    /// The original value was replaced through pseudonymization.
30    #[serde(rename = "p")]
31    Pseudonymized,
32    /// The original value was encrypted (not implemented yet).
33    #[serde(rename = "e")]
34    Encrypted,
35}
36
37/// Information on a modified section in a string.
38#[derive(Clone, Debug, PartialEq)]
39pub struct Remark {
40    /// The kind of redaction that has been applied on the target value.
41    pub ty: RemarkType,
42    /// Unique identifier of the data scrubbing or normalization rule that caused the modification.
43    pub rule_id: String,
44    /// The inclusive start and exclusive end indices of this remark.
45    pub range: Option<Range>,
46}
47
48impl Remark {
49    /// Creates a new remark.
50    pub fn new<S: Into<String>>(ty: RemarkType, rule_id: S) -> Self {
51        Remark {
52            rule_id: rule_id.into(),
53            ty,
54            range: None,
55        }
56    }
57
58    /// Creates a new text remark with range indices.
59    pub fn with_range<S: Into<String>>(ty: RemarkType, rule_id: S, range: Range) -> Self {
60        Remark {
61            rule_id: rule_id.into(),
62            ty,
63            range: Some(range),
64        }
65    }
66
67    /// The note of this remark.
68    pub fn rule_id(&self) -> &str {
69        &self.rule_id
70    }
71
72    /// The range of this remark.
73    pub fn range(&self) -> Option<&Range> {
74        self.range.as_ref()
75    }
76
77    /// The length of this range.
78    pub fn len(&self) -> Option<usize> {
79        self.range.map(|r| r.1 - r.0)
80    }
81
82    /// Indicates if the remark refers to an empty range
83    pub fn is_empty(&self) -> bool {
84        self.len() == Some(0)
85    }
86
87    /// Returns the type.
88    pub fn ty(&self) -> RemarkType {
89        self.ty
90    }
91}
92
93impl<'de> Deserialize<'de> for Remark {
94    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
95        struct RemarkVisitor;
96
97        impl<'de> de::Visitor<'de> for RemarkVisitor {
98            type Value = Remark;
99
100            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
101                write!(formatter, "a meta remark")
102            }
103
104            fn visit_seq<A: de::SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
105                let rule_id = seq
106                    .next_element()?
107                    .ok_or_else(|| de::Error::custom("missing required rule-id"))?;
108                let ty = seq
109                    .next_element()?
110                    .ok_or_else(|| de::Error::custom("missing required remark-type"))?;
111                let start = seq.next_element()?;
112                let end = seq.next_element()?;
113
114                // Drain the sequence
115                while let Some(de::IgnoredAny) = seq.next_element()? {}
116
117                let range = match (start, end) {
118                    (Some(start), Some(end)) => Some((start, end)),
119                    _ => None,
120                };
121
122                Ok(Remark { ty, rule_id, range })
123            }
124        }
125
126        deserializer.deserialize_seq(RemarkVisitor)
127    }
128}
129
130impl Serialize for Remark {
131    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
132        let mut seq = serializer.serialize_seq(None)?;
133        seq.serialize_element(self.rule_id())?;
134        seq.serialize_element(&self.ty())?;
135        if let Some(range) = self.range() {
136            seq.serialize_element(&range.0)?;
137            seq.serialize_element(&range.1)?;
138        }
139        seq.end()
140    }
141}
142
143/// The kind of an `Error`.
144#[derive(Clone, Debug, Eq, PartialEq)]
145pub enum ErrorKind {
146    /// The data does not fit the schema or is semantically incorrect.
147    InvalidData,
148
149    /// The structure is missing a required attribute.
150    MissingAttribute,
151
152    /// The attribute is not allowed in this structure.
153    InvalidAttribute,
154
155    /// This value was too long and removed entirely.
156    ValueTooLong,
157
158    /// Clock-drift of the SDK has been corrected in all timestamps.
159    ClockDrift,
160
161    /// The timestamp is too old.
162    PastTimestamp,
163
164    /// The timestamp lies in the future, likely due to clock drift.
165    FutureTimestamp,
166
167    /// Any other unknown error for forward compatibility.
168    Unknown(String),
169}
170
171impl ErrorKind {
172    /// Parses an error kind from a `&str` or `String`.
173    fn parse<S>(string: S) -> Self
174    where
175        S: AsRef<str> + Into<String>,
176    {
177        match string.as_ref() {
178            "invalid_data" => ErrorKind::InvalidData,
179            "missing_attribute" => ErrorKind::MissingAttribute,
180            "invalid_attribute" => ErrorKind::InvalidAttribute,
181            "value_too_long" => ErrorKind::ValueTooLong,
182            "past_timestamp" => ErrorKind::PastTimestamp,
183            "future_timestamp" => ErrorKind::FutureTimestamp,
184            _ => ErrorKind::Unknown(string.into()),
185        }
186    }
187
188    /// Returns the string representation of this error kind.
189    pub fn as_str(&self) -> &str {
190        match self {
191            ErrorKind::InvalidData => "invalid_data",
192            ErrorKind::MissingAttribute => "missing_attribute",
193            ErrorKind::InvalidAttribute => "invalid_attribute",
194            ErrorKind::ValueTooLong => "value_too_long",
195            ErrorKind::PastTimestamp => "past_timestamp",
196            ErrorKind::FutureTimestamp => "future_timestamp",
197            ErrorKind::ClockDrift => "clock_drift",
198            ErrorKind::Unknown(error) => error,
199        }
200    }
201}
202
203impl fmt::Display for ErrorKind {
204    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
205        write!(f, "{}", self.as_str())
206    }
207}
208
209impl From<String> for ErrorKind {
210    fn from(string: String) -> Self {
211        ErrorKind::parse(string)
212    }
213}
214
215impl<'a> From<&'a str> for ErrorKind {
216    fn from(string: &'a str) -> Self {
217        ErrorKind::parse(string)
218    }
219}
220
221impl FromStr for ErrorKind {
222    type Err = ();
223
224    fn from_str(string: &str) -> Result<Self, Self::Err> {
225        Ok(ErrorKind::from(string))
226    }
227}
228
229impl<'de> Deserialize<'de> for ErrorKind {
230    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
231        struct ErrorKindVisitor;
232
233        impl de::Visitor<'_> for ErrorKindVisitor {
234            type Value = ErrorKind;
235
236            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
237                write!(formatter, "an error kind")
238            }
239
240            fn visit_str<E>(self, string: &str) -> Result<Self::Value, E>
241            where
242                E: de::Error,
243            {
244                Ok(ErrorKind::from(string))
245            }
246
247            fn visit_string<E>(self, string: String) -> Result<Self::Value, E>
248            where
249                E: de::Error,
250            {
251                Ok(ErrorKind::from(string))
252            }
253        }
254
255        deserializer.deserialize_str(ErrorKindVisitor)
256    }
257}
258
259impl Serialize for ErrorKind {
260    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
261        serializer.serialize_str(self.as_str())
262    }
263}
264
265/// An error with an enumerable kind and optional data.
266#[derive(Debug, Clone, PartialEq)]
267pub struct Error {
268    kind: ErrorKind,
269    data: Map<String, Value>,
270}
271
272impl Error {
273    /// Creates a new error with the given data.
274    #[inline]
275    fn with_data(kind: ErrorKind, data: Map<String, Value>) -> Self {
276        Error { kind, data }
277    }
278
279    /// Creates a new error without data.
280    #[inline]
281    pub fn new(kind: ErrorKind) -> Self {
282        Error::with_data(kind, Map::default())
283    }
284
285    /// Creates a new error and allows instant modification in a function.
286    #[inline]
287    pub fn with<F>(kind: ErrorKind, f: F) -> Self
288    where
289        F: FnOnce(&mut Self),
290    {
291        let mut error = Error::new(kind);
292        f(&mut error);
293        error
294    }
295
296    /// Creates an invalid data error with a plain text reason.
297    pub fn invalid<S>(reason: S) -> Self
298    where
299        S: std::fmt::Display,
300    {
301        Error::with(ErrorKind::InvalidData, |error| {
302            error.insert("reason", reason.to_string());
303        })
304    }
305
306    /// Creates an error that describes an invalid value.
307    pub fn expected(expectation: &str) -> Self {
308        // Does not use `Error::invalid` to avoid the string copy.
309        Error::with(ErrorKind::InvalidData, |error| {
310            error.insert("reason", format!("expected {expectation}"));
311        })
312    }
313
314    /// Creates an error that describes an expected non-empty value.
315    pub fn nonempty() -> Self {
316        // TODO: Replace `invalid_data` this with an explicity error constant for empty values
317        Error::invalid("expected a non-empty value")
318    }
319
320    /// Creates an error that describes an expected non-empty string.
321    pub fn nonempty_string() -> Self {
322        // TODO: Replace `invalid_data` this with an explicity error constant for empty values
323        Error::invalid("expected a non-empty string")
324    }
325
326    /// Returns the kind of this error.
327    pub fn kind(&self) -> &ErrorKind {
328        &self.kind
329    }
330
331    /// Returns an iterator over the data of this error.
332    pub fn data(&self) -> impl Iterator<Item = (&str, &Value)> {
333        self.data.iter().map(|(k, v)| (k.as_str(), v))
334    }
335
336    /// Inserts a new key into the data bag of this error.
337    pub fn insert<K, V>(&mut self, key: K, value: V) -> Option<Value>
338    where
339        K: Into<String>,
340        V: Into<Value>,
341    {
342        self.data.insert(key.into(), value.into())
343    }
344
345    /// Retrieves a key from the data bag of this error.
346    pub fn get<K>(&self, key: K) -> Option<&Value>
347    where
348        K: AsRef<str>,
349    {
350        self.data.get(key.as_ref())
351    }
352}
353
354impl From<ErrorKind> for Error {
355    fn from(kind: ErrorKind) -> Self {
356        Error::new(kind)
357    }
358}
359
360impl<'de> Deserialize<'de> for Error {
361    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
362        struct ErrorVisitor;
363
364        impl<'de> de::Visitor<'de> for ErrorVisitor {
365            type Value = Error;
366
367            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
368                write!(formatter, "a meta remark")
369            }
370
371            fn visit_str<E>(self, string: &str) -> Result<Self::Value, E>
372            where
373                E: de::Error,
374            {
375                Ok(Error::new(ErrorKind::from(string)))
376            }
377
378            fn visit_string<E>(self, string: String) -> Result<Self::Value, E>
379            where
380                E: de::Error,
381            {
382                Ok(Error::new(ErrorKind::from(string)))
383            }
384
385            fn visit_seq<A: de::SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
386                let kind = seq
387                    .next_element()?
388                    .ok_or_else(|| de::Error::custom("missing error kind"))?;
389                let data = seq.next_element()?.unwrap_or_default();
390
391                // Drain the sequence
392                while let Some(de::IgnoredAny) = seq.next_element()? {}
393
394                Ok(Error::with_data(kind, data))
395            }
396        }
397
398        deserializer.deserialize_any(ErrorVisitor)
399    }
400}
401
402impl Serialize for Error {
403    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
404        if self.data.is_empty() {
405            return self.kind.serialize(serializer);
406        }
407
408        let mut seq = serializer.serialize_seq(None)?;
409        seq.serialize_element(&self.kind)?;
410        seq.serialize_element(&self.data)?;
411        seq.end()
412    }
413}
414
415/// Meta information for a data field in the event payload.
416#[derive(Clone, Deserialize, Serialize)]
417struct MetaInner {
418    /// Remarks detailing modifications of this field.
419    #[serde(default, skip_serializing_if = "SmallVec::is_empty", rename = "rem")]
420    remarks: SmallVec<[Remark; 3]>,
421
422    /// Errors that happened during normalization or processing.
423    #[serde(default, skip_serializing_if = "SmallVec::is_empty", rename = "err")]
424    errors: SmallVec<[Error; 3]>,
425
426    /// The original length of modified text fields or collections.
427    #[serde(default, skip_serializing_if = "Option::is_none", rename = "len")]
428    original_length: Option<u32>,
429
430    /// In some cases the original value might be sent along.
431    #[serde(default, skip_serializing_if = "Option::is_none", rename = "val")]
432    original_value: Option<Value>,
433}
434
435impl MetaInner {
436    /// Returns `true` if the meta data entry is empty.
437    pub fn is_empty(&self) -> bool {
438        self.original_length.is_none()
439            && self.remarks.is_empty()
440            && self.errors.is_empty()
441            && self.original_value.is_none()
442    }
443}
444
445/// Meta information for a data field in the event payload.
446#[derive(Clone, Default, Serialize)]
447pub struct Meta(Option<Box<MetaInner>>);
448
449impl fmt::Debug for Meta {
450    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
451        f.debug_struct("Meta")
452            .field("remarks", &self.remarks())
453            .field("errors", &self.errors())
454            .field("original_length", &self.original_length())
455            .field("original_value", &self.original_value())
456            .finish()
457    }
458}
459
460impl<'de> Deserialize<'de> for Meta {
461    #[inline]
462    fn deserialize<D>(deserializer: D) -> Result<Meta, D::Error>
463    where
464        D: serde::Deserializer<'de>,
465    {
466        Ok(match <Option<MetaInner>>::deserialize(deserializer)? {
467            Some(value) => {
468                if value.is_empty() {
469                    Meta(None)
470                } else {
471                    Meta(Some(Box::new(value)))
472                }
473            }
474            None => Meta(None),
475        })
476    }
477}
478
479impl Meta {
480    /// From an error
481    pub fn from_error<E: Into<Error>>(err: E) -> Self {
482        let mut meta = Self::default();
483        meta.add_error(err);
484        meta
485    }
486
487    fn upsert(&mut self) -> &mut MetaInner {
488        self.0.get_or_insert_with(Box::default)
489    }
490
491    /// The original length of this field, if applicable.
492    pub fn original_length(&self) -> Option<usize> {
493        self.0
494            .as_ref()
495            .and_then(|x| x.original_length.map(|x| x as usize))
496    }
497
498    /// Updates the original length of this annotation.
499    pub fn set_original_length(&mut self, original_length: Option<usize>) {
500        let inner = self.upsert();
501        if inner.original_length.is_none() {
502            inner.original_length = original_length.map(|x| x as u32);
503        }
504    }
505
506    fn remarks(&self) -> &[Remark] {
507        match self.0 {
508            Some(ref inner) => &inner.remarks[..],
509            None => &[][..],
510        }
511    }
512
513    /// Iterates all remarks on this field.
514    pub fn iter_remarks(&self) -> impl Iterator<Item = &Remark> {
515        self.remarks().iter()
516    }
517
518    /// Clears all remarks
519    pub fn clear_remarks(&mut self) {
520        if let Some(ref mut inner) = self.0 {
521            inner.remarks.clear();
522        }
523    }
524
525    /// Adds a remark.
526    pub fn add_remark(&mut self, remark: Remark) {
527        self.upsert().remarks.push(remark);
528    }
529
530    fn errors(&self) -> &[Error] {
531        match self.0 {
532            Some(ref inner) => &inner.errors[..],
533            None => &[][..],
534        }
535    }
536
537    /// Iterates errors on this field.
538    pub fn iter_errors(&self) -> impl Iterator<Item = &Error> {
539        self.errors().iter()
540    }
541
542    /// Mutable reference to errors of this field.
543    pub fn add_error<E: Into<Error>>(&mut self, err: E) {
544        let errors = &mut self.upsert().errors;
545        let err = err.into();
546        if errors.contains(&err) {
547            return;
548        }
549        errors.push(err);
550    }
551
552    /// Returns a reference to the original value, if any.
553    pub fn original_value(&self) -> Option<&Value> {
554        self.0.as_ref().and_then(|x| x.original_value.as_ref())
555    }
556
557    /// Returns a mutable reference to the original value, if any.
558    pub fn original_value_as_mut(&mut self) -> Option<&mut Value> {
559        self.0.as_mut().and_then(|x| x.original_value.as_mut())
560    }
561
562    /// Sets the original value.
563    pub fn set_original_value<T>(&mut self, original_value: Option<T>)
564    where
565        T: IntoValue,
566    {
567        // XXX: Since metadata is currently not subject to trimming, only allow really small values
568        // in original_value for now.
569        if crate::size::estimate_size(original_value.as_ref()) < 500 {
570            self.upsert().original_value = original_value.map(IntoValue::into_value);
571        }
572    }
573
574    /// Take out the original value.
575    pub fn take_original_value(&mut self) -> Option<Value> {
576        self.0.as_mut().and_then(|x| x.original_value.take())
577    }
578
579    /// Indicates whether this field has errors.
580    pub fn has_errors(&self) -> bool {
581        self.0.as_ref().is_some_and(|x| !x.errors.is_empty())
582    }
583
584    /// Indicates whether this field has meta data attached.
585    pub fn is_empty(&self) -> bool {
586        self.0.as_ref().is_none_or(|x| x.is_empty())
587    }
588
589    /// Merges this meta with another one.
590    pub fn merge(mut self, other: Self) -> Self {
591        if let Some(other_inner) = other.0 {
592            let other_inner = *other_inner;
593            let inner = self.upsert();
594            inner.remarks.extend(other_inner.remarks);
595            inner.errors.extend(other_inner.errors);
596            if inner.original_length.is_none() {
597                inner.original_length = other_inner.original_length;
598            }
599            if inner.original_value.is_none() {
600                inner.original_value = other_inner.original_value;
601            }
602        }
603        self
604    }
605}
606
607impl Default for MetaInner {
608    fn default() -> Self {
609        MetaInner {
610            remarks: SmallVec::new(),
611            errors: SmallVec::new(),
612            original_length: None,
613            original_value: None,
614        }
615    }
616}
617
618impl PartialEq for MetaInner {
619    fn eq(&self, other: &Self) -> bool {
620        self.remarks == other.remarks
621            && self.errors == other.errors
622            && self.original_length == other.original_length
623            && self.original_value == other.original_value
624    }
625}
626
627impl PartialEq for Meta {
628    fn eq(&self, other: &Self) -> bool {
629        if self.is_empty() && other.is_empty() {
630            true
631        } else {
632            match (self.0.as_ref(), other.0.as_ref()) {
633                (Some(a), Some(b)) => a == b,
634                _ => false,
635            }
636        }
637    }
638}