rdfx
Core RDF 1.2 data structures for Rust — terms (triple terms included), triples and quads, graphs and datasets, interpretations and vocabularies, blank node isomorphism, and rdf:reifies round-tripping.
use ;
// RDF 1.1: language-tagged literal in object position.
let t = triple!;
// RDF 1.2: a triple term as the object (`<<( s p o )>>`).
let annotated = triple!;
assert!;
Graphs and datasets are generic over one resource type, so pick the representation that fits — indices interned in a vocabulary, or any type opted in with impl_resource!:
use ;
let mut dataset: = new;
dataset.insert;
dataset.insert;
assert_eq!;
Why this fork
Fork of rdf-types by Timothée Haudebourg. The RDF 1.1 model carries over unchanged; this fork adds:
- RDF 1.2: triple terms, directional language strings (
rdf:dirLangString), and therdf:reifiesannotation model withunstar/restarround-tripping. - Hash-backed graph and dataset implementations plus indexed variants, alongside the upstream B-tree ones, and a graph/dataset trait split so traversal, pattern matching and mutation are separate bounds.
- Rewritten isomorphism: bitmap signature refinement, candidate ordering by set size, augmenting-path bipartite matching instead of greedy matching, and triple-term descent. Two correctness fixes came with it — false positives on blank-free quads, and stale subject/predicate/object index sets after removal.
- Sealed position-marker traits (
IsSubject,IsPredicate,IsObject,IsGraph) turning RDF position constraints into compile-time errors, with generalized-RDF types for when you need to lift them. - Performance: SWAR blank id validation,
memchr-acceleratedDisplay,itoaanduuidfast paths in blank node generators, allocation removal across isomorphism. - Rust 2024 edition, MSRV 1.96, single crate instead of a workspace.
- Renamed crate:
rdf-types→rdfx. Depends oniri-rs(fork ofiref) instead ofiref, which is the point of the fork. - Criterion bench suite (
dataset,isomorphism,swar,triple_terms,vocabulary).
Credit and history preserved — see Attribution.
Install
Feature flags
| Flag | Default | Enables |
|---|---|---|
serde |
Serialize / Deserialize for terms, literals, triples and quads |
|
meta |
meta module: locspan-tagged values and Strip |
|
contextual |
Display through a vocabulary via contextual |
|
uuid-generator |
All UUID blank node generators (v3, v4, v5) | |
uuid-generator-v3 |
Name-based (MD5) UUID blank node generator | |
uuid-generator-v4 |
Random UUID blank node generator | |
uuid-generator-v5 |
Name-based (SHA-1) UUID blank node generator |
RDF 1.2
RDF 1.1 data is a syntactic subset — the new variants are simply never constructed. Three additions matter.
Triple terms. A triple used as a term. Strict RDF admits them in object position only; the generalized types lift that restriction. Macro syntax: <<( s p o )>>.
Directional language strings. A language tag plus base direction, datatype rdf:dirLangString. Macro syntax: "value" @ "lang" / "rtl".
use ;
let t = triple!;
let Named = t.into_object else ;
assert!;
The rdf:reifies annotation model. star::unstar_graph rewrites triple terms into RDF 1.1-compatible reified form; star::restar_graph folds them back. The pair round-trips, so 1.2 data survives a 1.1-only channel.
Storage
Storage is uniform: BTreeDataset<R>, HashDataset<R> and their indexed variants hold one R: Resource in every position. LocalTerm — the lexical alphabet — is deliberately not a Resource, because a literal cannot be a subject. Two ways around that:
- Intern lexical values in a vocabulary and store the handles. Comparison and cloning collapse to integer operations.
- Wrap the lexical term in a newtype, opt it in with
impl_resource!, and supply anInterpretationmapping the wrapper back to IRIs, literals and triple-term components.
Indexed variants carry subject/predicate/object indices for pattern matching; plain variants are smaller and build faster.
Isomorphism
Two RDF graphs are isomorphic when some bijection over blank nodes makes them equal. graph_equivalent / dataset_equivalent answer yes or no; find_bijection_with returns the mapping itself.
use ;
let mut a: = new;
a.insert;
let mut b: = new;
b.insert;
assert!;
The _with variants take an Interpretation, which is what makes blank nodes — and the interiors of triple terms — visible to the matcher. Without one, resources are opaque and equivalence degrades to set equality.
Vocabularies
A vocabulary maps lexical values onto lightweight handles, so a dataset can store integers instead of IRIs:
use ;
let mut vocabulary: IndexVocabulary = default;
let i = vocabulary.insert;
assert_eq!;
Benchmarks
Criterion output: target/criterion/.
MSRV
Rust 1.96 (edition 2024).
Attribution
Original crate: rdf-types by Timothée Haudebourg. Upstream commits are preserved in this repo's history under their original authorship. This fork is RDF 1.2 support, extra storage backends, a rewritten isomorphism engine, and a layer of performance work on top of the original design.
License
Dual-licensed, same as upstream. Pick whichever fits: