# Oxiland
Oxiland is a safe Rust reimplementation of the Redland `librdf` object model,
powered by [Oxigraph](https://oxigraph.org/).
The project is working toward measurable Redland compatibility without carrying
manual C memory management into its Rust API. Oxigraph provides the RDF and
SPARQL engine; Oxiland supplies Redland-oriented concepts, behavior, migration
paths, and—later in the 0.x series—a separately audited C compatibility layer.
> [!IMPORTANT]
> Oxiland 0.1 provides the trusted core model surface. It does **not** yet
> provide complete Redland API accounting, differential behavioral parity,
> source, or ABI compatibility. See the [parity ledger](PARITY.md) and
> [0.1 report](docs/reports/0.1.md).
## Why Oxiland?
- Familiar Redland concepts with Rust ownership and error handling.
- Oxigraph-backed RDF terms, datasets, parsing primitives, and SPARQL.
- In-memory operation by default, with optional [Fjall](https://github.com/fjall-rs/fjall) persistence.
- No `unsafe` code in the primary crate.
- Compatibility claims backed by an API inventory and differential tests
rather than an unqualified percentage.
- A staged path toward existing C consumer support.
## Current capabilities
| RDF named nodes, blank nodes, literals, triples, and quads | Available through Oxigraph types |
| In-memory model | Available |
| Default-graph CRUD | Available |
| Named-graph/context CRUD and matching | Available |
| Partial statement matching | Available; streaming `StatementMatches` |
| SPARQL query execution | Basic ASK/SELECT support |
| RDF parser and serializer primitives | Re-exported; Redland-style facade planned for 0.2 |
| Persistent Fjall model | Available via `Model::open` |
| SPARQL Update and complete result adapters | Planned for 0.3 |
| Full safe Rust Redland accounting | Planned for 0.6 |
| C source and ABI compatibility | Planned for 0.7–0.9 |
“Available” means the current public workflow is implemented and tested. It
does not imply full subsystem parity with Redland.
## Requirements
- Rust 1.87 or newer
Oxiland pins Oxigraph 0.5.9 for the current release so compatibility testing is
performed against a known engine version.
## Installation
Add Oxiland to your `Cargo.toml`:
```toml
[dependencies]
oxiland = "0.1.0"
```
## Quick start
```rust
use oxiland::terms::{Literal, NamedNode, Triple};
use oxiland::{Model, Query, QueryResults};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let model = Model::new()?;
model.add(Triple::new(
NamedNode::new("https://example.com/alice")?,
NamedNode::new("https://example.com/name")?,
Literal::new_simple_literal("Alice"),
))?;
let result = Query::new("ASK { ?s ?p ?o }").execute(&model)?;
assert!(matches!(result, QueryResults::Boolean(true)));
Ok(())
}
```
`Model::add` returns `true` when it inserts a new statement and `false` when the
same statement already exists.
Run this example from the repository with:
```console
cargo run --example quick_start
```
## Contexts and pattern matching
Redland contexts map to Oxigraph graph names:
```rust
use oxiland::terms::{GraphName, Literal, NamedNode, Triple};
use oxiland::{Model, StatementPattern};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let model = Model::new()?;
let subject = NamedNode::new("https://example.com/alice")?;
let graph = NamedNode::new("https://example.com/people")?;
model.add_to_graph(
Triple::new(
subject.clone(),
NamedNode::new("https://example.com/name")?,
Literal::new_simple_literal("Alice"),
),
GraphName::NamedNode(graph),
)?;
let matches = model
.find(StatementPattern {
subject: Some(subject.as_ref().into()),
..StatementPattern::default()
})
.collect::<Result<Vec<_>, _>>()?;
assert_eq!(matches.len(), 1);
Ok(())
}
```
`Model::find` returns a streaming `StatementMatches` iterator over a store
snapshot (ADR-005).
The complete example is runnable with `cargo run --example contexts`.
## Persistent storage
`Model::open` stores quads in a [Fjall](https://github.com/fjall-rs/fjall) keyspace and keeps
an Oxigraph in-memory working set for querying:
```rust,no_run
use oxiland::Model;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let model = Model::open("./data/oxiland-store")?;
assert!(model.is_empty()?);
Ok(())
}
```
On-disk compatibility and migration guarantees are not yet stabilized. Do not
treat 0.x persistent stores as archival formats without an independent export.
## Relationship to Redland
Oxiland targets the public `librdf` 1.0.17 API and the reference manual labeled
1.0.18. Raptor and Rasqal behavior is included only when exposed through a
public `librdf` workflow.
Compatibility is reported at separate levels:
1. **Concept parity** — Redland workflows have Rust equivalents.
2. **Safe API accounting** — every public Redland item is mapped or classified.
3. **Behavioral parity** — equivalent operations match native Redland fixtures.
4. **C source compatibility** — supported C programs compile against Oxiland.
5. **C ABI compatibility** — supported existing binaries can load the
compatibility library.
6. **Downstream compatibility** — selected real consumers pass unchanged.
This distinction matters: safe Rust may replace allocation functions
idiomatically while the future C layer must still reproduce their observable
ownership behavior. Details live in the
[compatibility plan](docs/COMPATIBILITY.md).
## Architecture
The primary `oxiland` crate remains safe and delegates standards-heavy work to
Oxigraph:
```text
Rust application
│
▼
Oxiland safe facade ──> Oxigraph RDF, storage, I/O, and SPARQL
▲
│
Future oxiland-capi
▲
│
Existing C application
```
The future `oxiland-capi` crate will isolate opaque handles, strings,
allocators, callbacks, panic containment, and other audited `unsafe` code. The
safe crate has `#![forbid(unsafe_code)]`.
See the [architecture plan](docs/ARCHITECTURE.md) and
[decision log](docs/DECISIONS.md) for the full boundaries and open decisions.
## Roadmap
| 0.1 | Core terms, models, contexts, and basic queries |
| 0.2 | Redland-shaped RDF parsers and serializers |
| 0.3 | Complete query, results, and update workflows |
| 0.4 | Durable storage, transactions, and backend capabilities |
| 0.5 | Streams, utilities, logging, and observability |
| 0.6 | Fully accounted safe Rust Redland surface |
| 0.7 | C ABI preview |
| 0.8 | C and downstream ecosystem validation |
| 0.9 | API/ABI-frozen 1.0 release candidate |
Milestones are evidence-gated rather than date-gated. The detailed
[0.x roadmap](docs/ROADMAP.md) defines deliverables, dependencies, exclusions,
and release criteria.
## Project documentation
- [Planning index](docs/README.md)
- [Changelog](CHANGELOG.md)
- [Parity ledger](PARITY.md)
- [0.1 compatibility report](docs/reports/0.1.md)
- [0.x roadmap](docs/ROADMAP.md)
- [Execution plan and current backlog](docs/EXECUTION.md)
- [Architecture](docs/ARCHITECTURE.md)
- [Compatibility contract](docs/COMPATIBILITY.md)
- [Verification and release gates](docs/VERIFICATION.md)
- [Architecture decisions](docs/DECISIONS.md)
- [Risk register](docs/RISKS.md)
- [0.1 inventory](compatibility/inventory/redland-1.0.17-oxiland-0.1.json)
The parity ledger describes what exists now. Planning documents describe the
intended path and must not be read as implemented functionality.
## Development
Run the default local checks:
```console
cargo fmt --check
cargo clippy --all-targets -- -D warnings
cargo test
cargo doc --no-deps
python3 scripts/check-inventory.py
scripts/generate-public-api.sh check
```
CI runs these checks on stable and Rust 1.87.
Compatibility work should be implemented as a vertical slice: inventory
mapping, public API, implementation, positive and failure tests, differential
evidence where applicable, and parity-ledger updates. The
[execution plan](docs/EXECUTION.md) defines readiness and completion.
## Contributing
Contributions are welcome while the API is evolving. Before proposing a broad
facade, storage, or FFI change:
1. identify the affected Redland subsystem or inventory entries;
2. read the relevant architecture and compatibility decisions;
3. define observable behavior and unsupported cases;
4. include tests through the public Oxiland API;
5. update the parity ledger and planning evidence.
The most valuable current tasks are listed in the
[0.2 backlog](docs/EXECUTION.md#current-02-backlog).
## License
Oxiland is licensed under either of:
- [Apache License, Version 2.0](LICENSE-APACHE)
- [MIT License](LICENSE-MIT)
at your option.