Skip to main content

cdevents_sdk/
subject.rs

1use std::str::FromStr;
2
3use serde::{Deserialize, Serialize};
4
5use crate::{Content, Id, UriReference};
6
7/// see <https://github.com/cdevents/spec/blob/main/spec.md#cdevent-subject>
8#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
9#[serde(deny_unknown_fields)]
10pub struct Subject {
11    #[serde(rename = "content")]
12    content: Content,
13    #[serde(rename = "id")]
14    id: Id,
15    #[serde(
16        rename = "source",
17        default,
18        skip_serializing_if = "Option::is_none",
19    )]
20    source: Option<UriReference>,
21    #[serde(rename = "type", skip_serializing_if = "Option::is_none", default)]
22    #[deprecated = "this file was removed since cdevents spec 0.5"]
23    #[doc(hidden)]
24    ty: Option<String>,
25}
26
27impl Subject {
28    /// see <https://github.com/cdevents/spec/blob/main/spec.md#id-subject>
29    pub fn id(&self) -> &Id {
30        &self.id
31    }
32
33    pub fn with_id(mut self, id: Id) -> Self {
34        self.id = id;
35        self
36    }
37
38    /// see <https://github.com/cdevents/spec/blob/main/spec.md#source-subject>
39    pub fn source(&self) -> &Option<UriReference> {
40        &self.source
41    }
42
43    pub fn with_source(mut self, source: UriReference) -> Self {
44        self.source = Some(source);
45        self
46    }
47
48    // /// see <https://github.com/cdevents/spec/blob/main/spec.md#type-context>
49    // /// derived from content
50    // pub fn ty(&self) -> &str {
51    //     &self.ty
52    // }
53
54    /// see <https://github.com/cdevents/spec/blob/main/spec.md#content>
55    pub fn content(&self) -> &Content {
56        &self.content
57    }
58
59    #[allow(deprecated)]
60    pub fn from_json(ty: &str, json: serde_json::Value) -> Result<Self, serde_json::Error> {
61        Ok(Subject {
62            id: json["id"]
63                .as_str()
64                .ok_or_else(|| serde::de::Error::missing_field("id"))?
65                .try_into()
66                .map_err(serde::de::Error::custom)?,
67            ty: json["type"]
68                .as_str().map(|s| s.to_owned()),
69            source: match json["source"].as_str() {
70                None => None,
71                Some(s) => Some(
72                    UriReference::from_str(s).map_err(serde::de::Error::custom)?,
73                ),
74            },
75            content: Content::from_json(ty, json["content"].clone())?,
76        })
77    }
78}
79
80impl<T> From<T> for Subject where T: Into<Content>{
81    #[allow(deprecated)]
82    fn from(content: T) -> Self {
83        let content = content.into();
84        // TODO remove this hack when remove support for spec < 0.5
85        let ty = crate::extract_subject_predicate(content.ty())
86            .map(|(s, _)| s.to_string());
87        Self {
88            content,
89            id: Id::default(),
90            source: None,
91            ty,
92        }
93    }
94}
95
96#[cfg(feature = "testkit")]
97impl<> proptest::arbitrary::Arbitrary for Subject {
98    type Parameters = ();
99    type Strategy = proptest::strategy::BoxedStrategy<Self>;
100    fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
101        use proptest::prelude::*;
102        (
103            any::<Content>(),
104            any::<Id>(),
105            any::<Option<UriReference>>(),
106        ).prop_map(|(content, id, source)| {
107            let mut subject = Subject::from(content).with_id(id);
108            if let Some(source) = source {
109                subject = subject.with_source(source);
110            }
111            subject
112        }).boxed()
113    }
114}
115
116
117#[cfg(test)]
118mod tests {
119    use proptest::prelude::*;
120    use super::*;
121
122    proptest! {
123        #[test]
124        #[cfg(feature = "testkit")]
125        fn jsonify_arbitraries(s in any::<Subject>()) {
126            // Not enough information into json of subject to deserialize into the same sut content
127            // so only check that it could be serialized
128            serde_json::to_string(&s).unwrap();
129        }
130    }
131}