Skip to main content

relay_event_normalization/eap/
attribute_like.rs

1use relay_event_schema::protocol::{Attribute, Attributes, SpanData};
2use relay_protocol::{Annotated, Object, Value};
3
4/// An attribute collection which is keyed by an attribute key defined in [`relay_conventions`].
5///
6/// This exists as a common abstraction over [`SpanData`] and [`Attributes`]. Its purpose is to
7/// allow modern attribute based normalizations also to apply to transaction based spans,
8/// eliminating the need to duplicate code.
9///
10/// This largely mirrors the API of [`Attributes`] and provides it also for [`SpanData`].
11pub trait AttributesLike {
12    /// The attribute value.
13    type Value: AttributeLike;
14
15    /// Access this container through the underlying [`Object`].
16    fn as_object(&self) -> &Object<Self::Value>;
17    /// Access this container through the underlying [`Object`] mutably.
18    fn as_object_mut(&mut self) -> &mut Object<Self::Value>;
19
20    /// Checks whether this collection contains an attribute with the given `key`.
21    fn contains_key(&self, key: &str) -> bool {
22        self.as_object().contains_key(key)
23    }
24
25    /// Inserts an attribute with the given value into the collection.
26    fn insert(&mut self, key: String, value: Annotated<Self::Value>) {
27        self.as_object_mut().insert(key, value);
28    }
29
30    /// Removes a `key` from the attribute collection returning its value.
31    fn remove(&mut self, key: &str) -> Option<Annotated<Self::Value>> {
32        self.as_object_mut().remove(key)
33    }
34}
35
36impl AttributesLike for SpanData {
37    type Value = Value;
38
39    fn as_object(&self) -> &Object<Self::Value> {
40        &self.other
41    }
42
43    fn as_object_mut(&mut self) -> &mut Object<Self::Value> {
44        &mut self.other
45    }
46}
47
48impl AttributesLike for Attributes {
49    type Value = Attribute;
50
51    fn as_object(&self) -> &Object<Self::Value> {
52        &self.0
53    }
54
55    fn as_object_mut(&mut self) -> &mut Object<Self::Value> {
56        &mut self.0
57    }
58}
59
60/// An attribute value stored in [`AttributesLike`].
61///
62/// This only allows read only accessors as mutating the attribute value may not be allowed.
63/// For example [`Attribute`] has a `type` field which must match its `value field.
64pub trait AttributeLike: Clone + From<String> + From<i64> + From<f64> {
65    /// Returns a reference to the stored value in the attribute.
66    fn as_value(&self) -> Option<&Value>;
67
68    /// Returns the stored value as a `str`.
69    ///
70    /// Is `None` when the stored value is not a string.
71    fn as_str(&self) -> Option<&str> {
72        self.as_value().and_then(Value::as_str)
73    }
74
75    /// Returns the stored value as a `f64`.
76    ///
77    /// Is `None` when the stored value is not a float.
78    fn as_f64(&self) -> Option<f64> {
79        self.as_value().and_then(Value::as_f64)
80    }
81}
82
83impl AttributeLike for Value {
84    fn as_value(&self) -> Option<&Value> {
85        Some(self)
86    }
87}
88
89impl AttributeLike for Attribute {
90    fn as_value(&self) -> Option<&Value> {
91        self.value.value.value()
92    }
93}