1#[macro_export]
8macro_rules! json_literal {
9 ($ty:ty) => {
10 impl<I: $crate::rdfx::Interpretation> $crate::LinkedDataResource<I> for $ty {
11 fn interpretation(
12 &self,
13 _interpretation: &mut I,
14 ) -> $crate::ResourceInterpretation<'_, I> {
15 use $crate::{CowRdfTerm, OwnedRdfTerm, RdfLiteral, ResourceInterpretation};
16
17 let mut value = $crate::jstrict::to_value(self).unwrap();
18 value.canonicalize();
19
20 ResourceInterpretation::Uninterpreted(Some(CowRdfTerm::Owned(
21 OwnedRdfTerm::Literal(RdfLiteral::Json(value)),
22 )))
23 }
24 }
25
26 impl<I: $crate::rdfx::Interpretation> $crate::LinkedDataPredicateObjects<I> for $ty {
27 fn visit_objects<S>(&self, mut visitor: S) -> Result<S::Ok, S::Error>
28 where
29 S: $crate::PredicateObjectsVisitor<I>,
30 {
31 visitor.object(self)?;
32 visitor.end()
33 }
34 }
35
36 impl<I: $crate::rdfx::Interpretation> $crate::LinkedDataDeserializePredicateObjects<I>
37 for $ty
38 where
39 I: $crate::rdfx::interpretation::ReverseInterpretation,
40 I::Resource: $crate::rdfx::Resource,
41 {
42 fn deserialize_objects_in<'a, D>(
43 interpretation: &I,
44 dataset: &D,
45 graph: Option<&I::Resource>,
46 objects: impl IntoIterator<Item = &'a I::Resource>,
47 context: $crate::Context<I>,
48 ) -> Result<Self, $crate::FromLinkedDataError>
49 where
50 I::Resource: 'a,
51 D: $crate::rdfx::dataset::PatternMatchingDataset<Subject = I::Resource>,
52 {
53 let mut objects = objects.into_iter();
54 match objects.next() {
55 Some(object) => {
56 if objects.next().is_none() {
57 <Self as $crate::LinkedDataDeserializeSubject<I>>::deserialize_subject_in(
58 interpretation, dataset, graph, object, context,
59 )
60 } else {
61 Err($crate::FromLinkedDataError::TooManyValues(
62 context.into_iris(interpretation),
63 ))
64 }
65 }
66 None => Err($crate::FromLinkedDataError::MissingRequiredValue(
67 context.into_iris(interpretation),
68 )),
69 }
70 }
71 }
72
73 impl<I: $crate::rdfx::Interpretation> $crate::LinkedDataSubject<I> for $ty {
74 fn visit_subject<S>(&self, visitor: S) -> Result<S::Ok, S::Error>
75 where
76 S: $crate::SubjectVisitor<I>,
77 {
78 visitor.end()
79 }
80 }
81
82 impl<I: $crate::rdfx::Interpretation> $crate::LinkedDataDeserializeSubject<I> for $ty
83 where
84 I: $crate::rdfx::interpretation::ReverseInterpretation,
85 I::Resource: $crate::rdfx::Resource,
86 {
87 fn deserialize_subject_in<D>(
88 interpretation: &I,
89 _dataset: &D,
90 _graph: Option<&I::Resource>,
91 resource: &I::Resource,
92 context: $crate::Context<I>,
93 ) -> Result<Self, $crate::FromLinkedDataError>
94 where
95 D: $crate::rdfx::dataset::PatternMatchingDataset<Subject = I::Resource>,
96 {
97 let mut literal_ty = None;
98 for l in $crate::rdfx::interpretation::ReverseInterpretation::literals_of(
99 interpretation,
100 resource,
101 ) {
102 match l.type_ {
103 $crate::rdfx::CowLiteralType::Any(ref ty) => {
104 let ty_iri = ty.as_iri();
105 if ty_iri.as_str() == $crate::RDF_JSON.as_str() {
106 use $crate::jstrict::Parse;
107 let (json, _) = $crate::jstrict::Value::parse_str(&l.value)
108 .map_err(|_| {
109 $crate::FromLinkedDataError::InvalidLiteral(
110 context.into_iris(interpretation),
111 )
112 })?;
113
114 return $crate::jstrict::from_value(json).map_err(|_| {
115 $crate::FromLinkedDataError::InvalidLiteral(
116 context.into_iris(interpretation),
117 )
118 });
119 } else {
120 literal_ty = Some(ty_iri.into())
121 }
122 }
123 $crate::rdfx::CowLiteralType::LangString(_)
124 | $crate::rdfx::CowLiteralType::DirLangString { .. } => {
125 literal_ty = Some($crate::rdfx::RDF_LANG_STRING.into())
126 }
127 }
128 }
129
130 match literal_ty {
131 Some(ty) => Err($crate::FromLinkedDataError::LiteralTypeMismatch {
132 context: context.into_iris(interpretation),
133 expected: Some(Box::new($crate::RDF_JSON.into())),
134 found: Box::new(ty),
135 }),
136 None => Err($crate::FromLinkedDataError::ExpectedLiteral(
137 context.into_iris(interpretation),
138 )),
139 }
140 }
141 }
142 };
143}
144
145#[cfg(test)]
146mod test {
147 #[derive(Debug, serde::Serialize, serde::Deserialize)]
148 struct Test {
149 field: String,
150 }
151
152 json_literal!(Test);
153
154 #[test]
155 fn json_literal_macro_accepts_a_serde_type() {
156 let test = Test {
157 field: "value".to_owned(),
158 };
159 assert_eq!(test.field, "value");
160 }
161}