oxirs_core/model/
graph.rs1use crate::model::{Object, Predicate, Subject, Triple, TripleRef};
4use std::collections::HashSet;
5use std::iter::FromIterator;
6
7#[derive(Debug, Clone, PartialEq, Eq)]
50pub struct Graph {
51 triples: HashSet<Triple>,
52}
53
54impl Graph {
55 pub fn new() -> Self {
67 Graph {
68 triples: HashSet::new(),
69 }
70 }
71
72 pub fn with_capacity(capacity: usize) -> Self {
91 Graph {
92 triples: HashSet::with_capacity(capacity),
93 }
94 }
95
96 pub fn from_triples(triples: Vec<Triple>) -> Self {
126 Graph {
127 triples: triples.into_iter().collect(),
128 }
129 }
130
131 pub fn insert(&mut self, triple: Triple) -> bool {
135 self.triples.insert(triple)
136 }
137
138 pub fn remove(&mut self, triple: &Triple) -> bool {
142 self.triples.remove(triple)
143 }
144
145 pub fn contains(&self, triple: &Triple) -> bool {
147 self.triples.contains(triple)
148 }
149
150 pub fn len(&self) -> usize {
152 self.triples.len()
153 }
154
155 pub fn is_empty(&self) -> bool {
157 self.triples.is_empty()
158 }
159
160 pub fn clear(&mut self) {
162 self.triples.clear();
163 }
164
165 pub fn iter(&self) -> impl Iterator<Item = &Triple> {
167 self.triples.iter()
168 }
169
170 pub fn iter_ref(&self) -> impl Iterator<Item = TripleRef<'_>> {
172 self.triples.iter().map(|t| t.into())
173 }
174
175 pub fn triples_for_pattern<'a>(
179 &'a self,
180 subject: Option<&'a Subject>,
181 predicate: Option<&'a Predicate>,
182 object: Option<&'a Object>,
183 ) -> impl Iterator<Item = &'a Triple> {
184 self.triples.iter().filter(move |triple| {
185 if let Some(s) = subject {
186 if triple.subject() != s {
187 return false;
188 }
189 }
190 if let Some(p) = predicate {
191 if triple.predicate() != p {
192 return false;
193 }
194 }
195 if let Some(o) = object {
196 if triple.object() != o {
197 return false;
198 }
199 }
200 true
201 })
202 }
203
204 pub fn triples_for_subject<'a>(
206 &'a self,
207 subject: &'a Subject,
208 ) -> impl Iterator<Item = &'a Triple> {
209 self.triples_for_pattern(Some(subject), None, None)
210 }
211
212 pub fn triples_for_predicate<'a>(
214 &'a self,
215 predicate: &'a Predicate,
216 ) -> impl Iterator<Item = &'a Triple> {
217 self.triples_for_pattern(None, Some(predicate), None)
218 }
219
220 pub fn triples_for_object<'a>(
222 &'a self,
223 object: &'a Object,
224 ) -> impl Iterator<Item = &'a Triple> {
225 self.triples_for_pattern(None, None, Some(object))
226 }
227
228 pub fn triples_for_subject_predicate<'a>(
230 &'a self,
231 subject: &'a Subject,
232 predicate: &'a Predicate,
233 ) -> impl Iterator<Item = &'a Triple> {
234 self.triples_for_pattern(Some(subject), Some(predicate), None)
235 }
236
237 pub fn extend<I>(&mut self, triples: I)
239 where
240 I: IntoIterator<Item = Triple>,
241 {
242 self.triples.extend(triples);
243 }
244
245 pub fn retain<F>(&mut self, f: F)
247 where
248 F: FnMut(&Triple) -> bool,
249 {
250 self.triples.retain(f);
251 }
252
253 pub fn union(&self, other: &Graph) -> Graph {
255 let mut result = self.clone();
256 result.triples.extend(other.triples.iter().cloned());
257 result
258 }
259
260 pub fn intersection(&self, other: &Graph) -> Graph {
262 Graph {
263 triples: self.triples.intersection(&other.triples).cloned().collect(),
264 }
265 }
266
267 pub fn difference(&self, other: &Graph) -> Graph {
269 Graph {
270 triples: self.triples.difference(&other.triples).cloned().collect(),
271 }
272 }
273
274 pub fn is_subset(&self, other: &Graph) -> bool {
276 self.triples.is_subset(&other.triples)
277 }
278
279 pub fn is_superset(&self, other: &Graph) -> bool {
281 self.triples.is_superset(&other.triples)
282 }
283
284 pub fn is_disjoint(&self, other: &Graph) -> bool {
286 self.triples.is_disjoint(&other.triples)
287 }
288}
289
290impl Default for Graph {
291 fn default() -> Self {
292 Self::new()
293 }
294}
295
296impl FromIterator<Triple> for Graph {
297 fn from_iter<T: IntoIterator<Item = Triple>>(iter: T) -> Self {
298 Graph {
299 triples: HashSet::from_iter(iter),
300 }
301 }
302}
303
304impl Extend<Triple> for Graph {
305 fn extend<T: IntoIterator<Item = Triple>>(&mut self, iter: T) {
306 self.triples.extend(iter);
307 }
308}
309
310impl IntoIterator for Graph {
311 type Item = Triple;
312 type IntoIter = std::collections::hash_set::IntoIter<Triple>;
313
314 fn into_iter(self) -> Self::IntoIter {
315 self.triples.into_iter()
316 }
317}
318
319impl<'a> IntoIterator for &'a Graph {
320 type Item = &'a Triple;
321 type IntoIter = std::collections::hash_set::Iter<'a, Triple>;
322
323 fn into_iter(self) -> Self::IntoIter {
324 self.triples.iter()
325 }
326}
327
328#[cfg(test)]
329mod tests {
330 use super::*;
331 use crate::model::{Literal, NamedNode};
332
333 fn create_test_triple() -> Triple {
334 let subject = NamedNode::new("http://example.org/subject").expect("valid IRI");
335 let predicate = NamedNode::new("http://example.org/predicate").expect("valid IRI");
336 let object = Literal::new("object");
337 Triple::new(subject, predicate, object)
338 }
339
340 #[test]
341 fn test_graph_basic_operations() {
342 let mut graph = Graph::new();
343 let triple = create_test_triple();
344
345 assert!(graph.is_empty());
346 assert_eq!(graph.len(), 0);
347
348 assert!(graph.insert(triple.clone()));
349 assert!(!graph.is_empty());
350 assert_eq!(graph.len(), 1);
351 assert!(graph.contains(&triple));
352
353 assert!(!graph.insert(triple.clone())); assert_eq!(graph.len(), 1);
355
356 assert!(graph.remove(&triple));
357 assert!(graph.is_empty());
358 assert_eq!(graph.len(), 0);
359 assert!(!graph.contains(&triple));
360 }
361
362 #[test]
363 fn test_graph_iteration() {
364 let mut graph = Graph::new();
365 let triple1 = create_test_triple();
366
367 let subject2 = NamedNode::new("http://example.org/subject2").expect("valid IRI");
368 let predicate2 = NamedNode::new("http://example.org/predicate2").expect("valid IRI");
369 let object2 = Literal::new("object2");
370 let triple2 = Triple::new(subject2, predicate2, object2);
371
372 graph.insert(triple1.clone());
373 graph.insert(triple2.clone());
374
375 let mut collected: Vec<_> = graph.iter().cloned().collect();
376 collected.sort_by_key(|t| format!("{t}"));
377
378 assert_eq!(collected.len(), 2);
379 assert!(collected.contains(&triple1));
380 assert!(collected.contains(&triple2));
381 }
382
383 #[test]
384 fn test_graph_pattern_matching() {
385 let mut graph = Graph::new();
386
387 let subject = NamedNode::new("http://example.org/subject").expect("valid IRI");
388 let predicate1 = NamedNode::new("http://example.org/predicate1").expect("valid IRI");
389 let predicate2 = NamedNode::new("http://example.org/predicate2").expect("valid IRI");
390 let object1 = Literal::new("object1");
391 let object2 = Literal::new("object2");
392
393 let triple1 = Triple::new(subject.clone(), predicate1.clone(), object1);
394 let triple2 = Triple::new(subject.clone(), predicate2, object2);
395
396 graph.insert(triple1.clone());
397 graph.insert(triple2.clone());
398
399 let by_subject: Vec<_> = graph
401 .triples_for_subject(&Subject::NamedNode(subject.clone()))
402 .cloned()
403 .collect();
404 assert_eq!(by_subject.len(), 2);
405
406 let by_predicate: Vec<_> = graph
408 .triples_for_predicate(&Predicate::NamedNode(predicate1))
409 .cloned()
410 .collect();
411 assert_eq!(by_predicate.len(), 1);
412 assert_eq!(by_predicate[0], triple1);
413 }
414
415 #[test]
416 fn test_graph_set_operations() {
417 let mut graph1 = Graph::new();
418 let mut graph2 = Graph::new();
419
420 let triple1 = create_test_triple();
421 let subject2 = NamedNode::new("http://example.org/subject2").expect("valid IRI");
422 let predicate2 = NamedNode::new("http://example.org/predicate2").expect("valid IRI");
423 let object2 = Literal::new("object2");
424 let triple2 = Triple::new(subject2, predicate2, object2);
425
426 graph1.insert(triple1.clone());
427 graph2.insert(triple1.clone());
428 graph2.insert(triple2.clone());
429
430 let union = graph1.union(&graph2);
431 assert_eq!(union.len(), 2);
432
433 let intersection = graph1.intersection(&graph2);
434 assert_eq!(intersection.len(), 1);
435 assert!(intersection.contains(&triple1));
436
437 assert!(graph1.is_subset(&graph2));
438 assert!(!graph1.is_superset(&graph2));
439 assert!(graph2.is_superset(&graph1));
440 }
441}