xapi_rs/data/
sub_statement_object.rs

1// SPDX-License-Identifier: GPL-3.0-or-later
2
3use crate::data::{
4    Activity, ActivityId, Agent, AgentId, DataError, Fingerprint, Group, GroupId, StatementRef,
5    Validate, ValidationError,
6};
7use core::fmt;
8use serde::{Deserialize, Serialize, de::Error};
9use std::hash::Hasher;
10
11/// Enumeration for a potential _Object_ of a [Statement][1] itself being the
12/// _Object_ of another; i.e. the designated variant here is the _Object_ of
13/// the [Statement][1] referenced in a [sub-statement][2] variant.
14///
15/// [1]: crate::Statement
16/// [2]: crate::SubStatement#variant::SubStatement
17#[derive(Clone, Debug, PartialEq, Serialize)]
18#[serde(untagged)]
19pub enum SubStatementObject {
20    /// The _object_ is an [Agent].
21    Agent(Agent),
22    /// The _object_ is a [Group].
23    Group(Group),
24    /// The _object_ is a [Statement-Reference][StatementRef].
25    StatementRef(StatementRef),
26    /// The _object_ is an [Activity].
27    Activity(Activity),
28}
29
30#[derive(Debug, Serialize)]
31#[serde(untagged)]
32pub(crate) enum SubStatementObjectId {
33    Activity(ActivityId),
34    Agent(AgentId),
35    Group(GroupId),
36    StatementRef(StatementRef),
37}
38
39impl From<SubStatementObject> for SubStatementObjectId {
40    fn from(value: SubStatementObject) -> Self {
41        match value {
42            SubStatementObject::Agent(agent) => SubStatementObjectId::Agent(agent.into()),
43            SubStatementObject::Group(group) => SubStatementObjectId::Group(group.into()),
44            SubStatementObject::StatementRef(stmt_ref) => {
45                SubStatementObjectId::StatementRef(stmt_ref)
46            }
47            SubStatementObject::Activity(activity) => {
48                SubStatementObjectId::Activity(activity.into())
49            }
50        }
51    }
52}
53
54impl From<SubStatementObjectId> for SubStatementObject {
55    fn from(value: SubStatementObjectId) -> Self {
56        match value {
57            SubStatementObjectId::Activity(x) => SubStatementObject::Activity(Activity::from(x)),
58            SubStatementObjectId::Agent(x) => SubStatementObject::Agent(Agent::from(x)),
59            SubStatementObjectId::Group(x) => SubStatementObject::Group(Group::from(x)),
60            SubStatementObjectId::StatementRef(x) => SubStatementObject::StatementRef(x),
61        }
62    }
63}
64
65impl SubStatementObject {
66    /// Coerce an [Agent] to a [SubStatementObject].
67    pub fn from_agent(obj: Agent) -> Self {
68        SubStatementObject::Agent(obj)
69    }
70
71    /// Coerce a [Group] to a [SubStatementObject].
72    pub fn from_group(obj: Group) -> Self {
73        SubStatementObject::Group(obj)
74    }
75
76    /// Coerce a [StatementRef] to a [SubStatementObject].
77    pub fn from_statement_ref(obj: StatementRef) -> Self {
78        SubStatementObject::StatementRef(obj)
79    }
80
81    /// Coerce an [Activity] to a [SubStatementObject].
82    pub fn from_activity(obj: Activity) -> Self {
83        SubStatementObject::Activity(obj)
84    }
85
86    /// Return TRUE if this is an [Agent][1] variant; FALSE otherwise.
87    ///
88    /// [1]: SubStatementObject#variant.Agent
89    pub fn is_agent(&self) -> bool {
90        matches!(self, SubStatementObject::Agent(_))
91    }
92
93    /// Return TRUE if this is a [Group][1] variant; FALSE otherwise.
94    ///
95    /// [1]: SubStatementObject#variant.Group
96    pub fn is_group(&self) -> bool {
97        matches!(self, SubStatementObject::Group(_))
98    }
99
100    /// Return TRUE if this is an [StatementRef][1] variant; FALSE otherwise.
101    ///
102    /// [1]: SubStatementObject#variant.StatementRef
103    pub fn is_statement_ref(&self) -> bool {
104        matches!(self, SubStatementObject::StatementRef(_))
105    }
106
107    /// Return TRUE if this is an [Activity][1] variant; FALSE otherwise.
108    ///
109    /// [1]: SubStatementObject#variant.Activity
110    pub fn is_activity(&self) -> bool {
111        matches!(self, SubStatementObject::Activity(_))
112    }
113
114    /// Coerce this to an [Agent] if indeed it was an `SubStatementObject::Agent`
115    /// variant. Raise [DataError] if it was not.
116    pub fn as_agent(&self) -> Result<Agent, DataError> {
117        match self {
118            SubStatementObject::Agent(x) => Ok(x.to_owned()),
119            _ => Err(DataError::Validation(ValidationError::ConstraintViolation(
120                format!("This ({self}) is NOT an Agent").into(),
121            ))),
122        }
123    }
124
125    /// Coerce this to a [Group] if indeed it was an `SubStatementObject::Group`
126    /// variant. Raise [DataError] if it was not.
127    pub fn as_group(&self) -> Result<Group, DataError> {
128        match self {
129            SubStatementObject::Group(x) => Ok(x.to_owned()),
130            _ => Err(DataError::Validation(ValidationError::ConstraintViolation(
131                format!("This ({self}) is NOT a Group").into(),
132            ))),
133        }
134    }
135
136    /// Coerce this to a [StatementRef] if indeed it was an `SubStatementObject::StatementRef`
137    /// variant. Raise [DataError] if it was not.
138    pub fn as_statement_ref(&self) -> Result<StatementRef, DataError> {
139        match self {
140            SubStatementObject::StatementRef(x) => Ok(x.to_owned()),
141            _ => Err(DataError::Validation(ValidationError::ConstraintViolation(
142                format!("This ({self}) is NOT a StatementRef").into(),
143            ))),
144        }
145    }
146
147    /// Coerce this to an [Activity] if indeed it was an `SubStatementObject::Activity`
148    /// variant. Raise [DataError] if it was not.
149    pub fn as_activity(&self) -> Result<Activity, DataError> {
150        match self {
151            SubStatementObject::Activity(x) => Ok(x.to_owned()),
152            _ => Err(DataError::Validation(ValidationError::ConstraintViolation(
153                format!("This ({self}) is NOT an Activity").into(),
154            ))),
155        }
156    }
157}
158
159impl<'de> Deserialize<'de> for SubStatementObject {
160    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
161    where
162        D: serde::Deserializer<'de>,
163    {
164        let value = serde_json::Value::deserialize(deserializer)?;
165        if let Ok(x) = Agent::deserialize(value.clone())
166            && x.check_object_type()
167        {
168            return Ok(SubStatementObject::Agent(x));
169        }
170        if let Ok(x) = Group::deserialize(value.clone())
171            && x.check_object_type()
172        {
173            return Ok(SubStatementObject::Group(x));
174        }
175        if let Ok(x) = StatementRef::deserialize(value.clone())
176            && x.check_object_type()
177        {
178            return Ok(SubStatementObject::StatementRef(x));
179        }
180        match Activity::deserialize(value) {
181            Ok(x) => Ok(SubStatementObject::Activity(x)),
182            _ => Err(D::Error::custom(
183                "input did not match any SubStatementObject variant",
184            )),
185        }
186    }
187}
188
189impl fmt::Display for SubStatementObject {
190    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
191        match self {
192            SubStatementObject::Activity(x) => write!(f, "{x}"),
193            SubStatementObject::Agent(x) => write!(f, "{x}"),
194            SubStatementObject::Group(x) => write!(f, "{x}"),
195            SubStatementObject::StatementRef(x) => write!(f, "{x}"),
196        }
197    }
198}
199
200impl Fingerprint for SubStatementObject {
201    fn fingerprint<H: Hasher>(&self, state: &mut H) {
202        match self {
203            SubStatementObject::Agent(x) => x.fingerprint(state),
204            SubStatementObject::Group(x) => x.fingerprint(state),
205            SubStatementObject::StatementRef(x) => x.fingerprint(state),
206            SubStatementObject::Activity(x) => x.fingerprint(state),
207        }
208    }
209}
210
211impl Validate for SubStatementObject {
212    fn validate(&self) -> Vec<ValidationError> {
213        match self {
214            SubStatementObject::Activity(x) => x.validate(),
215            SubStatementObject::Agent(x) => x.validate(),
216            SubStatementObject::Group(x) => x.validate(),
217            SubStatementObject::StatementRef(x) => x.validate(),
218        }
219    }
220}
221
222#[cfg(test)]
223mod tests {
224    use super::*;
225    use tracing_test::traced_test;
226
227    const ID: &str = "9e13cefd-53d3-4eac-b5ed-2cf6693903bb";
228    const JSON: &str =
229        r#"{"objectType":"StatementRef","id":"9e13cefd-53d3-4eac-b5ed-2cf6693903bb"}"#;
230
231    #[traced_test]
232    #[test]
233    fn test_se() -> Result<(), DataError> {
234        let sr = StatementRef::builder().id(ID)?.build()?;
235        let sso = SubStatementObject::StatementRef(sr);
236        let se_result = serde_json::to_string(&sso);
237        assert!(se_result.is_ok());
238        let json = se_result.unwrap();
239        assert_eq!(json, JSON);
240
241        Ok(())
242    }
243
244    #[traced_test]
245    #[test]
246    fn test_de() {
247        let de_result = serde_json::from_str(JSON);
248        assert!(de_result.is_ok());
249        match de_result.unwrap() {
250            SubStatementObject::StatementRef(sr) => {
251                assert_eq!(sr.id().to_string(), ID);
252            }
253            _ => panic!("Bummer :("),
254        }
255    }
256}