1use crate::object::{FragmentRef, InvalidExpandedJson, Traverse};
2use crate::{Id, Indexed, IndexedObject, Node, Object, Relabel, TryFromJson};
3use hashbrown::HashMap;
4use indexmap::IndexSet;
5use iref::IriBuf;
6use rdf_types::vocabulary::VocabularyMut;
7use rdf_types::{BlankIdBuf, Generator, Vocabulary};
8use std::collections::HashSet;
9use std::hash::Hash;
10
11#[derive(Debug, Clone)]
15pub struct ExpandedDocument<T = IriBuf, B = BlankIdBuf>(IndexSet<IndexedObject<T, B>>);
16
17impl<T, B> Default for ExpandedDocument<T, B> {
18 #[inline(always)]
19 fn default() -> Self {
20 Self(IndexSet::new())
21 }
22}
23
24impl<T, B> ExpandedDocument<T, B> {
25 #[inline(always)]
26 pub fn new() -> Self {
27 Self::default()
28 }
29
30 #[inline(always)]
31 pub fn len(&self) -> usize {
32 self.0.len()
33 }
34
35 #[inline(always)]
36 pub fn is_empty(&self) -> bool {
37 self.0.is_empty()
38 }
39
40 #[inline(always)]
41 pub fn objects(&self) -> &IndexSet<IndexedObject<T, B>> {
42 &self.0
43 }
44
45 #[inline(always)]
46 pub fn into_objects(self) -> IndexSet<IndexedObject<T, B>> {
47 self.0
48 }
49
50 #[inline(always)]
51 pub fn iter(&self) -> indexmap::set::Iter<'_, IndexedObject<T, B>> {
52 self.0.iter()
53 }
54
55 #[inline(always)]
56 pub fn traverse(&self) -> Traverse<T, B> {
57 Traverse::new(self.iter().map(|o| FragmentRef::IndexedObject(o)))
58 }
59
60 #[inline(always)]
61 pub fn count(&self, f: impl FnMut(&FragmentRef<T, B>) -> bool) -> usize {
62 self.traverse().filter(f).count()
63 }
64
65 #[inline(always)]
68 pub fn identify_all_with<V: Vocabulary<Iri = T, BlankId = B>, G: Generator<V>>(
69 &mut self,
70 vocabulary: &mut V,
71 generator: &mut G,
72 ) where
73 T: Eq + Hash,
74 B: Eq + Hash,
75 {
76 let objects = std::mem::take(&mut self.0);
77 for mut object in objects {
78 object.identify_all_with(vocabulary, generator);
79 self.0.insert(object);
80 }
81 }
82
83 #[inline(always)]
86 pub fn identify_all<G: Generator>(&mut self, generator: &mut G)
87 where
88 T: Eq + Hash,
89 B: Eq + Hash,
90 (): Vocabulary<Iri = T, BlankId = B>,
91 {
92 self.identify_all_with(&mut (), generator)
93 }
94
95 #[inline(always)]
99 pub fn relabel_and_canonicalize_with<V: Vocabulary<Iri = T, BlankId = B>, G: Generator<V>>(
100 &mut self,
101 vocabulary: &mut V,
102 generator: &mut G,
103 ) where
104 T: Clone + Eq + Hash,
105 B: Clone + Eq + Hash,
106 {
107 let objects = std::mem::take(&mut self.0);
108 let mut relabeling = HashMap::new();
109 let mut buffer = ryu_js::Buffer::new();
110 for mut object in objects {
111 object.relabel_with(vocabulary, generator, &mut relabeling);
112 object.canonicalize_with(&mut buffer);
113 self.0.insert(object);
114 }
115 }
116
117 #[inline(always)]
121 pub fn relabel_and_canonicalize<G: Generator>(&mut self, generator: &mut G)
122 where
123 T: Clone + Eq + Hash,
124 B: Clone + Eq + Hash,
125 (): Vocabulary<Iri = T, BlankId = B>,
126 {
127 self.relabel_and_canonicalize_with(&mut (), generator)
128 }
129
130 #[inline(always)]
132 pub fn relabel_with<V: Vocabulary<Iri = T, BlankId = B>, G: Generator<V>>(
133 &mut self,
134 vocabulary: &mut V,
135 generator: &mut G,
136 ) where
137 T: Clone + Eq + Hash,
138 B: Clone + Eq + Hash,
139 {
140 let objects = std::mem::take(&mut self.0);
141 let mut relabeling = HashMap::new();
142 for mut object in objects {
143 object.relabel_with(vocabulary, generator, &mut relabeling);
144 self.0.insert(object);
145 }
146 }
147
148 #[inline(always)]
150 pub fn relabel<G: Generator>(&mut self, generator: &mut G)
151 where
152 T: Clone + Eq + Hash,
153 B: Clone + Eq + Hash,
154 (): Vocabulary<Iri = T, BlankId = B>,
155 {
156 self.relabel_with(&mut (), generator)
157 }
158
159 pub fn canonicalize_with(&mut self, buffer: &mut ryu_js::Buffer)
164 where
165 T: Eq + Hash,
166 B: Eq + Hash,
167 {
168 let objects = std::mem::take(&mut self.0);
169 for mut object in objects {
170 object.canonicalize_with(buffer);
171 self.0.insert(object);
172 }
173 }
174
175 pub fn canonicalize(&mut self)
177 where
178 T: Eq + Hash,
179 B: Eq + Hash,
180 {
181 let mut buffer = ryu_js::Buffer::new();
182 self.canonicalize_with(&mut buffer)
183 }
184
185 pub fn map_ids<U, C>(
187 self,
188 mut map_iri: impl FnMut(T) -> U,
189 mut map_id: impl FnMut(Id<T, B>) -> Id<U, C>,
190 ) -> ExpandedDocument<U, C>
191 where
192 U: Eq + Hash,
193 C: Eq + Hash,
194 {
195 ExpandedDocument(
196 self.0
197 .into_iter()
198 .map(|i| i.map_inner(|o| o.map_ids(&mut map_iri, &mut map_id)))
199 .collect(),
200 )
201 }
202
203 pub fn blank_ids(&self) -> HashSet<&B>
205 where
206 B: Eq + Hash,
207 {
208 self.traverse()
209 .filter_map(|f| f.into_id().and_then(Id::into_blank))
210 .collect()
211 }
212
213 pub fn main_node(&self) -> Option<&Node<T, B>> {
218 let mut result = None;
219
220 for object in self {
221 if let Object::Node(node) = object.inner() {
222 if result.is_some() {
223 return None;
224 }
225
226 result = Some(&**node)
227 }
228 }
229
230 result
231 }
232
233 pub fn into_main_node(self) -> Option<Node<T, B>> {
238 let mut result = None;
239
240 for object in self {
241 if let Object::Node(node) = object.into_inner() {
242 if result.is_some() {
243 return None;
244 }
245
246 result = Some(*node)
247 }
248 }
249
250 result
251 }
252}
253
254impl<T: Hash + Eq, B: Hash + Eq> ExpandedDocument<T, B> {
255 #[inline(always)]
256 pub fn insert(&mut self, object: IndexedObject<T, B>) -> bool {
257 self.0.insert(object)
258 }
259}
260
261impl<T: Eq + Hash, B: Eq + Hash> From<Indexed<Node<T, B>>> for ExpandedDocument<T, B> {
262 fn from(value: Indexed<Node<T, B>>) -> Self {
263 let mut result = Self::default();
264
265 result.insert(value.map_inner(Object::node));
266
267 result
268 }
269}
270
271impl<T: Eq + Hash, B: Eq + Hash> TryFromJson<T, B> for ExpandedDocument<T, B> {
272 fn try_from_json_in(
273 vocabulary: &mut impl VocabularyMut<Iri = T, BlankId = B>,
274 value: json_syntax::Value,
275 ) -> Result<Self, InvalidExpandedJson> {
276 match value {
277 json_syntax::Value::Array(items) => {
278 let mut result = Self::new();
279
280 for item in items {
281 result.insert(Indexed::try_from_json_in(vocabulary, item)?);
282 }
283
284 Ok(result)
285 }
286 other => Err(InvalidExpandedJson::Unexpected(
287 other.kind(),
288 json_syntax::Kind::Array,
289 )),
290 }
291 }
292}
293
294impl<T: Eq + Hash, B: Eq + Hash> PartialEq for ExpandedDocument<T, B> {
295 fn eq(&self, other: &Self) -> bool {
297 self.0.eq(&other.0)
298 }
299}
300
301impl<T: Eq + Hash, B: Eq + Hash> Eq for ExpandedDocument<T, B> {}
302
303impl<T, B> IntoIterator for ExpandedDocument<T, B> {
304 type IntoIter = IntoIter<T, B>;
305 type Item = IndexedObject<T, B>;
306
307 #[inline(always)]
308 fn into_iter(self) -> Self::IntoIter {
309 IntoIter(self.0.into_iter())
310 }
311}
312
313impl<'a, T, B> IntoIterator for &'a ExpandedDocument<T, B> {
314 type IntoIter = indexmap::set::Iter<'a, IndexedObject<T, B>>;
315 type Item = &'a IndexedObject<T, B>;
316
317 #[inline(always)]
318 fn into_iter(self) -> Self::IntoIter {
319 self.iter()
320 }
321}
322pub struct IntoIter<T, B>(indexmap::set::IntoIter<IndexedObject<T, B>>);
323
324impl<T, B> Iterator for IntoIter<T, B> {
325 type Item = IndexedObject<T, B>;
326
327 fn next(&mut self) -> Option<Self::Item> {
328 self.0.next()
329 }
330}
331
332impl<T: Hash + Eq, B: Hash + Eq> FromIterator<IndexedObject<T, B>> for ExpandedDocument<T, B> {
333 fn from_iter<I: IntoIterator<Item = IndexedObject<T, B>>>(iter: I) -> Self {
334 Self(iter.into_iter().collect())
335 }
336}
337
338impl<T: Hash + Eq, B: Hash + Eq> Extend<IndexedObject<T, B>> for ExpandedDocument<T, B> {
339 fn extend<I: IntoIterator<Item = IndexedObject<T, B>>>(&mut self, iter: I) {
340 self.0.extend(iter)
341 }
342}
343
344impl<T, B> From<IndexSet<IndexedObject<T, B>>> for ExpandedDocument<T, B> {
345 fn from(set: IndexSet<IndexedObject<T, B>>) -> Self {
346 Self(set)
347 }
348}