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    /// Returns an attribute value.
21    fn get_value(&self, key: &str) -> Option<&Value> {
22        self.as_object()
23            .get(key)
24            .and_then(Annotated::value)
25            .and_then(AttributeLike::as_value)
26    }
27
28    /// Checks whether this collection contains an attribute with the given `key`.
29    fn contains_key(&self, key: &str) -> bool {
30        self.as_object().contains_key(key)
31    }
32
33    /// Inserts an attribute with the given value into the collection.
34    fn insert(&mut self, key: String, value: Annotated<Self::Value>) {
35        self.as_object_mut().insert(key, value);
36    }
37
38    /// Removes a `key` from the attribute collection returning its value.
39    fn remove(&mut self, key: &str) -> Option<Annotated<Self::Value>> {
40        self.as_object_mut().remove(key)
41    }
42}
43
44impl AttributesLike for SpanData {
45    type Value = Value;
46
47    fn as_object(&self) -> &Object<Self::Value> {
48        &self.other
49    }
50
51    fn as_object_mut(&mut self) -> &mut Object<Self::Value> {
52        &mut self.other
53    }
54}
55
56impl AttributesLike for Attributes {
57    type Value = Attribute;
58
59    fn as_object(&self) -> &Object<Self::Value> {
60        &self.0
61    }
62
63    fn as_object_mut(&mut self) -> &mut Object<Self::Value> {
64        &mut self.0
65    }
66}
67
68/// An attribute value stored in [`AttributesLike`].
69///
70/// This only allows read only accessors as mutating the attribute value may not be allowed.
71/// For example [`Attribute`] has a `type` field which must match its `value field.
72pub trait AttributeLike: Clone + From<String> + From<i64> + From<f64> {
73    /// Returns a reference to the stored value in the attribute.
74    fn as_value(&self) -> Option<&Value>;
75
76    /// Returns the stored value as a `str`.
77    ///
78    /// Is `None` when the stored value is not a string.
79    fn as_str(&self) -> Option<&str> {
80        self.as_value().and_then(Value::as_str)
81    }
82
83    /// Returns the stored value as a `f64`.
84    ///
85    /// Is `None` when the stored value is not a float.
86    fn as_f64(&self) -> Option<f64> {
87        self.as_value().and_then(Value::as_f64)
88    }
89}
90
91impl AttributeLike for Value {
92    fn as_value(&self) -> Option<&Value> {
93        Some(self)
94    }
95}
96
97impl AttributeLike for Attribute {
98    fn as_value(&self) -> Option<&Value> {
99        self.value.value.value()
100    }
101}