Rust streams and iterators¶
Oxiland uses standard Rust iterators for statement matching, RDF parsing, and SPARQL results. The concrete iterator types differ, but they follow one resource and failure policy.
Contract¶
- Items are produced lazily; collection is always caller-controlled.
- Fallible streams yield
Result<Item>so storage, parsing, or evaluation failures can appear after successful items. breakor dropping the iterator stops the operation and releases its owned state through RAII.- Iteration order is not a general dataset guarantee unless a SPARQL
ORDER BYor another documented API contract defines it. - A stream is not automatically a snapshot copy; it owns or borrows the state documented by its concrete API.
Surfaces¶
| Workflow | Entry point | Item |
|---|---|---|
| Statement matching | Model::find |
Result<Quad> |
| Reader RDF parse | Parser::parse_reader / parse_path |
Result<Quad> |
| Slice RDF parse | Parser::parse_slice / parse_str |
Result<Quad> |
| SPARQL SELECT | QueryResults::Solutions |
Oxigraph solution result |
| SPARQL CONSTRUCT / DESCRIBE | QueryResults::Graph |
Oxigraph triple result |
Process incrementally¶
use oxiland::terms::{Literal, Triple, named_node};
use oxiland::{Model, StatementPattern};
# fn main() -> oxiland::Result<()> {
let model = Model::new()?;
model.add(Triple::new(
named_node("https://example.com/s")?,
named_node("https://example.com/p")?,
Literal::new_simple_literal("value"),
))?;
for item in model.find(StatementPattern::default()) {
let quad = item?;
println!("{quad}");
break;
}
# Ok(())
# }
Avoid collect::<Result<Vec<_>, _>>() for unbounded or caller-controlled
results unless the application has already enforced a size limit.
Error timing¶
Parser configuration can succeed even when a later record is malformed. Query execution can return a result iterator whose evaluation later fails. Handle errors at the item boundary:
```rust,no_run
use oxiland:
:{Parser, Syntax};¶
let stream = Parser::for_syntax(Syntax::Turtle).parse_path("incoming.ttl")?; for item in stream { match item { Ok(quad) => process(quad), Err(error) => { report(error); break; } } }
fn process(_: oxiland::terms::Quad) {}¶
fn report(_: oxiland::Error) {}¶
Ok::<(), oxiland::Error>(())¶
```
For progressive model loading, successful items before a failure may already be durable. Iterator-level laziness does not imply transactional rollback.
Ownership and cancellation¶
StatementMatches yields owned quads from store state and does not borrow the
Model. Parser streams own their reader or borrow their input slice according
to the method signature. SPARQL result adapters remain tied to query/model state
through their Rust lifetimes.
SPARQL supports cooperative CancellationToken handling. Parse and bulk-load
iterators do not expose wall-clock cancellation; stop consuming them or apply
process/thread isolation at the application boundary.
Production practices¶
- Apply SPARQL limits and application-level budgets before exposing a stream.
- Keep expensive iterators out of long-lived unrelated waits.
- Track processed count, duration, early termination, and concrete error class.
- Use streaming writers to avoid materializing serialized output as a
String. - Do not assume streaming bounds the model's own memory footprint; persistent models keep an in-memory working set.
See RDF input and output, SPARQL, and Rust production operations.