Rust Bindings for Growl
Safe Rust wrapper over the Growl OWL 2 RL reasoner. Provides RAII arena management, typed RDF terms, and a high-level API for ontology reasoning.
Prerequisites
A C compiler is required. The cc crate handles compilation automatically; no SLOP toolchain is needed since pre-transpiled C sources are included in csrc/.
Installation
[]
= "0.1"
Quick Start
use ;
let arena = new;
let mut graph = new;
// Create terms
let dog = arena.make_iri;
let animal = arena.make_iri;
let fido = arena.make_iri;
let rdf_type = arena.make_iri;
let rdfs_subclass = arena.make_iri;
let owl_class = arena.make_iri;
// Build graph
graph.add_triple;
graph.add_triple;
graph.add_triple;
graph.add_triple;
// Run the reasoner
let result = reason;
match result
High-Level API
The Reasoner struct owns its arena and graph, hiding FFI details. It returns OwnedReasonerResult with owned data that can be freely sent across threads.
use ;
let mut reasoner = new; // 32 MB arena
// or: Reasoner::with_capacity(64 * 1024 * 1024)
// Add triples — all-IRI convenience method
reasoner.add_iri_triple;
reasoner.add_iri_triple;
// Or add triples with OwnedTerm for literals and blank nodes
let s = Iri;
let p = Iri;
let o = Literal ;
reasoner.add_triple;
// Run reasoning
match reasoner.reason
// Enable complete mode (cls-thing, prp-ap, dt-type2)
let mut reasoner = new.complete;
// Or use custom config
let config = new.verbose.fast;
let result = reasoner.reason_with_config;
// Quick consistency check (no triples returned)
assert!;
Owned Types
OwnedTerm, OwnedTriple, and OwnedReasonerResult use String instead of borrowed &str, so they have no lifetime dependency on the arena and are Send + Sync.
Low-Level API
Arena
RAII wrapper around the C arena allocator. All terms and graphs are allocated from an arena.
let arena = new; // 4 MB
let arena = with_default_capacity; // 1 MB
// Create RDF terms
let iri = arena.make_iri;
let blank = arena.make_blank;
let lit = arena.make_literal;
let triple = arena.make_triple;
IndexedGraph
An indexed RDF graph with SPO/PSO/OSP lookups.
let mut graph = new;
// Add triples (raw FFI terms)
graph.add_triple;
// Add triples (safe Term values)
graph.add;
graph.size; // number of triples
graph.contains_triple; // exact lookup
// Pattern matching — None means wildcard
graph.match_pattern; // all triples with given p and o
// Convenience accessors
graph.objects; // Vec<Term>
graph.subjects; // Vec<Term>
Term
Safe, read-side view of an RDF term. Lifetime tied to the arena's string data.
// Convert from FFI
let term = from_ffi;
// Display formats: <http://...>, _:b42, "hello"@en
println!;
Triple
Safe, read-side view of an RDF triple.
let triple = from_ffi;
println!; // <s> <p> <o> .
ReasonerConfig
Builder pattern configuration for the reasoner.
let config = new
.worker_count // parallel workers (default: 4)
.channel_buffer // message buffer size (default: 256)
.max_iterations // iteration limit (default: 1000)
.verbose // per-iteration timing (default: true)
.fast // skip schema rules (default: false)
.complete // enable cls-thing & prp-ap (default: false)
.validate // enable validation mode (default: false)
.validate_ns; // validate only this namespace
ReasonerResult
Annotation Filtering
Large ontologies often contain many annotation triples (rdfs:label, rdfs:comment, SKOS labels, Dublin Core metadata) that have no semantic effect under OWL 2 RL. Filtering them before reasoning can significantly reduce memory use and improve performance.
High-level (Reasoner):
let mut reasoner = new.filter_annotations;
reasoner.add_iri_triple;
reasoner.add_iri_triple;
// Annotation triples are filtered before reasoning and restored in the result
let result = reasoner.reason;
Low-level:
let filtered = filter_annotations;
let result = reason;
The list of 27 standard annotation properties is available as growl::STANDARD_ANNOTATION_PROPERTIES. User-declared owl:AnnotationProperty instances in the graph are also filtered.
Validation
Validation mode checks TBox consistency by injecting a synthetic instance of each class and property, then running the reasoner to detect contradictions (e.g., unsatisfiable classes due to disjointness or restriction conflicts). It reports all unsatisfiable entities, not just the first.
A namespace prefix can scope validation to only entities within that namespace, which is useful when importing external ontologies that may have known issues.
High-level (Reasoner):
let mut reasoner = new.complete;
// ... add triples ...
// Validate all entities
let result = reasoner.validate;
// Validate only entities in a namespace
let result = reasoner.validate_ns;
match result
Low-level:
let result = validate;
let result = validate_with_ns;
Types:
// Owned equivalents (Send + Sync)
Free Functions
// Run with default config
reason // Run with custom config
reason_with_config // Quick consistency check (no graph returned)
is_consistent // Filter annotation triples
filter_annotations // Validate TBox (check for unsatisfiable classes/properties)
validate // Query helpers
get_types
Thread Safety
The C runtime uses a global intern pool (slop_global_intern_pool) that is protected by a pthread_mutex_t (enabled via the SLOP_INTERN_THREADSAFE compile flag in build.rs). This means multiple arenas can safely be used concurrently from different threads.
The Arena type is still !Send + !Sync, individual arenas must not be shared across threads. Each thread should create its own arena.
Running Tests
&&
Tests can run with the default thread count since the intern pool is internally synchronized.
The build script (build.rs) compiles all C sources automatically via the cc crate.
License
Apache License 2.0 — see LICENSE.