sophia_api/
source.rs

1//! A source yields items, and may also fail in the process.
2//! This module provides two specialized kinds of source:
3//! [`TripleSource`] and [`QuadSource`].
4//!
5//! These traits provides an API similar to (a subset of) the [`Iterator`] API,
6//! with methods such as [`for_each_triple`] and [`try_for_each_triple`]
7//! (resp. '[`for_each_quad`] and [`try_for_each_quad`]).
8//!
9//! # Rationale (or Why not simply use `Iterator`?)
10//!
11//! The [`Iterator`] trait is designed in such a way that items must live at least as long as the iterator itself.
12//! This assumption may be too strong in some situations.
13//!
14//! For example,
15//! consider a parser using 3 buffers to store the subject, predicate,
16//! and object of the triples it parses.
17//! Each time it extracts a triple from the data,
18//! it yields it (as 3 references to its internal buffers)
19//! to the closure passed to `for_each_triple`.
20//! Then, it **reuses** the buffers to store the data for the next triple,
21//! and yields the new triple, as 3 references to the *same* buffers.
22//!
23//! Such a parser can not implement [`Iterator`],
24//! because, once yielded by the iterator's `next` method,
25//! an item is free to live during further iterations.
26//! In particular, it can be stored in a collection,
27//! and still be alive when the `next` method is called again
28//! (consider for example the [`Iterator::collect`] method).
29//!
30//! Because many parsers (as well as other triple/quad sources)
31//! will be implemented in a manner similar to that described above,
32//! we have to provide a trait with *weaker assumptions*
33//! on the lifetime of the yielded triples.
34//!
35//! The alternative would be to wrap such parsers with a layer that would *copy*
36//! the data from internal buffers to fresh buffers for each triples,
37//! but we do not want to impose that cost on all implementations
38//! — especially when many consumers will be happy with short-lived references.
39//!
40//! # Why not implement a single trait `Source`?
41//!
42//! A cleaner design would have been to have a single trait `Source`,
43//! with generic method names such as `for_each_item`.
44//!
45//! This proved hard to use in practice,
46//! because restricting the type of items requires [higher-rank trait bounds],
47//! and these bounds would have to be repeated anywhere the specialized trait is required.
48//!
49//! The choice was therefore to favor ease of use over purity and maintainability.
50//!
51//! [`for_each_triple`]: TripleSource::for_each_triple
52//! [`try_for_each_triple`]: TripleSource::try_for_each_triple
53//! [`for_each_quad`]: QuadSource::for_each_quad
54//! [`try_for_each_quad`]: QuadSource::try_for_each_quad
55//! [higher-rank trait bounds]: https://doc.rust-lang.org/nomicon/hrtb.html
56
57use std::error::Error;
58
59pub mod convert;
60pub mod filter;
61pub mod filter_map;
62pub mod map;
63
64mod _quad;
65pub use _quad::*;
66mod _stream_error;
67pub use _stream_error::*;
68mod _triple;
69pub use _triple::*;
70
71use super::*;
72use std::convert::Infallible;