Skip to main content

jsonld_serialization/expanded/
object.rs

1use std::hash::Hash;
2
3use jsonld_core::{
4    Indexed,
5    IndexedObject,
6    Node,
7    Object,
8    object::{
9        Graph,
10        List,
11        node::{Included, Multiset, Properties, ReverseProperties},
12    },
13    rdf::{RDF_FIRST, RDF_REST, RDF_TYPE},
14};
15use ld_core::{CowRdfTerm, LinkedDataResource, OwnedRdfTerm};
16use rdfx::{
17    Interpretation,
18    interpretation::{ReverseInterpretation, ReverseLocalInterpretation},
19    vocabulary::Vocabulary,
20};
21
22use crate::Error;
23
24use super::{
25    graph::SerializeGraph,
26    list::{SerializeListFirst, SerializeListRest},
27    node::{SerializeNode, into_type_value, is_iri},
28    property::{SerializeProperty, SerializeReverseProperty},
29    serialize_node_with,
30    value::literal_to_value,
31};
32
33/// Serialize the given Linked-Data value into a JSON-LD object using a
34/// custom vocabulary and interpretation.
35///
36/// # Errors
37///
38/// Returns an error when the value cannot be expressed as a JSON-LD object.
39pub fn serialize_object_with<I, V, T>(vocabulary: &mut V, interpretation: &mut I, value: &T) -> Result<Object<V::Iri, V::BlankId>, Error>
40where
41    V: Vocabulary + rdfx::vocabulary::VocabularyMut,
42    V::Iri: Clone + Eq + Hash,
43    V::BlankId: Clone + Eq + Hash,
44    I: ReverseInterpretation + ReverseLocalInterpretation,
45    T: ?Sized + LinkedDataResource<I> + ld_core::LinkedDataSubject<I>,
46{
47    match value.lexical_representation(interpretation).map(CowRdfTerm::into_owned) {
48        Some(OwnedRdfTerm::Literal(lit)) => {
49            let value = literal_to_value(vocabulary, lit);
50            Ok(Object::Value(value))
51        }
52        Some(OwnedRdfTerm::Iri(iri)) => {
53            let id = jsonld_core::Id::Valid(jsonld_core::ValidId::Iri(vocabulary.insert_owned(iri)));
54            let serializer = SerializeNode::new(vocabulary, interpretation, Some(id));
55
56            Ok(Object::node(value.visit_subject(serializer)?))
57        }
58        Some(OwnedRdfTerm::BlankId(b)) => {
59            let id = jsonld_core::Id::Valid(jsonld_core::ValidId::Blank(vocabulary.insert_owned_blank_id(b)));
60            let serializer = SerializeNode::new(vocabulary, interpretation, Some(id));
61
62            Ok(Object::node(value.visit_subject(serializer)?))
63        }
64        None => {
65            let serializer = SerializeObject::new(vocabulary, interpretation);
66
67            value.visit_subject(serializer)
68        }
69    }
70}
71
72pub struct SerializeObject<'a, I, V: Vocabulary> {
73    vocabulary: &'a mut V,
74    interpretation: &'a mut I,
75    types: Vec<jsonld_core::Id<V::Iri, V::BlankId>>,
76    properties: Properties<V::Iri, V::BlankId>,
77    reverse_properties: ReverseProperties<V::Iri, V::BlankId>,
78    included: Included<V::Iri, V::BlankId>,
79    graph: Option<Graph<V::Iri, V::BlankId>>,
80    first: Option<Object<V::Iri, V::BlankId>>,
81    rest: Option<Vec<IndexedObject<V::Iri, V::BlankId>>>,
82}
83
84impl<'a, I, V: Vocabulary> SerializeObject<'a, I, V> {
85    pub fn new(vocabulary: &'a mut V, interpretation: &'a mut I) -> Self {
86        Self {
87            vocabulary,
88            interpretation,
89            types: Vec::new(),
90            properties: Properties::new(),
91            reverse_properties: ReverseProperties::new(),
92            included: Included::default(),
93            graph: None,
94            first: None,
95            rest: None,
96        }
97    }
98}
99
100impl<I: Interpretation, V: Vocabulary> ld_core::SubjectVisitor<I> for SerializeObject<'_, I, V>
101where
102    V: rdfx::vocabulary::VocabularyMut,
103    V::Iri: Clone + Eq + Hash,
104    V::BlankId: Clone + Eq + Hash,
105    I: ReverseInterpretation + ReverseLocalInterpretation,
106{
107    type Ok = Object<V::Iri, V::BlankId>;
108    type Error = Error;
109
110    fn predicate<L, T>(&mut self, predicate: &L, value: &T) -> Result<(), Self::Error>
111    where
112        L: ?Sized + LinkedDataResource<I>,
113        T: ?Sized + ld_core::LinkedDataPredicateObjects<I>,
114    {
115        let prop = match predicate.lexical_representation(self.interpretation).map(CowRdfTerm::into_owned) {
116            Some(OwnedRdfTerm::Iri(iri)) => {
117                if iri.as_ref() == RDF_FIRST {
118                    let serializer = SerializeListFirst::new(self.vocabulary, self.interpretation);
119                    self.first = value.visit_objects(serializer)?;
120                } else if iri.as_ref() == RDF_REST {
121                    let serializer = SerializeListRest::new(self.vocabulary, self.interpretation);
122                    self.rest = Some(value.visit_objects(serializer)?);
123                }
124
125                jsonld_core::Id::Valid(jsonld_core::ValidId::Iri(self.vocabulary.insert_owned(iri)))
126            }
127            Some(OwnedRdfTerm::BlankId(b)) => jsonld_core::Id::Valid(jsonld_core::ValidId::Blank(self.vocabulary.insert_owned_blank_id(b))),
128            _ => return Err(Error::InvalidPredicate),
129        };
130
131        let serializer = SerializeProperty::new(self.vocabulary, self.interpretation);
132
133        let objects = value.visit_objects(serializer)?;
134
135        if is_iri(self.vocabulary, &prop, RDF_TYPE) {
136            let mut non_iri_objects = Multiset::new();
137
138            for obj in objects {
139                match into_type_value(obj) {
140                    Ok(ty) => self.types.push(ty),
141                    Err(obj) => {
142                        non_iri_objects.insert(obj);
143                    }
144                }
145            }
146
147            if !non_iri_objects.is_empty() {
148                self.properties.set(prop, non_iri_objects);
149            }
150        } else {
151            self.properties.set(prop, objects);
152        }
153
154        Ok(())
155    }
156
157    fn reverse_predicate<L, T>(&mut self, predicate: &L, value: &T) -> Result<(), Self::Error>
158    where
159        L: ?Sized + LinkedDataResource<I>,
160        T: ?Sized + ld_core::LinkedDataPredicateObjects<I>,
161    {
162        let prop = match predicate.lexical_representation(self.interpretation).map(CowRdfTerm::into_owned) {
163            Some(OwnedRdfTerm::Iri(iri)) => jsonld_core::Id::Valid(jsonld_core::ValidId::Iri(self.vocabulary.insert_owned(iri))),
164            Some(OwnedRdfTerm::BlankId(b)) => jsonld_core::Id::Valid(jsonld_core::ValidId::Blank(self.vocabulary.insert_owned_blank_id(b))),
165            _ => return Err(Error::InvalidPredicate),
166        };
167
168        let serializer = SerializeReverseProperty::new(self.vocabulary, self.interpretation);
169
170        let objects = value.visit_objects(serializer)?;
171        self.reverse_properties.set(prop, objects);
172
173        Ok(())
174    }
175
176    fn include<T>(&mut self, value: &T) -> Result<(), Self::Error>
177    where
178        T: ?Sized + LinkedDataResource<I> + ld_core::LinkedDataSubject<I>,
179    {
180        let node = serialize_node_with(self.vocabulary, self.interpretation, value)?;
181        self.included.push(Indexed::none(node));
182        Ok(())
183    }
184
185    fn graph<T>(&mut self, value: &T) -> Result<(), Self::Error>
186    where
187        T: ?Sized + ld_core::LinkedDataGraph<I>,
188    {
189        let serializer = SerializeGraph::new(self.vocabulary, self.interpretation);
190        self.graph = Some(value.visit_graph(serializer)?);
191        Ok(())
192    }
193
194    fn end(mut self) -> Result<Self::Ok, Self::Error> {
195        if let (Some(first), Some(mut items)) = (self.first.take(), self.rest.take()) {
196            if self.types.is_empty() && self.properties.is_empty() && self.graph.is_none() {
197                items.push(Indexed::none(first));
198                items.reverse();
199                return Ok(Object::List(List::new(items)));
200            }
201            // restore moved values for the fallthrough path
202            self.first = Some(first);
203            self.rest = Some(items);
204        }
205        {
206            if let Some(item) = self.first {
207                let iri = self.vocabulary.insert(RDF_FIRST);
208                self.properties
209                    .insert(jsonld_core::Id::Valid(jsonld_core::ValidId::Iri(iri)), Indexed::none(item));
210            }
211
212            if let Some(rest) = self.rest {
213                let iri = self.vocabulary.insert(RDF_REST);
214                self.properties.insert(
215                    jsonld_core::Id::Valid(jsonld_core::ValidId::Iri(iri)),
216                    Indexed::none(Object::List(List::new(rest))),
217                );
218            }
219
220            let mut node = Node::new();
221
222            if !self.types.is_empty() {
223                node.types = Some(self.types);
224            }
225
226            *node.properties_mut() = self.properties;
227
228            if !self.reverse_properties.is_empty() {
229                node.set_reverse_properties(Some(self.reverse_properties));
230            }
231
232            if !self.included.is_empty() {
233                node.set_included(Some(self.included));
234            }
235
236            node.graph = self.graph;
237
238            Ok(Object::node(node))
239        }
240    }
241}