diff --git a/CHANGELOG.md b/CHANGELOG.md index 66236f91..47ec5195 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - `QueryOptions::with_named_graph` now takes an `impl Into` instead of an `impl Into`. - `pyoxigraph` `query` methods now takes two new parameters, `default_graph` and `named_graphs`. `default_graph_uris` and `named_graph_uris` parameters are deprecated. - Fixes a bug in `xsd:gYear` parsing. +- Adds explicit types for quads iterators returned by stores. ## [0.1.0] - 2020-08-09 diff --git a/lib/src/store/memory.rs b/lib/src/store/memory.rs index 5333da3e..ec0c586e 100644 --- a/lib/src/store/memory.rs +++ b/lib/src/store/memory.rs @@ -175,7 +175,7 @@ impl MemoryStore { predicate: Option>, object: Option>, graph_name: Option>, - ) -> impl Iterator { + ) -> MemoryQuadIter { let quads = if let Some((subject, predicate, object, graph_name)) = get_encoded_quad_pattern(self, subject, predicate, object, graph_name) .unwrap_infallible() @@ -184,10 +184,18 @@ impl MemoryStore { } else { Vec::new() }; - let this = self.clone(); - quads.into_iter().map( - move |quad| this.decode_quad(&quad).unwrap(), // Could not fail - ) + MemoryQuadIter { + iter: quads.into_iter(), + store: self.clone(), + } + } + + /// Returns all the quads contained in the store + pub fn iter(&self) -> MemoryQuadIter { + MemoryQuadIter { + iter: self.encoded_quads().into_iter(), + store: self.clone(), + } } /// Checks if this store contains a given quad @@ -424,11 +432,7 @@ impl MemoryStore { /// # std::io::Result::Ok(()) /// ``` pub fn dump_dataset(&self, writer: impl Write, format: DatasetFormat) -> Result<(), io::Error> { - dump_dataset( - self.quads_for_pattern(None, None, None, None).map(Ok), - writer, - format, - ) + dump_dataset(self.iter().map(Ok), writer, format) } #[allow(clippy::expect_used)] @@ -1222,9 +1226,27 @@ impl Extend for MemoryStore { } } +impl IntoIterator for MemoryStore { + type Item = Quad; + type IntoIter = MemoryQuadIter; + + fn into_iter(self) -> MemoryQuadIter { + self.iter() + } +} + +impl<'a> IntoIterator for &'a MemoryStore { + type Item = Quad; + type IntoIter = MemoryQuadIter; + + fn into_iter(self) -> MemoryQuadIter { + self.iter() + } +} + impl fmt::Display for MemoryStore { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - for t in self.quads_for_pattern(None, None, None, None) { + for t in self { writeln!(f, "{}", t)?; } Ok(()) @@ -1254,6 +1276,24 @@ impl Iterator for EncodedQuadsIter { } } +/// An iterator returning the quads contained in a [`MemoryStore`](struct.MemoryStore.html). +pub struct MemoryQuadIter { + iter: IntoIter, + store: MemoryStore, +} + +impl Iterator for MemoryQuadIter { + type Item = Quad; + + fn next(&mut self) -> Option { + Some(self.store.decode_quad(&self.iter.next()?).unwrap()) + } + + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + impl StrId for LargeSpur {} // Isomorphism implementation diff --git a/lib/src/store/rocksdb.rs b/lib/src/store/rocksdb.rs index bd23aee9..d28877a1 100644 --- a/lib/src/store/rocksdb.rs +++ b/lib/src/store/rocksdb.rs @@ -155,17 +155,24 @@ impl RocksDbStore { predicate: Option>, object: Option>, graph_name: Option>, - ) -> impl Iterator> { - match get_encoded_quad_pattern(self, subject, predicate, object, graph_name) { - Ok(Some((subject, predicate, object, graph_name))) => QuadsIter::Quads { - iter: self.encoded_quads_for_pattern(subject, predicate, object, graph_name), - store: self.clone(), + ) -> RocksDbQuadIter { + RocksDbQuadIter { + inner: match get_encoded_quad_pattern(self, subject, predicate, object, graph_name) { + Ok(Some((subject, predicate, object, graph_name))) => QuadIterInner::Quads { + iter: self.encoded_quads_for_pattern(subject, predicate, object, graph_name), + store: self.clone(), + }, + Ok(None) => QuadIterInner::Empty, + Err(error) => QuadIterInner::Error(once(error)), }, - Ok(None) => QuadsIter::Empty, - Err(error) => QuadsIter::Error(once(error)), } } + /// Returns all the quads contained in the store + pub fn iter(&self) -> RocksDbQuadIter { + self.quads_for_pattern(None, None, None, None) + } + /// Checks if this store contains a given quad pub fn contains<'a>(&self, quad: impl Into>) -> Result { if let Some(quad) = self.get_encoded_quad(quad.into())? { @@ -318,11 +325,7 @@ impl RocksDbStore { /// /// See [`MemoryStore`](../memory/struct.MemoryStore.html#method.dump_dataset) for a usage example. pub fn dump_dataset(&self, writer: impl Write, syntax: DatasetFormat) -> Result<(), io::Error> { - dump_dataset( - self.quads_for_pattern(None, None, None, None), - writer, - syntax, - ) + dump_dataset(self.iter(), writer, syntax) } fn id2str_cf(&self) -> &ColumnFamily { @@ -617,7 +620,7 @@ impl RocksDbStore { impl fmt::Display for RocksDbStore { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - for t in self.quads_for_pattern(None, None, None, None) { + for t in self.iter() { writeln!(f, "{}", t.map_err(|_| fmt::Error)?)?; } Ok(()) @@ -1161,7 +1164,12 @@ fn map_err(e: Error) -> io::Error { io::Error::new(io::ErrorKind::Other, e) } -enum QuadsIter { +/// An iterator returning the quads contained in a [`RocksDbStore`](struct.RocksDbStore.html). +pub struct RocksDbQuadIter { + inner: QuadIterInner, +} + +enum QuadIterInner { Quads { iter: DecodingIndexesIterator, store: RocksDbStore, @@ -1170,17 +1178,17 @@ enum QuadsIter { Empty, } -impl Iterator for QuadsIter { +impl Iterator for RocksDbQuadIter { type Item = Result; fn next(&mut self) -> Option> { - match self { - Self::Quads { iter, store } => Some(match iter.next()? { + match &mut self.inner { + QuadIterInner::Quads { iter, store } => Some(match iter.next()? { Ok(quad) => store.decode_quad(&quad).map_err(|e| e.into()), Err(error) => Err(error), }), - Self::Error(iter) => iter.next().map(Err), - Self::Empty => None, + QuadIterInner::Error(iter) => iter.next().map(Err), + QuadIterInner::Empty => None, } } } @@ -1242,12 +1250,7 @@ fn store() -> Result<(), io::Error> { })?; assert_eq!(store.len(), 4); - assert_eq!( - store - .quads_for_pattern(None, None, None, None) - .collect::, _>>()?, - all_quads - ); + assert_eq!(store.iter().collect::, _>>()?, all_quads); assert_eq!( store .quads_for_pattern(Some(main_s.as_ref()), None, None, None) diff --git a/lib/src/store/sled.rs b/lib/src/store/sled.rs index d65ab250..0b283a67 100644 --- a/lib/src/store/sled.rs +++ b/lib/src/store/sled.rs @@ -164,17 +164,24 @@ impl SledStore { predicate: Option>, object: Option>, graph_name: Option>, - ) -> impl Iterator> { - match get_encoded_quad_pattern(self, subject, predicate, object, graph_name) { - Ok(Some((subject, predicate, object, graph_name))) => QuadsIter::Quads { - iter: self.encoded_quads_for_pattern(subject, predicate, object, graph_name), - store: self.clone(), + ) -> SledQuadIter { + SledQuadIter { + inner: match get_encoded_quad_pattern(self, subject, predicate, object, graph_name) { + Ok(Some((subject, predicate, object, graph_name))) => QuadIterInner::Quads { + iter: self.encoded_quads_for_pattern(subject, predicate, object, graph_name), + store: self.clone(), + }, + Ok(None) => QuadIterInner::Empty, + Err(error) => QuadIterInner::Error(once(error)), }, - Ok(None) => QuadsIter::Empty, - Err(error) => QuadsIter::Error(once(error)), } } + /// Returns all the quads contained in the store + pub fn iter(&self) -> SledQuadIter { + self.quads_for_pattern(None, None, None, None) + } + /// Checks if this store contains a given quad pub fn contains<'a>(&self, quad: impl Into>) -> Result { if let Some(quad) = self.get_encoded_quad(quad.into())? { @@ -352,11 +359,7 @@ impl SledStore { /// /// See [`MemoryStore`](../memory/struct.MemoryStore.html#method.dump_dataset) for a usage example. pub fn dump_dataset(&self, writer: impl Write, format: DatasetFormat) -> Result<(), io::Error> { - dump_dataset( - self.quads_for_pattern(None, None, None, None), - writer, - format, - ) + dump_dataset(self.iter(), writer, format) } fn contains_encoded(&self, quad: &EncodedQuad) -> Result { @@ -590,7 +593,7 @@ impl SledStore { impl fmt::Display for SledStore { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - for t in self.quads_for_pattern(None, None, None, None) { + for t in self.iter() { writeln!(f, "{}", t.map_err(|_| fmt::Error)?)?; } Ok(()) @@ -1217,7 +1220,12 @@ impl Iterator for DecodingQuadIterator { } } -enum QuadsIter { +/// An iterator returning the quads contained in a [`SledStore`](struct.SledStore.html). +pub struct SledQuadIter { + inner: QuadIterInner, +} + +enum QuadIterInner { Quads { iter: DecodingQuadsIterator, store: SledStore, @@ -1226,17 +1234,17 @@ enum QuadsIter { Empty, } -impl Iterator for QuadsIter { +impl Iterator for SledQuadIter { type Item = Result; fn next(&mut self) -> Option> { - match self { - Self::Quads { iter, store } => Some(match iter.next()? { + match &mut self.inner { + QuadIterInner::Quads { iter, store } => Some(match iter.next()? { Ok(quad) => store.decode_quad(&quad).map_err(|e| e.into()), Err(error) => Err(error), }), - Self::Error(iter) => iter.next().map(Err), - Self::Empty => None, + QuadIterInner::Error(iter) => iter.next().map(Err), + QuadIterInner::Empty => None, } } } @@ -1293,12 +1301,7 @@ fn store() -> Result<(), io::Error> { result?; assert_eq!(store.len(), 4); - assert_eq!( - store - .quads_for_pattern(None, None, None, None) - .collect::, _>>()?, - all_quads - ); + assert_eq!(store.iter().collect::, _>>()?, all_quads); assert_eq!( store .quads_for_pattern(Some(main_s.as_ref()), None, None, None) diff --git a/python/src/memory_store.rs b/python/src/memory_store.rs index 0dd53942..a63bb0b1 100644 --- a/python/src/memory_store.rs +++ b/python/src/memory_store.rs @@ -4,7 +4,7 @@ use crate::sparql::*; use crate::store_utils::*; use oxigraph::io::{DatasetFormat, GraphFormat}; use oxigraph::model::*; -use oxigraph::MemoryStore; +use oxigraph::store::memory::*; use pyo3::basic::CompareOp; use pyo3::exceptions::{NotImplementedError, ValueError}; use pyo3::prelude::*; @@ -95,12 +95,12 @@ impl PyMemoryStore { let (subject, predicate, object, graph_name) = extract_quads_pattern(subject, predicate, object, graph_name)?; Ok(QuadIter { - inner: Box::new(self.inner.quads_for_pattern( + inner: self.inner.quads_for_pattern( subject.as_ref().map(|t| t.into()), predicate.as_ref().map(|t| t.into()), object.as_ref().map(|t| t.into()), graph_name.as_ref().map(|t| t.into()), - )), + ), }) } @@ -351,14 +351,14 @@ impl<'p> PySequenceProtocol<'p> for PyMemoryStore { impl PyIterProtocol for PyMemoryStore { fn __iter__(slf: PyRef) -> QuadIter { QuadIter { - inner: Box::new(slf.inner.quads_for_pattern(None, None, None, None)), + inner: slf.inner.iter(), } } } #[pyclass(unsendable)] pub struct QuadIter { - inner: Box>, + inner: MemoryQuadIter, } #[pyproto] diff --git a/python/src/sled_store.rs b/python/src/sled_store.rs index f10cf87f..7a3282c6 100644 --- a/python/src/sled_store.rs +++ b/python/src/sled_store.rs @@ -4,11 +4,10 @@ use crate::sparql::*; use crate::store_utils::*; use oxigraph::io::{DatasetFormat, GraphFormat}; use oxigraph::model::*; -use oxigraph::SledStore; +use oxigraph::store::sled::*; use pyo3::exceptions::ValueError; use pyo3::prelude::*; use pyo3::{PyIterProtocol, PyObjectProtocol, PySequenceProtocol}; -use std::io; use std::io::BufReader; /// Store based on the `Sled `_ key-value database. @@ -110,12 +109,12 @@ impl PySledStore { let (subject, predicate, object, graph_name) = extract_quads_pattern(subject, predicate, object, graph_name)?; Ok(QuadIter { - inner: Box::new(self.inner.quads_for_pattern( + inner: self.inner.quads_for_pattern( subject.as_ref().map(|t| t.into()), predicate.as_ref().map(|t| t.into()), object.as_ref().map(|t| t.into()), graph_name.as_ref().map(|t| t.into()), - )), + ), }) } @@ -360,14 +359,14 @@ impl PySequenceProtocol for PySledStore { impl PyIterProtocol for PySledStore { fn __iter__(slf: PyRef) -> QuadIter { QuadIter { - inner: Box::new(slf.inner.quads_for_pattern(None, None, None, None)), + inner: slf.inner.iter(), } } } #[pyclass(unsendable)] pub struct QuadIter { - inner: Box>>, + inner: SledQuadIter, } #[pyproto]