relay_event_schema/protocol/
attributes.rs1use relay_protocol::{Annotated, Empty, FromValue, IntoValue, Object, SkipSerialization, Value};
2use std::{borrow::Borrow, fmt};
3
4use crate::processor::ProcessValue;
5
6#[derive(Clone, PartialEq, Empty, FromValue, IntoValue, ProcessValue)]
7pub struct Attribute {
8 #[metastructure(flatten)]
9 pub value: AttributeValue,
10
11 #[metastructure(additional_properties)]
13 pub other: Object<Value>,
14}
15
16impl Attribute {
17 pub fn new(attribute_type: AttributeType, value: Value) -> Self {
18 Self {
19 value: AttributeValue {
20 ty: Annotated::new(attribute_type),
21 value: Annotated::new(value),
22 },
23 other: Object::new(),
24 }
25 }
26}
27
28impl fmt::Debug for Attribute {
29 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30 f.debug_struct("Attribute")
31 .field("value", &self.value.value)
32 .field("type", &self.value.ty)
33 .field("other", &self.other)
34 .finish()
35 }
36}
37
38#[derive(Debug, Clone, PartialEq, Empty, FromValue, IntoValue, ProcessValue)]
39pub struct AttributeValue {
40 #[metastructure(field = "type", required = true, trim = false)]
41 pub ty: Annotated<AttributeType>,
42 #[metastructure(required = true, pii = "true")]
43 pub value: Annotated<Value>,
44}
45
46impl From<String> for AttributeValue {
47 fn from(value: String) -> Self {
48 AttributeValue {
49 ty: Annotated::new(AttributeType::String),
50 value: Annotated::new(value.into()),
51 }
52 }
53}
54
55impl From<i64> for AttributeValue {
56 fn from(value: i64) -> Self {
57 AttributeValue {
58 ty: Annotated::new(AttributeType::Integer),
59 value: Annotated::new(value.into()),
60 }
61 }
62}
63
64impl From<f64> for AttributeValue {
65 fn from(value: f64) -> Self {
66 AttributeValue {
67 ty: Annotated::new(AttributeType::Double),
68 value: Annotated::new(value.into()),
69 }
70 }
71}
72
73impl From<bool> for AttributeValue {
74 fn from(value: bool) -> Self {
75 AttributeValue {
76 ty: Annotated::new(AttributeType::Boolean),
77 value: Annotated::new(value.into()),
78 }
79 }
80}
81
82#[derive(Debug, Clone, PartialEq, Eq)]
83pub enum AttributeType {
84 Boolean,
85 Integer,
86 Double,
87 String,
88 Unknown(String),
89}
90
91impl ProcessValue for AttributeType {}
92
93impl AttributeType {
94 pub fn as_str(&self) -> &str {
95 match self {
96 Self::Boolean => "boolean",
97 Self::Integer => "integer",
98 Self::Double => "double",
99 Self::String => "string",
100 Self::Unknown(value) => value,
101 }
102 }
103
104 pub fn unknown_string() -> String {
105 "unknown".to_owned()
106 }
107}
108
109impl fmt::Display for AttributeType {
110 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111 write!(f, "{}", self.as_str())
112 }
113}
114
115impl From<String> for AttributeType {
116 fn from(value: String) -> Self {
117 match value.as_str() {
118 "boolean" => Self::Boolean,
119 "integer" => Self::Integer,
120 "double" => Self::Double,
121 "string" => Self::String,
122 _ => Self::Unknown(value),
123 }
124 }
125}
126
127impl Empty for AttributeType {
128 #[inline]
129 fn is_empty(&self) -> bool {
130 false
131 }
132}
133
134impl FromValue for AttributeType {
135 fn from_value(value: Annotated<Value>) -> Annotated<Self> {
136 match String::from_value(value) {
137 Annotated(Some(value), meta) => Annotated(Some(value.into()), meta),
138 Annotated(None, meta) => Annotated(None, meta),
139 }
140 }
141}
142
143impl IntoValue for AttributeType {
144 fn into_value(self) -> Value
145 where
146 Self: Sized,
147 {
148 Value::String(match self {
149 Self::Unknown(s) => s,
150 s => s.to_string(),
151 })
152 }
153
154 fn serialize_payload<S>(&self, s: S, _behavior: SkipSerialization) -> Result<S::Ok, S::Error>
155 where
156 Self: Sized,
157 S: serde::Serializer,
158 {
159 serde::ser::Serialize::serialize(self.as_str(), s)
160 }
161}
162
163#[derive(Debug, Clone, Default, PartialEq, Empty, FromValue, IntoValue, ProcessValue)]
165pub struct Attributes(pub Object<Attribute>);
166
167impl Attributes {
168 pub fn new() -> Self {
170 Self(Object::new())
171 }
172
173 pub fn get_value<Q>(&self, key: &Q) -> Option<&Value>
175 where
176 String: Borrow<Q>,
177 Q: Ord + ?Sized,
178 {
179 self.get_attribute(key)?.value.value.value()
180 }
181
182 pub fn get_attribute<Q>(&self, key: &Q) -> Option<&Attribute>
184 where
185 String: Borrow<Q>,
186 Q: Ord + ?Sized,
187 {
188 self.0.get(key)?.value()
189 }
190
191 pub fn insert<V: Into<AttributeValue>>(&mut self, key: String, value: V) {
193 fn inner(slf: &mut Attributes, key: String, value: AttributeValue) {
194 let attribute = Annotated::new(Attribute {
195 value,
196 other: Default::default(),
197 });
198 slf.insert_raw(key, attribute);
199 }
200 let value = value.into();
201 inner(self, key, value);
202 }
203
204 pub fn insert_raw(&mut self, key: String, attribute: Annotated<Attribute>) {
206 self.0.insert(key, attribute);
207 }
208
209 pub fn contains_key<Q>(&self, key: &Q) -> bool
211 where
212 String: Borrow<Q>,
213 Q: Ord + ?Sized,
214 {
215 self.0.contains_key(key)
216 }
217
218 pub fn iter_mut(
220 &mut self,
221 ) -> std::collections::btree_map::IterMut<String, Annotated<Attribute>> {
222 self.0.iter_mut()
223 }
224}
225
226impl IntoIterator for Attributes {
227 type Item = (String, Annotated<Attribute>);
228
229 type IntoIter = std::collections::btree_map::IntoIter<String, Annotated<Attribute>>;
230
231 fn into_iter(self) -> Self::IntoIter {
232 self.0.into_iter()
233 }
234}
235
236impl FromIterator<(String, Annotated<Attribute>)> for Attributes {
237 fn from_iter<T: IntoIterator<Item = (String, Annotated<Attribute>)>>(iter: T) -> Self {
238 Self(Object::from_iter(iter))
239 }
240}