rudof_lib
rudof_lib is the centralized, programmatic facade for the entire Rudof ecosystem. It exposes a stable entry point (Rudof) that hides the complexity of dealing with numerous specialized underlying subcrates (shacl_validation, shex_validation, rudof_rdf, pgschema, etc.).
At a high level, it provides robust, builder-style interfaces for:
- Loading and serializing RDF and PG data.
- Loading, checking, serializing and validating ShEx schemas.
- Loading, serializing and validating SHACL shapes.
- Loading, serializing and validating PGSchemas.
- Loading, running and serializing SPARQL queries and query results.
- Converting and comparing schemas between supported formats.
- Loading and serializing DCTAP and Service Descriptions.
- Generating synthetic data from schemas.
Primary goals:
- Provide a stable, ergonomic entry point (
Rudof) that acts as a facade over specialized crates. - Expose operations via builder-style (fluent) interfaces.
- Keep a clear separation between the public API, concrete implementations, and shared types/formats/errors.
Architecture and Structure
The package structure is organized to make the public API small and stable while keeping implementations modular and testable. Below is a more detailed description of the main files and folders, what to expect inside them and the conventions used by the crate.
src/lib.rs: Core entry, exposing the essential (Rudof,RudofConfig, errors and formats).src/rudof.rs: Houses the centralRudofstate container. Contains methods grouped by domain returning configured builder instances.src/rudof_config.rs: HousesRudofConfigfor configuration handling and defaults.src/api/: The functional brain of the library. Divided by domain (data,shex,shacl, etc.). Each domain contains three subparts:builders/: The public builder types (*Builder) that callers instantiate viaRudofmethods. Builders configure the operation and finally call an implementation function when executed.implementations/: Concrete operation code that performs the logic usingRudofand the configured inputs.trait definition(in the domain module): describe the operations offered.
src/formats/: Enums for input/serialization formats (for exampleSchemaFormat,InputSpec, orConversionFormat).src/types/: Shared domain types (for exampleData,QueryResult,shex_statistics, and other cross-cutting structs).src/errors/: Domain-specific error types and the unifiedRudofError. Errors are defined per-domain and composed into a top-level error to provide predictable error handling for callers.src/utils/: Internal utility helpers.
Operations on the Rudof Struct
Every functionality in the library operates by initially calling a method on the Rudof instance. This creates a specific operation builder. Modifiers chain upon this builder, culminating in an .execute() call.
Below is an exhaustive breakdown grouped by domain:
1. Core
#![allow(unused)] fn main() { use rudof_lib::{Rudof, RudofConfig}; // Initialize Rudof with default config let mut rudof = Rudof::new(RudofConfig::default()); // Get the current version let version = rudof.version().execute(); println!("Rudof version: {}", version); // Update the configuration rudof.update_config(RudofConfig::default()); // Reset all internal state rudof.reset_all().execute(); }
2. Data
2.1 RDF Data
#![allow(unused)] fn main() { use rudof_lib::{Rudof, RudofConfig}; use rudof_lib::formats::{ InputSpec, DataFormat, DataReaderMode, ResultDataFormat, NodeInspectionMode }; use std::str::FromStr; let mut rudof = Rudof::new(RudofConfig::default()); let rdf_data_input = vec![InputSpec::from_str( r#" prefix ex: <http://example.org/> . ex:alice a ex:Person ; ex:age 30 . "# ).unwrap()]; // Load RDF data into Rudof's state rudof.load_data() .with_data(&data_input) .with_data_format(&DataFormat::Turtle) .with_reader_mode(&DataReaderMode::Lax) .with_merge(false) .execute() .unwrap(); // Serialize the loaded data to standard output rudof.serialize_data(&mut std::io::stdout()) .with_result_data_format(&ResultDataFormat.NTriples) .execute() .unwrap(); // Serialize the information of the node "ex:alice" to standard output let node = "ex:alice"; let predicates = vec!["ex:age".to_string()]; rudof.show_node_info(&node, &mut std::io::stdout()) .with_show_node_mode(&NodeInspectionMode::Outgoing) .with_predicates(&predicates) .with_depth(1) .with_show_colors(false) .execute() .unwrap(); // Reset data state rudof.reset_data().execute() }
2.2 Property Graph Data
#![allow(unused)] fn main() { use rudof_lib::{Rudof, RudofConfig}; use rudof_lib::formats::{InputSpec, DataFormat, DataReaderMode, ResultDataFormat}; use std::str::FromStr; let mut rudof = Rudof::new(RudofConfig::default()); let pg_data_input = vec![InputSpec::from_str( r#" (alice {Person} [ name: "Alice", age: 23, aliases: "Ally" ]) (bob {Person} [ name: "Robert", aliases: ["Bob", "Bobby"] ]) "#, ).unwrap()]; // Load Property Graph data into Rudof's state (without merging) rudof.load_data() .with_data(&pg_data_input) .with_data_format(&DataFormat::Pg) .execute() .unwrap(); // Serialize the loaded data to standard output rudof.serialize_data(&mut std::io::stdout()).execute().unwrap(); }
2.3 SPARQL Endpoint
#![allow(unused)] fn main() { use rudof_lib::{Rudof, RudofConfig}; let mut rudof = Rudof::new(RudofConfig::default()); // Lists the registered SPARQL endpoints let endpoints = rudof.list_endpoints().execute(); for (name, url) in endpoints { println!("{}, {}", name, url); } // Focus SPARQL endpoint let endpoint = "http://example.org/sparql"; rudof.load_data() .with_endpoint(&endpoint) .execute() .unwrap(); }
2.4 Service Description
#![allow(unused)] fn main() { use rudof_lib::{Rudof, RudofConfig}; use rudof_lib::formats::{ InputSpec, DataFormat, DataReaderMode, ResultServiceFormat }; use std::str::FromStr; let mut rudof = Rudof::new(RudofConfig::default()); let service_description_input = InputSpec::from_str( r#" prefix sd: <http://www.w3.org/ns/sparql-service-description#> . prefix ent: <http://www.w3.org/ns/entailment/> . <http://example.org/sparql> a sd:Service ; sd:endpoint <http://example.org/sparql> ; sd:supportedLanguage sd:SPARQL11Query ; sd:defaultEntailmentRegime ent:Simple . "#; ).unwrap(); // Load a Service Description into Rudof's state let base = "http://example.org/"; rudof.load_service_description(&service_description) .with_data_format(&DataFormat::Turtle) .with_reader_mode(&DataReaderMode::Strict) .with_base(&base) .execute() .unwrap(); // Serialize the loaded service description to standard output rudof.serialize_service_description(&mut std::io::stdout()) .with_result_service_format(&ResultServiceFormat::Json) .execute() .unwrap(); }
3. ShEx
#![allow(unused)] fn main() { use rudof_lib::{Rudof, RudofConfig}; use rudof_lib::formats::{ InputSpec, ShExFormat, ShapeMapFormat, ShExValidationSortByMode, }; use std::str::FromStr; let mut rudof = Rudof::new(RudofConfig::default()); let rdf_data_input = vec![InputSpec::from_str( r#" <alice> <name> "Alice" ; <age> 30 . "# ).unwrap()]; let base_nodes = "http://example.org"; // Load RDF data into Rudof's state rudof.load_data() .with_data(&rdf_data_input) .with_base(&base_nodes) .execute() .unwrap(); let shex_schema_input = InputSpec::from_str( r#" PREFIX xsd: <http://www.w3.org/2001/XMLSchema#> <PersonShape> { <name> xsd:string ; <age> xsd:integer } "#, ).unwrap(); let base_shapes = "http://example.org"; // Check ShEx schema well-formedness and check for negative cycles in the dependency graph, // serializing the checking results to standard output rudof.check_shex_schema(&shex_schema_input, &mut std::io::stdout()) .with_shex_schema_format(&ShExFormat::ShExC) .with_base(&base_shapes) .execute() .unwrap(); // Load ShEx schema into Rudof's state rudof.load_shex_schema(&shex_schema_input) .with_shex_schema_format(&ShExFormat::ShExC) .with_base(&base_shapes) .execute() .unwrap(); // Serialize the loaded ShEx schema to standard output rudof.serialize_shex_schema(&mut std::io::stdout()) .with_shape(&"http://example.org/PersonShape") .with_show_statistics(true) .with_show_dependencies(true) .with_show_time(true) .with_result_shex_format(&ShExFormat::ShExJ) .execute() .unwrap(); let shapemap_input = InputSpec::from_str( r#" <alice>@<PersonShape> "# ).unwrap(); // Load shapemap into Rudof's state rudof.load_shex_schema(&shapemap_input) .with_shapemap_format(&ShapeMapFormat::Compact) .with_base_nodes(&base_nodes) .with_base_shapes(&base_shapes) .execute() .unwrap(); // Serialize the loaded shapemap to standard output rudof.serialize_shex_schema(&mut std::io::stdout()) .with_result_shapemap_format(&ShapeMapFormat::Compact) .with_show_colors(false) .execute() .unwrap(); // Run validation storing the result into Rudof´s state rudof.validate_shex().execute().unwrap(); // Serialize the validation results to standard output rudof.serialize_shex_validation_results(&mut std::io::stdout()) .with_shex_validation_sort_order_mode(&ShExValidationSortByMode::Node) .with_result_shex_validation_format(&ResultShExValidationFormat::Details) .execute() .unwrap(); // Reset ShEx schema state rudof.reset_shex_schema().execute(); // Reset shapemap state rudof.reset_shapemap().execute(); // Reset ShEx validation state (ShEx schema, shapemap and validation results) rudof.reset_shex().execute(); }
4. SHACL
#![allow(unused)] fn main() { use rudof_lib::{Rudof, RudofConfig}; use rudof_lib::formats::{ InputSpec, DataFormat, ShaclFormat, ShaclValidationSortByMode }; use std::str::FromStr; let mut rudof = Rudof::new(RudofConfig::default()); let data_with_shapes_input = InputSpec::from_str(r#" prefix ex: <http://example.org/> . prefix sh: <http://www.w3.org/ns/shacl#> . prefix xsd: <http://www.w3.org/2001/XMLSchema#> . SHACL Shape ex:PersonShape a sh:NodeShape ; sh:targetClass ex:Person ; sh:property [ sh:path ex:name ; sh:datatype xsd:string ; sh:minCount 1 ; ] . Instance data ex:Alice a ex:Person ; ex:name "Alice Smith" ; ex:age 30 . ex:Bob a ex:Person ; ex:name "Bob Jones" ; ex:age 25 . "#).unwrap(); // Load RDF data containing SHACL shapes rudof.load_data() .with_data(&[data_with_shapes_input]) .with_data_format(&DataFormat::Turtle) .execute() .unwrap(); // Extract SHACL shapes from the loaded data and load them into Rudof's state (you can also separate data and shapes into two fields and use ".with_shacl_schema()") rudof.load_shacl_shapes().execute().unwrap(); // Serialize the loaded shapes to standard output rudof.serialize_shacl_shapes(&mut std::io::stdout()) .with_shacl_result_format(&ShaclFormat::NTriples) .execute() .unwrap(); // Run validation storing the result into Rudof´s state rudof.validate_shacl().execute().unwrap(); // Serialize the validation results to standard output rudof.serialize_shacl_validation_results(&mut std::io::stdout()) .with_shacl_validation_sort_order_mode(&ShaclValidationSortByMode::Node) .with_result_shacl_validation_format(&ResultShaclValidationFormat::Details) .execute() .unwrap(); // Reset SHACL shapes state rudof.reset_shacl_shapes().execute(); // Reset SHACL validation state (SHACL schema and validation results) rudof.reset_shacl().execute(); }
5. Property Graph Schema
#![allow(unused)] fn main() { use rudof_lib::{Rudof, RudofConfig}; use rudof_lib::formats::{InputSpec, DataFormat, PgSchemaFormat, ResultPgSchemaValidationFormat}; use std::str::FromStr; let mut rudof = Rudof::new(RudofConfig::default()); let pg_data_input = vec![InputSpec::from_str( r#" (n1 {"Student"}["name": "Alice", "age": 23]) (n2_wrong {"Student"}["name": "Bob", "age": 12]) (n3_wrong {"Student"}["name": "Carol", "age": "unknown"]) "#, ).unwrap()]; // Load Property Graph data into Rudof's state rudof.load_data() .with_data(&pg_data_input) .with_data_format(&DataFormat::Pg) .execute() .unwrap(); let pg_schema_input = InputSpec::from_str( r#" CREATE NODE TYPE ( AdultStudentType: Student { name: STRING , age: INTEGER CHECK > 18 }) "#).unwrap(); // Load Property Graph Schema into Rudof's state rudof.load_pgschema(&pg_schema_input) .with_pg_schema_format(&PgSchemaFormat::PgSchemaC) .execute() .unwrap(); // Serialize the loaded Property Graph Schema to standard output rudof.serialize_pgschema(&mut std::io::stdout()) .with_result_pg_schema_format(&PgSchemaFormat::PgSchemaC) .execute() .unwrap(); let typemap_input = InputSpec::from_str( r#" n1: AdultStudentType, n2_wrong: AdultStudentType, n3_wrong: AdultStudentType "#,).unwrap(); // Load typemap into Rudof's state rudof.load_typemap(&typemap_input).execute().unwrap(); // Run validation storing the result into Rudof´s state rudof.validate_pgschema().execute().unwrap(); // Serialize the validation results to standard output rudof.serialize_pgschema_validation_results(&mut std::io::stdout()) .with_result_pg_schema_validation_format(&ResultPgSchemaValidationFormat::Details) .with_show_colors(false) .execute() .unwrap() // Reset Property Graph schema shapes state rudof.reset_pgschema().execute() // Reset typemap state rudof.reset_typemap().execute() // Reset Property Graph schema validation state (PG schema, typemap and validation results) rudof.reset_pgschema_validation().execute() }
6. Query
#![allow(unused)] fn main() { use rudof_lib::{Rudof, RudofConfig}; use rudof_lib::formats::{ InputSpec, DataFormat, ResultQueryFormat, QueryType }; use std::str::FromStr; let mut rudof = Rudof::new(RudofConfig::default()); let data_input = InputSpec::from_str(r#" prefix : <http://example.org/> prefix schema: <http://schema.org/> :a schema:name "Alice" ; :status :Active ; schema:knows :a, :b . :b schema:name "Bob" ; :status :Waiting ; schema:knows :c . :c schema:name "Carol" . :d schema:name 23 . # Should fail :e schema:name "Emily" ; # Should fail schema:knows :d . "#).unwrap(); // Load RDF data rudof.load_data() .with_data(&[data_with_shapes_input]) .with_data_format(&DataFormat::Turtle) .execute() .unwrap(); let query_input = InputSpec::from_str( r#" prefix : <http://example.org/> prefix schema: <http://schema.org/> select ?person ?name ?status where { ?person schema:name ?name ; :status ?status . } "#, ) .unwrap(); // Load query into Rudof's state rudof.load_query(&query_input) .with_query_type(&QueryType::Select) .execute() .unwrap(); // Serialize the query to standard output rudof.serialize_query(&mut std::io::stdout()).execute().unwrap(); // Run the query rudof.run_query().execute(); // Serialize the query results to standard output rudof.serialize_query_result(&mut std::io::stdout()) .with_result_query_format(&ResultQueryFormat::Csv) .execute() .unwrap(); // Reset query state rudof.reset_query().execute() // Reset query execution state (query and query results) rudof.reset_query_results().execute() }
7. DCTAP
#![allow(unused)] fn main() { use rudof_lib::{Rudof, RudofConfig}; use rudof_lib::formats::{InputSpec, DCTapFormat, ResultDCTapFormat}; use std::str::FromStr; let mut rudof = Rudof::new(RudofConfig::default()); let dctap_input = InputSpec::from_str( r#" shapeID,propertyID,mandatory,repeatable,valueDataType :Person,rdf:type,true,false, :Person,schema:name,true,false,xsd:string :Person,schema:age,false,false,xsd:integer :Person,schema:memberOf,false,true,:Organization :Organization,rdf:type,true,false, :Organization,schema:name,true,false,xsd:string :Organization,schema:location,false,false,xsd:string "# ).unwrap(); // Load a DCTAP into Rudof's state rudof.load_dctap(&dctap_input) .with_dctap_format(&DCTapFormat::Csv) .execute() .unwrap(); // Serialize the loaded DCTAP to standard output rudof.serialize_dctap(&mut std::io::stdout()) .with_result_dctap_format(&ResultDCTapFormat::Json) .execute() .unwrap(); // Reset DCTAP state rudof.reset_dctap().execute(); }
8. RDF_Config (DBCLS)
#![allow(unused)] fn main() { use rudof_lib::{Rudof, RudofConfig}; use rudof_lib::formats::{InputSpec, RdfConfigFormat, ResultRdfConfigFormat}; use std::str::FromStr; let mut rudof = Rudof::new(RudofConfig::default()); let config_input = InputSpec::from_str( r#" - Person ex:person1 ex:person2: - a: ex:Person - rdfs:label: - name: "Alice" - ex:age?: - age_value: 32 - ex:memberOf: - organization: Organization - Organization ex:org1: - a: ex:Organization - rdfs:label: - org_name: "Example Org" - ex:location: - city: "Oviedo" "#).unwrap(); // Load RDF config rudof.load_rdf_config(&config_input) .with_rdf_config_format(&RdfConfigFormat::Yaml) .execute() .unwrap(); // Serialize the loaded RDF config to standard output rudof.serialize_rdf_config(&mut std::io::stdout()) .with_rdf_config_format(&ResultRdfConfigFormat::Yaml) .execute() .unwrap(); // Reset RDF config state rudof.reset_rdf_config().execute(); }
9. Generation
#![allow(unused)] fn main() { use rudof_lib::{Rudof, RudofConfig}; use rudof_lib::formats::{DataFormat, InputSpec, GenerationSchemaFormat}; use std::str::FromStr; let rudof = Rudof::new(RudofConfig::default()); let schema_input = InputSpec::from_str( r#" prefix : <http://example.org/> :User { :name . } "#).unwrap(); // Generate synthetic data asynchronously // Note: Requires a Tokio runtime or similar async environment rudof.generate_data(&schema_input, &GenerationSchemaFormat::ShEx, 10) .with_output(&mut std::io::stdout()) .with_parallel(4) .with_result_generation_format(&DataFormat::Turtle) .with_seed(42) .execute() .await .unwrap(); }