Hi,
currently I'm writing a crate for conversion between Semantic Web's RDF data and Rust types. The idea I'm stugglling with is the conversion of complex types into a semantic representation, i.e. a bunch of RDF-triples. Since the creation of those triples could be expensive I want to return an iterator that lazily creates the triples on demand. Therefore, I wrote the following code.
use sophia::term::{Term, TermData};
use std::collections::VecDeque;
pub type TripleCreator<'a, TD> = Box<dyn 'a + Fn(Term<TD>) -> [Term<TD>; 3]>;
pub trait GetTriplesIter {
fn triples_iter<'a, TD>(&'a self, s: &'a Term<TD>) -> TriplesIter<'a, TD>
where
TD: TermData;
}
pub struct TriplesIter<'a, TD>
where
TD: TermData,
{
s: &'a Term<TD>,
creators: VecDeque<TripleCreator<'a, TD>>,
}
impl<'a, TD> Iterator for TriplesIter<'a, TD>
where
TD: TermData,
{
type Item = [Term<TD>; 3];
fn next(&mut self) -> Option<Self::Item> {
self.creators
.pop_front()
.map(|creator| creator(self.s.clone()))
}
}
The plan is that implementors collect a bunch of closures that are executet on call of next()
. It is intended that TriplesIter
(and its closures) borrows self
immutable so it can't be altered while TriplesIter
exists.
Would you consider this an idomatic solution? Some suggestions for impovements in terms of performance and/or ergonomics?