relay_event_schema/protocol/
attributes.rs

1use relay_protocol::{Annotated, Empty, FromValue, IntoValue, Object, SkipSerialization, Value};
2use std::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    /// Additional arbitrary fields for forwards compatibility.
12    #[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
46#[derive(Debug, Clone, PartialEq, Eq)]
47pub enum AttributeType {
48    Boolean,
49    Integer,
50    Double,
51    String,
52    Unknown(String),
53}
54
55impl ProcessValue for AttributeType {}
56
57impl AttributeType {
58    pub fn as_str(&self) -> &str {
59        match self {
60            Self::Boolean => "boolean",
61            Self::Integer => "integer",
62            Self::Double => "double",
63            Self::String => "string",
64            Self::Unknown(value) => value,
65        }
66    }
67
68    pub fn unknown_string() -> String {
69        "unknown".to_string()
70    }
71}
72
73impl fmt::Display for AttributeType {
74    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75        write!(f, "{}", self.as_str())
76    }
77}
78
79impl From<String> for AttributeType {
80    fn from(value: String) -> Self {
81        match value.as_str() {
82            "boolean" => Self::Boolean,
83            "integer" => Self::Integer,
84            "double" => Self::Double,
85            "string" => Self::String,
86            _ => Self::Unknown(value),
87        }
88    }
89}
90
91impl Empty for AttributeType {
92    #[inline]
93    fn is_empty(&self) -> bool {
94        false
95    }
96}
97
98impl FromValue for AttributeType {
99    fn from_value(value: Annotated<Value>) -> Annotated<Self> {
100        match String::from_value(value) {
101            Annotated(Some(value), meta) => Annotated(Some(value.into()), meta),
102            Annotated(None, meta) => Annotated(None, meta),
103        }
104    }
105}
106
107impl IntoValue for AttributeType {
108    fn into_value(self) -> Value
109    where
110        Self: Sized,
111    {
112        Value::String(match self {
113            Self::Unknown(s) => s,
114            s => s.to_string(),
115        })
116    }
117
118    fn serialize_payload<S>(&self, s: S, _behavior: SkipSerialization) -> Result<S::Ok, S::Error>
119    where
120        Self: Sized,
121        S: serde::Serializer,
122    {
123        serde::ser::Serialize::serialize(self.as_str(), s)
124    }
125}