├── doc └── .gitkeep ├── VERSION ├── bin └── rdf │ ├── tests │ └── .gitkeep │ ├── src │ ├── commands.rs │ ├── commands │ │ ├── format │ │ │ └── list.rs │ │ ├── count.rs │ │ └── parse.rs │ ├── exit.rs │ └── main.rs │ ├── build.rs │ └── Cargo.toml ├── lib ├── xsd │ ├── tests │ │ └── .gitkeep │ ├── examples │ │ └── .gitkeep │ ├── src │ │ └── lib.rs │ ├── Cargo.toml │ └── README.md ├── rdf-borsh │ ├── tests │ │ └── .gitkeep │ ├── examples │ │ └── .gitkeep │ ├── src │ │ ├── borsh_term_id.rs │ │ ├── borsh_triple.rs │ │ ├── borsh_dataset.rs │ │ ├── borsh_header.rs │ │ ├── borsh_writer.rs │ │ ├── borsh_quad.rs │ │ ├── borsh_term.rs │ │ ├── borsh_reader.rs │ │ ├── lib.rs │ │ └── parse.rs │ └── Cargo.toml ├── rdf-model │ ├── tests │ │ └── .gitkeep │ ├── examples │ │ └── .gitkeep │ ├── src │ │ ├── traits │ │ │ ├── countable.rs │ │ │ ├── queryable.rs │ │ │ ├── maybe_durable.rs │ │ │ ├── maybe_indexed.rs │ │ │ ├── maybe_mutable.rs │ │ │ └── enumerable.rs │ │ ├── feature.rs │ │ ├── node.rs │ │ ├── vocabulary.rs │ │ ├── literal.rs │ │ ├── prelude.rs │ │ ├── graph.rs │ │ ├── dataset.rs │ │ ├── document.rs │ │ ├── source.rs │ │ ├── term_kind.rs │ │ ├── term.rs │ │ ├── alloc │ │ │ ├── heap_triple.rs │ │ │ ├── heap_quad.rs │ │ │ └── heap_term.rs │ │ ├── providers │ │ │ ├── sophia.rs │ │ │ └── oxrdf.rs │ │ ├── statement.rs │ │ └── lib.rs │ └── Cargo.toml ├── rdf-query │ ├── tests │ │ └── .gitkeep │ ├── examples │ │ └── .gitkeep │ ├── src │ │ └── lib.rs │ └── Cargo.toml ├── rdf-vocab │ ├── tests │ │ └── .gitkeep │ ├── examples │ │ └── .gitkeep │ ├── src │ │ └── lib.rs │ └── Cargo.toml ├── rdf_rs │ ├── examples │ │ └── .gitkeep │ ├── tests │ │ └── .gitkeep │ ├── src │ │ └── lib.rs │ └── Cargo.toml ├── rdf-derive │ ├── examples │ │ └── .gitkeep │ ├── tests │ │ └── .gitkeep │ ├── src │ │ └── lib.rs │ └── Cargo.toml ├── rdf-format │ ├── examples │ │ └── .gitkeep │ ├── tests │ │ └── .gitkeep │ ├── src │ │ ├── lib.rs │ │ └── format.rs │ └── Cargo.toml ├── rdf-reader │ ├── examples │ │ └── .gitkeep │ ├── tests │ │ └── .gitkeep │ ├── src │ │ ├── providers │ │ │ ├── sophia.rs │ │ │ └── oxrdf.rs │ │ ├── reader_options.rs │ │ ├── reader.rs │ │ ├── open_url.rs │ │ ├── lib.rs │ │ └── open_path.rs │ └── Cargo.toml └── rdf-writer │ ├── examples │ └── .gitkeep │ ├── tests │ └── .gitkeep │ ├── src │ ├── providers │ │ ├── oxrdf.rs │ │ └── sophia.rs │ ├── writer_options.rs │ ├── lib.rs │ └── writer.rs │ └── Cargo.toml ├── .github ├── CODEOWNERS └── workflows │ └── ci.yaml ├── AUTHORS ├── .gitattributes ├── .config └── mise.toml ├── rustfmt.toml ├── CREDITS.md ├── .cargo └── config.toml ├── Makefile ├── .gitignore ├── Rakefile ├── CHANGES.md ├── UNLICENSE ├── Cargo.toml └── README.md /doc/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 0.2.2 2 | -------------------------------------------------------------------------------- /bin/rdf/tests/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/xsd/tests/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/rdf-borsh/tests/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/rdf-model/tests/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/rdf-query/tests/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/rdf-vocab/tests/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/rdf_rs/examples/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/rdf_rs/tests/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/xsd/examples/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @artob 2 | -------------------------------------------------------------------------------- /lib/rdf-borsh/examples/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/rdf-derive/examples/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/rdf-derive/tests/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/rdf-format/examples/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/rdf-format/tests/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/rdf-model/examples/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/rdf-query/examples/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/rdf-reader/examples/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/rdf-reader/tests/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/rdf-vocab/examples/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/rdf-writer/examples/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/rdf-writer/tests/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | * Arto Bendiken 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | Cargo.lock linguist-generated -diff 2 | Rakefile linguist-vendored 3 | -------------------------------------------------------------------------------- /.config/mise.toml: -------------------------------------------------------------------------------- 1 | # See: https://mise.jdx.dev/environments/ 2 | 3 | [env] 4 | _.file = '.env' 5 | -------------------------------------------------------------------------------- /lib/rdf-reader/src/providers/sophia.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | -------------------------------------------------------------------------------- /lib/rdf-writer/src/providers/oxrdf.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | -------------------------------------------------------------------------------- /lib/rdf-writer/src/providers/sophia.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | # See: https://rust-lang.github.io/rustfmt/ 2 | 3 | reorder_imports = true 4 | imports_granularity = "Crate" 5 | -------------------------------------------------------------------------------- /CREDITS.md: -------------------------------------------------------------------------------- 1 | This is a project initiated during the [DBCLS BioHackathon 2024]. 2 | 3 | [DBCLS BioHackathon 2024]: https://2024.biohackathon.org 4 | -------------------------------------------------------------------------------- /lib/rdf-model/src/traits/countable.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | pub use dogma::traits::{Countable, MaybeCountable}; 4 | -------------------------------------------------------------------------------- /lib/rdf-model/src/traits/queryable.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | use super::Enumerable; 4 | 5 | pub trait Queryable: Enumerable {} 6 | -------------------------------------------------------------------------------- /lib/xsd/src/lib.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | //! ```rust 4 | //! # use xsd::*; 5 | //! ``` 6 | 7 | #![no_std] 8 | #![deny(unsafe_code)] 9 | -------------------------------------------------------------------------------- /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | # See: https://doc.rust-lang.org/cargo/reference/config.html 2 | # See: https://docs.shipyard.rs/configuration/git-fetch-with-cli.html 3 | 4 | [net] 5 | git-fetch-with-cli = true 6 | -------------------------------------------------------------------------------- /bin/rdf/src/commands.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | pub mod format { 4 | pub mod list; 5 | } 6 | 7 | pub mod count; 8 | pub mod parse; 9 | -------------------------------------------------------------------------------- /lib/rdf-derive/src/lib.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | //! ```rust 4 | //! # use rdf_derive::*; 5 | //! ``` 6 | 7 | #![no_std] 8 | #![deny(unsafe_code)] 9 | -------------------------------------------------------------------------------- /lib/rdf-query/src/lib.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | //! ```rust 4 | //! # use rdf_query::*; 5 | //! ``` 6 | 7 | #![no_std] 8 | #![deny(unsafe_code)] 9 | -------------------------------------------------------------------------------- /lib/rdf-vocab/src/lib.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | //! ```rust 4 | //! # use rdf_vocab::*; 5 | //! ``` 6 | 7 | #![no_std] 8 | #![deny(unsafe_code)] 9 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CARGO = cargo 2 | 3 | all: Cargo.toml 4 | $(CARGO) build 5 | 6 | check: Cargo.toml 7 | $(CARGO) test -- --nocapture 8 | 9 | clean: Cargo.toml 10 | @rm -rf *~ target 11 | $(CARGO) clean 12 | 13 | .PHONY: all check clean 14 | .SECONDARY: 15 | .SUFFIXES: 16 | -------------------------------------------------------------------------------- /lib/rdf-model/src/feature.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | /// The set of features that are enabled in this build of the crate. 4 | pub static FEATURES: &[&str] = &[ 5 | #[cfg(feature = "serde")] 6 | "serde", 7 | ]; 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # macOS 2 | .DS_Store 3 | 4 | # Environment variables 5 | .env 6 | 7 | # Jetbrains 8 | .idea/ 9 | 10 | # Visual Studio Code 11 | .vscode/ 12 | 13 | # Editor backup files 14 | *~ 15 | 16 | # Rust artifacts 17 | /Cargo.lock 18 | /rust-toolchain 19 | /target 20 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | namespace :version do 2 | desc "Bump the version number" 3 | task :bump do 4 | old_version = File.read('VERSION').strip 5 | new_version = old_version.gsub(/\.\d+$/, &:succ) 6 | warn `git grep -l #{old_version} | xargs sd -F #{old_version} #{new_version}`.chomp 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /lib/rdf-reader/src/reader_options.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | use rdf_format::Format; 4 | 5 | #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] 6 | pub struct ReaderOptions { 7 | pub format: Option, 8 | } 9 | -------------------------------------------------------------------------------- /lib/rdf-writer/src/writer_options.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | use rdf_format::Format; 4 | 5 | #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] 6 | pub struct WriterOptions { 7 | pub format: Option, 8 | } 9 | -------------------------------------------------------------------------------- /lib/rdf-format/src/lib.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | //! ```rust 4 | //! # use rdf_format::*; 5 | //! ``` 6 | 7 | #![no_std] 8 | #![deny(unsafe_code)] 9 | 10 | #[doc(hidden)] 11 | pub use rdf_model::prelude; 12 | 13 | mod format; 14 | pub use format::*; 15 | -------------------------------------------------------------------------------- /lib/rdf-model/src/traits/maybe_durable.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | pub trait MaybeDurable { 4 | fn is_durable(&self) -> bool { 5 | false // by default 6 | } 7 | 8 | fn is_nondurable(&self) -> bool { 9 | !self.is_durable() 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /lib/rdf-model/src/traits/maybe_indexed.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | pub trait MaybeIndexed { 4 | fn is_indexed(&self) -> bool { 5 | false // by default 6 | } 7 | 8 | fn is_unindexed(&self) -> bool { 9 | !self.is_indexed() 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /lib/rdf-model/src/traits/maybe_mutable.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | pub trait MaybeMutable { 4 | fn is_mutable(&self) -> bool { 5 | false // by default 6 | } 7 | 8 | fn is_immutable(&self) -> bool { 9 | !self.is_mutable() 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /bin/rdf/src/commands/format/list.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | use crate::{exit::ExitCode, StandardOptions}; 4 | 5 | #[allow(dead_code)] 6 | pub fn list(_flags: &StandardOptions) -> Result<(), ExitCode> { 7 | unimplemented!("`rdf format list` is not implemented yet") // TODO 8 | } 9 | -------------------------------------------------------------------------------- /lib/rdf-model/src/node.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | /// An RDF node. 4 | #[stability::unstable] 5 | pub trait Node {} 6 | 7 | impl core::fmt::Debug for dyn Node { 8 | fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { 9 | f.debug_struct("Node").finish() 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /lib/rdf-model/src/traits/enumerable.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | extern crate alloc; 4 | 5 | use super::Countable; 6 | use crate::Statement; 7 | use alloc::boxed::Box; 8 | use core::error::Error; 9 | 10 | pub trait Enumerable: 11 | Countable + Iterator, Box>> 12 | { 13 | } 14 | -------------------------------------------------------------------------------- /lib/rdf-model/src/vocabulary.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | /// An RDF vocabulary. 4 | /// 5 | /// See: https://www.w3.org/TR/rdf12-concepts/#dfn-rdf-vocabulary 6 | pub trait Vocabulary {} 7 | 8 | impl core::fmt::Debug for dyn Vocabulary { 9 | fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { 10 | f.debug_struct("Vocabulary").finish() 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /lib/rdf-model/src/literal.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | /// An RDF literal. 4 | /// 5 | /// See: https://www.w3.org/TR/rdf12-concepts/#dfn-literal 6 | #[stability::unstable] 7 | pub trait Literal {} 8 | 9 | impl core::fmt::Debug for dyn Literal { 10 | fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { 11 | f.debug_struct("Literal").finish() 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /lib/rdf-model/src/prelude.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | #![allow(unused)] 4 | 5 | #[cfg(feature = "std")] 6 | extern crate std; 7 | 8 | #[cfg(not(feature = "std"))] 9 | extern crate alloc; 10 | 11 | #[cfg(feature = "std")] 12 | use std as alloc; 13 | 14 | pub use alloc::{ 15 | string::{String, ToString}, 16 | vec, 17 | vec::Vec, 18 | }; 19 | 20 | pub use core::result::Result; 21 | -------------------------------------------------------------------------------- /lib/rdf-model/src/graph.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | use crate::traits::Enumerable; 4 | 5 | /// An RDF graph. 6 | /// 7 | /// See: https://www.w3.org/TR/rdf12-concepts/#dfn-rdf-graph 8 | pub trait Graph: Enumerable {} 9 | 10 | impl core::fmt::Debug for dyn Graph { 11 | fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { 12 | f.debug_struct("Graph").finish() 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /lib/rdf-model/src/dataset.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | use crate::traits::Enumerable; 4 | 5 | /// An RDF dataset. 6 | /// 7 | /// See: https://www.w3.org/TR/rdf12-concepts/#dfn-rdf-dataset 8 | pub trait Dataset: Enumerable {} 9 | 10 | impl core::fmt::Debug for dyn Dataset { 11 | fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { 12 | f.debug_struct("Dataset").finish() 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /lib/rdf-model/src/document.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | use crate::traits::Enumerable; 4 | 5 | /// An RDF document. 6 | /// 7 | /// See: https://www.w3.org/TR/rdf12-concepts/#dfn-rdf-document 8 | pub trait Document: Enumerable {} 9 | 10 | impl core::fmt::Debug for dyn Document { 11 | fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { 12 | f.debug_struct("Document").finish() 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /lib/rdf_rs/src/lib.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | //! ```rust,compile_fail 4 | //! # use rdf::*; 5 | //! ``` 6 | 7 | pub use rdf_derive as derive; 8 | pub use rdf_format as format; 9 | pub use rdf_model as model; 10 | pub use rdf_query as query; 11 | pub use rdf_reader as reader; 12 | pub use rdf_vocab as vocab; 13 | pub use rdf_writer as writer; 14 | 15 | #[doc = include_str!("../../../README.md")] 16 | #[cfg(doctest)] 17 | pub struct ReadmeDoctests; 18 | -------------------------------------------------------------------------------- /lib/rdf-reader/src/reader.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | extern crate alloc; 4 | 5 | pub use rdf_format::Format; 6 | pub use rdf_model::Source; 7 | 8 | pub trait Reader: Source { 9 | fn format(&self) -> Format; 10 | } 11 | 12 | impl core::fmt::Debug for dyn Reader { 13 | fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { 14 | f.debug_struct("Reader") 15 | .field("format", &self.format()) 16 | .finish() 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lib/rdf-model/src/source.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | use crate::traits::{Enumerable, MaybeDurable, MaybeIndexed, MaybeMutable}; 4 | 5 | /// An RDF source. 6 | /// 7 | /// See: https://www.w3.org/TR/rdf12-concepts/#dfn-rdf-source 8 | pub trait Source: Enumerable + MaybeDurable + MaybeIndexed + MaybeMutable {} 9 | 10 | impl core::fmt::Debug for dyn Source { 11 | fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { 12 | f.debug_struct("Source").finish() 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /lib/rdf-reader/src/open_url.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | extern crate std; 4 | 5 | use crate::{Reader, ReaderOptions}; 6 | use rdf_format::Format; 7 | use std::{boxed::Box, io::Result, string::String}; 8 | 9 | #[stability::unstable] 10 | pub fn open_url(_input_url: &String, options: Option) -> Result> { 11 | let options = options.unwrap_or_default(); 12 | let _input_format = options.format.unwrap_or_else(|| Format::Turtle); 13 | 14 | todo!() // TODO 15 | } 16 | -------------------------------------------------------------------------------- /CHANGES.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## 0.2.2 - 2025-05-06 9 | 10 | ## 0.2.1 - 2025-04-18 11 | 12 | ## 0.2.0 - 2025-01-18 13 | 14 | ## 0.1.1 - 2024-12-29 15 | 16 | ## 0.1.0 - 2024-12-05 17 | 18 | ## 0.0.1 - 2024-09-08 19 | 20 | ## 0.0.0 - 2024-08-27 21 | ### Added 22 | - Initial crate structure and interdependencies. 23 | -------------------------------------------------------------------------------- /lib/xsd/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "xsd" 3 | version.workspace = true 4 | authors.workspace = true 5 | edition.workspace = true 6 | rust-version.workspace = true 7 | description = "XSD.rs" 8 | #documentation = "https://docs.rs/xsd/" 9 | readme = "README.md" 10 | homepage.workspace = true 11 | repository.workspace = true 12 | license.workspace = true 13 | keywords = ["xml", "schema", "xsd"] 14 | categories.workspace = true 15 | publish.workspace = true 16 | 17 | [features] 18 | default = ["all", "std"] 19 | all = [] 20 | std = [] 21 | unstable = [] 22 | 23 | [dependencies] 24 | -------------------------------------------------------------------------------- /lib/rdf-writer/src/lib.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | //! ```rust 4 | //! # use rdf_writer::*; 5 | //! ``` 6 | 7 | #![no_std] 8 | #![deny(unsafe_code)] 9 | #![allow(unused_imports)] 10 | 11 | mod writer; 12 | pub use writer::*; 13 | 14 | mod writer_options; 15 | pub use writer_options::*; 16 | 17 | mod providers { 18 | #[cfg(feature = "oxrdf")] 19 | mod oxrdf; 20 | #[cfg(feature = "oxrdf")] 21 | pub use oxrdf::*; 22 | #[cfg(feature = "sophia")] 23 | mod sophia; 24 | #[cfg(feature = "sophia")] 25 | pub use sophia::*; 26 | } 27 | -------------------------------------------------------------------------------- /bin/rdf/build.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | use std::collections::BTreeSet; 4 | 5 | fn main() -> std::io::Result<()> { 6 | // See: https://github.com/baoyachi/shadow-rs 7 | // Omit all nonpublic and/or sensitive information: 8 | let mut omit = BTreeSet::new(); 9 | omit.insert(shadow_rs::CARGO_TREE); 10 | omit.insert(shadow_rs::CARGO_MANIFEST_DIR); 11 | omit.insert(shadow_rs::COMMIT_AUTHOR); 12 | omit.insert(shadow_rs::COMMIT_EMAIL); 13 | omit.insert(shadow_rs::GIT_STATUS_FILE); 14 | shadow_rs::new_deny(omit).unwrap(); 15 | 16 | Ok(()) 17 | } 18 | -------------------------------------------------------------------------------- /lib/rdf-query/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rdf-query" 3 | version.workspace = true 4 | authors.workspace = true 5 | edition.workspace = true 6 | rust-version.workspace = true 7 | description.workspace = true 8 | #documentation.workspace = true 9 | readme.workspace = true 10 | homepage.workspace = true 11 | repository.workspace = true 12 | license.workspace = true 13 | keywords.workspace = true 14 | categories.workspace = true 15 | publish.workspace = true 16 | 17 | [features] 18 | default = ["all", "std"] 19 | all = [] 20 | std = ["rdf-model/std"] 21 | unstable = ["rdf-model/unstable"] 22 | 23 | [dependencies] 24 | rdf-model.workspace = true 25 | -------------------------------------------------------------------------------- /lib/rdf-vocab/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rdf-vocab" 3 | version.workspace = true 4 | authors.workspace = true 5 | edition.workspace = true 6 | rust-version.workspace = true 7 | description.workspace = true 8 | #documentation.workspace = true 9 | readme.workspace = true 10 | homepage.workspace = true 11 | repository.workspace = true 12 | license.workspace = true 13 | keywords.workspace = true 14 | categories.workspace = true 15 | publish.workspace = true 16 | 17 | [features] 18 | default = ["all", "std"] 19 | all = [] 20 | std = ["rdf-model/std"] 21 | unstable = ["rdf-model/unstable"] 22 | 23 | [dependencies] 24 | rdf-model.workspace = true 25 | -------------------------------------------------------------------------------- /bin/rdf/src/commands/count.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | use crate::{exit::ExitCode, StandardOptions, Utf8PathBuf}; 4 | 5 | pub fn count(mut input_paths: Vec, flags: &StandardOptions) -> Result<(), ExitCode> { 6 | let mut count = 0usize; 7 | 8 | input_paths.dedup(); 9 | 10 | for input_path in input_paths { 11 | let reader = rdf_reader::open_path(&input_path, None)?; 12 | if flags.debug { 13 | eprintln!("{:?}", reader); 14 | } 15 | 16 | count += reader.count(); 17 | } 18 | 19 | println!("{}", count); 20 | Ok(()) 21 | } 22 | -------------------------------------------------------------------------------- /lib/rdf-model/src/term_kind.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] 4 | pub enum TermKind { 5 | Iri, 6 | BNode, 7 | Literal, 8 | } 9 | 10 | #[cfg(feature = "sophia")] 11 | impl From for TermKind { 12 | fn from(kind: sophia::api::term::TermKind) -> Self { 13 | use sophia::api::term::TermKind::*; 14 | match kind { 15 | Iri => Self::Iri, 16 | BlankNode => Self::BNode, 17 | Literal => Self::Literal, 18 | _ => todo!(), // TODO 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/rdf-writer/src/writer.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | extern crate alloc; 4 | 5 | use core::result::Result; 6 | use rdf_model::Statement; 7 | 8 | pub use rdf_format::Format; 9 | 10 | pub trait Writer { 11 | type Error; 12 | 13 | fn format(&self) -> Format; 14 | 15 | fn write_statement(&mut self, statement: &dyn Statement) -> Result<(), Self::Error>; 16 | } 17 | 18 | impl core::fmt::Debug for dyn Writer { 19 | fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { 20 | f.debug_struct("Writer") 21 | .field("format", &self.format()) 22 | .finish() 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/rdf-reader/src/lib.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | //! ```rust 4 | //! # use rdf_reader::*; 5 | //! ``` 6 | 7 | #![no_std] 8 | #![deny(unsafe_code)] 9 | 10 | #[cfg(feature = "std")] 11 | mod open_path; 12 | #[cfg(feature = "std")] 13 | pub use open_path::*; 14 | 15 | #[cfg(feature = "std")] 16 | mod open_url; 17 | #[cfg(feature = "std")] 18 | pub use open_url::*; 19 | 20 | mod reader; 21 | pub use reader::*; 22 | 23 | mod reader_options; 24 | pub use reader_options::*; 25 | 26 | mod providers { 27 | #[cfg(feature = "oxrdf")] 28 | mod oxrdf; 29 | #[cfg(feature = "oxrdf")] 30 | pub use oxrdf::*; 31 | #[cfg(feature = "sophia")] 32 | mod sophia; 33 | #[cfg(feature = "sophia")] 34 | pub use sophia::*; 35 | } 36 | -------------------------------------------------------------------------------- /bin/rdf/src/commands/parse.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | use crate::{exit::ExitCode, StandardOptions, Utf8PathBuf}; 4 | 5 | pub fn parse(mut input_paths: Vec, flags: &StandardOptions) -> Result<(), ExitCode> { 6 | input_paths.dedup(); 7 | 8 | for input_path in input_paths { 9 | let reader = rdf_reader::open_path(&input_path, None)?; 10 | if flags.debug { 11 | eprintln!("{:?}", reader); 12 | } 13 | 14 | for statement in reader { 15 | if flags.debug { 16 | eprintln!("{:?}", statement); 17 | } else if flags.verbose > 0 { 18 | println!("{:?}", statement); // TODO 19 | } 20 | } 21 | } 22 | 23 | Ok(()) 24 | } 25 | -------------------------------------------------------------------------------- /lib/rdf-model/src/term.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | extern crate alloc; 4 | 5 | use crate::TermKind; 6 | use alloc::borrow::Cow; 7 | 8 | /// An RDF term. 9 | /// 10 | /// See: https://www.w3.org/TR/rdf12-concepts/#dfn-rdf-term 11 | pub trait Term { 12 | fn kind(&self) -> TermKind; 13 | 14 | fn is_iri(&self) -> bool { 15 | self.kind() == TermKind::Iri 16 | } 17 | 18 | fn is_bnode(&self) -> bool { 19 | self.kind() == TermKind::BNode 20 | } 21 | 22 | fn is_literal(&self) -> bool { 23 | self.kind() == TermKind::Literal 24 | } 25 | 26 | fn as_str(&self) -> Cow; 27 | } 28 | 29 | impl core::fmt::Debug for dyn Term { 30 | fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { 31 | f.debug_struct("Term").finish() 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lib/rdf-model/src/alloc/heap_triple.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | use crate::{HeapTerm, Statement, Term}; 4 | 5 | /// A heap-allocated triple statement. 6 | #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] 7 | #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 8 | pub struct HeapTriple { 9 | s: HeapTerm, 10 | p: HeapTerm, 11 | o: HeapTerm, 12 | } 13 | 14 | impl Statement for HeapTriple { 15 | fn subject(&self) -> &dyn Term { 16 | &self.s 17 | } 18 | 19 | fn predicate(&self) -> &dyn Term { 20 | &self.p 21 | } 22 | 23 | fn object(&self) -> &dyn Term { 24 | &self.o 25 | } 26 | } 27 | 28 | impl From<(HeapTerm, HeapTerm, HeapTerm)> for HeapTriple { 29 | fn from((s, p, o): (HeapTerm, HeapTerm, HeapTerm)) -> Self { 30 | Self { s, p, o } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lib/rdf-derive/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rdf-derive" 3 | version.workspace = true 4 | authors.workspace = true 5 | edition.workspace = true 6 | rust-version.workspace = true 7 | description.workspace = true 8 | #documentation.workspace = true 9 | readme.workspace = true 10 | homepage.workspace = true 11 | repository.workspace = true 12 | license.workspace = true 13 | keywords = ["rdf", "derive", "macro"] 14 | categories = ["development-tools::procedural-macro-helpers"] 15 | publish.workspace = true 16 | 17 | [lib] 18 | proc-macro = true 19 | 20 | [features] 21 | default = ["all", "std"] 22 | all = [] 23 | std = ["rdf-model/std"] 24 | unstable = ["rdf-model/unstable"] 25 | 26 | [dependencies] 27 | proc-macro2 = { version = "1", default-features = false } 28 | proc-macro-crate = "3.2" 29 | quote = { version = "1", default-features = false } 30 | syn = { version = "2", default-features = true } 31 | 32 | [dev-dependencies] 33 | rdf-model.workspace = true 34 | -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | # See: https://docs.github.com/en/actions/writing-workflows 2 | --- 3 | name: CI 4 | 5 | on: 6 | push: 7 | branches: [master] 8 | pull_request: 9 | branches: [master] 10 | 11 | env: 12 | CARGO_TERM_COLOR: always 13 | 14 | jobs: 15 | build-ubuntu: 16 | name: Build on Ubuntu 17 | runs-on: ubuntu-latest 18 | steps: 19 | - name: Checkout 20 | uses: actions/checkout@v4 21 | - name: Build 22 | run: cargo build 23 | - name: Build examples 24 | run: cargo build --examples 25 | - name: Run tests 26 | run: cargo test 27 | build-windows: 28 | name: Build on Windows 29 | runs-on: windows-latest 30 | steps: 31 | - name: Checkout 32 | uses: actions/checkout@v4 33 | - name: Build 34 | run: cargo build 35 | - name: Build examples 36 | run: cargo build --examples 37 | - name: Run tests 38 | run: cargo test 39 | -------------------------------------------------------------------------------- /lib/rdf-reader/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rdf-reader" 3 | version.workspace = true 4 | authors.workspace = true 5 | edition.workspace = true 6 | rust-version.workspace = true 7 | description.workspace = true 8 | #documentation.workspace = true 9 | readme.workspace = true 10 | homepage.workspace = true 11 | repository.workspace = true 12 | license.workspace = true 13 | keywords.workspace = true 14 | categories.workspace = true 15 | publish.workspace = true 16 | 17 | [features] 18 | default = ["all", "std"] 19 | all = ["rdf-star", "serde"] 20 | oxrdf = ["rdf-model/oxrdf", "dep:oxrdfio"] 21 | rdf-star = ["oxrdfio?/rdf-star", "rdf-format/rdf-star", "rdf-model/rdf-star"] 22 | serde = ["rdf-model/serde"] 23 | sophia = ["rdf-model/sophia", "dep:sophia"] 24 | std = ["rdf-model/std"] 25 | unstable = ["rdf-model/unstable"] 26 | 27 | [dependencies] 28 | oxrdfio = { version = "0.1", default-features = false, optional = true } 29 | rdf-format.workspace = true 30 | rdf-model.workspace = true 31 | sophia = { version = "0.9", default-features = false, optional = true } 32 | stability = "0.2" 33 | -------------------------------------------------------------------------------- /lib/rdf-writer/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rdf-writer" 3 | version.workspace = true 4 | authors.workspace = true 5 | edition.workspace = true 6 | rust-version.workspace = true 7 | description.workspace = true 8 | #documentation.workspace = true 9 | readme.workspace = true 10 | homepage.workspace = true 11 | repository.workspace = true 12 | license.workspace = true 13 | keywords.workspace = true 14 | categories.workspace = true 15 | publish.workspace = true 16 | 17 | [features] 18 | default = ["all", "std"] 19 | all = ["rdf-star", "serde"] 20 | oxrdf = ["rdf-model/oxrdf", "dep:oxrdfio"] 21 | rdf-star = ["oxrdfio?/rdf-star", "rdf-format/rdf-star", "rdf-model/rdf-star"] 22 | serde = ["rdf-model/serde"] 23 | sophia = ["rdf-model/sophia", "dep:sophia"] 24 | std = ["rdf-model/std"] 25 | unstable = ["rdf-model/unstable"] 26 | 27 | [dependencies] 28 | oxrdfio = { version = "0.1", default-features = false, optional = true } 29 | rdf-format.workspace = true 30 | rdf-model.workspace = true 31 | sophia = { version = "0.9", default-features = false, optional = true } 32 | stability = "0.2" 33 | -------------------------------------------------------------------------------- /bin/rdf/src/exit.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | use clientele::SysexitsError; 4 | 5 | #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] 6 | pub struct ExitCode(pub SysexitsError); 7 | 8 | impl core::fmt::Display for ExitCode { 9 | fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { 10 | write!(f, "{}", self.0) 11 | } 12 | } 13 | 14 | impl std::process::Termination for ExitCode { 15 | fn report(self) -> std::process::ExitCode { 16 | self.0.report() 17 | } 18 | } 19 | 20 | impl core::error::Error for ExitCode {} 21 | 22 | impl From> for ExitCode { 23 | fn from(error: std::boxed::Box) -> Self { 24 | std::eprintln!("rdf: {:?}", error); 25 | Self(SysexitsError::from(error)) 26 | } 27 | } 28 | 29 | impl From for ExitCode { 30 | fn from(error: std::io::Error) -> Self { 31 | std::eprintln!("rdf: {:?}", error); 32 | Self(SysexitsError::from(error)) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/rdf-model/src/providers/sophia.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | extern crate alloc; 4 | 5 | use crate::{Term, TermKind}; 6 | use alloc::borrow::Cow; 7 | use sophia::api::term::SimpleTerm; 8 | 9 | pub struct SophiaTerm<'a> { 10 | inner: SimpleTerm<'a>, 11 | } 12 | 13 | impl<'a> Term for SophiaTerm<'a> { 14 | fn kind(&self) -> TermKind { 15 | use sophia::api::term::Term; 16 | self.inner.kind().into() 17 | } 18 | 19 | fn as_str(&self) -> Cow { 20 | match &self.inner { 21 | SimpleTerm::Iri(iri) => Cow::Borrowed(iri.as_str()), 22 | SimpleTerm::BlankNode(id) => Cow::Borrowed(id.as_str()), 23 | SimpleTerm::LiteralDatatype(value, _iri) => Cow::Borrowed(value.as_ref()), // TODO 24 | SimpleTerm::LiteralLanguage(value, _lang) => Cow::Borrowed(value.as_ref()), // TODO 25 | SimpleTerm::Triple(_) => todo!(), // TODO 26 | SimpleTerm::Variable(_) => todo!(), // TODO 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/rdf-format/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rdf-format" 3 | version.workspace = true 4 | authors.workspace = true 5 | edition.workspace = true 6 | rust-version.workspace = true 7 | description.workspace = true 8 | #documentation.workspace = true 9 | readme.workspace = true 10 | homepage.workspace = true 11 | repository.workspace = true 12 | license.workspace = true 13 | keywords.workspace = true 14 | categories.workspace = true 15 | publish.workspace = true 16 | 17 | [features] 18 | default = ["all", "std"] 19 | all = ["rdf-star", "serde"] 20 | oxrdf = ["rdf-model/oxrdf", "dep:oxrdfio"] 21 | rdf-star = ["oxrdfio?/rdf-star", "rdf-model/rdf-star"] 22 | serde = ["rdf-model/serde", "dep:serde"] 23 | sophia = ["rdf-model/sophia", "dep:sophia"] 24 | std = ["dogma/std", "rdf-model/std", "serde?/std"] 25 | unstable = ["rdf-model/unstable"] 26 | 27 | [dependencies] 28 | dogma.workspace = true 29 | oxrdfio = { version = "0.1", default-features = false, optional = true } 30 | rdf-model.workspace = true 31 | serde = { version = "1.0", default-features = false, features = [ 32 | "derive", 33 | ], optional = true } 34 | sophia = { version = "0.9", default-features = false, optional = true } 35 | -------------------------------------------------------------------------------- /lib/rdf-model/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rdf-model" 3 | version.workspace = true 4 | authors.workspace = true 5 | edition.workspace = true 6 | rust-version.workspace = true 7 | description.workspace = true 8 | #documentation.workspace = true 9 | readme.workspace = true 10 | homepage.workspace = true 11 | repository.workspace = true 12 | license.workspace = true 13 | keywords.workspace = true 14 | categories.workspace = true 15 | publish.workspace = true 16 | 17 | [features] 18 | default = ["all", "std"] 19 | all = ["rdf-star", "serde"] 20 | borsh = ["dep:borsh"] 21 | oxrdf = ["dep:oxrdf"] 22 | rdf-star = ["oxrdf?/rdf-star"] 23 | serde = ["dep:serde"] 24 | sophia = ["dep:sophia"] 25 | std = ["dogma/std", "serde?/std"] 26 | unstable = [] 27 | 28 | [dependencies] 29 | borsh = { version = "1.5", default-features = false, features = [ 30 | "derive", 31 | ], optional = true } 32 | dogma.workspace = true 33 | oxrdf = { version = "0.2", default-features = false, optional = true } 34 | serde = { version = "1.0", default-features = false, features = [ 35 | "derive", 36 | ], optional = true } 37 | sophia = { version = "0.9", default-features = false, optional = true } 38 | stability = "0.2" 39 | -------------------------------------------------------------------------------- /lib/rdf-borsh/src/borsh_term_id.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | use borsh::{BorshDeserialize, BorshSerialize}; 4 | use num_integer::Integer; 5 | use num_traits::FromPrimitive; 6 | 7 | #[derive( 8 | Clone, 9 | Copy, 10 | Debug, 11 | Default, 12 | Eq, 13 | Hash, 14 | Ord, 15 | PartialEq, 16 | PartialOrd, 17 | BorshSerialize, 18 | BorshDeserialize, 19 | )] 20 | pub struct BorshTermId(T); 21 | 22 | impl BorshTermId { 23 | pub fn is_zero(&self) -> bool { 24 | self.0.is_zero() 25 | } 26 | } 27 | 28 | impl From for BorshTermId { 29 | fn from(value: u16) -> Self { 30 | Self(value) 31 | } 32 | } 33 | 34 | impl FromPrimitive for BorshTermId { 35 | fn from_i64(n: i64) -> Option { 36 | if n <= u16::MAX as _ && n >= 0 { 37 | Some(Self(n as u16)) 38 | } else { 39 | None // overflow 40 | } 41 | } 42 | 43 | fn from_u64(n: u64) -> Option { 44 | if n <= u16::MAX as _ { 45 | Some(Self(n as u16)) 46 | } else { 47 | None // overflow 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /bin/rdf/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rdf-cli" 3 | version.workspace = true 4 | authors.workspace = true 5 | edition.workspace = true 6 | rust-version.workspace = true 7 | description.workspace = true 8 | #documentation.workspace = true 9 | readme.workspace = true 10 | homepage.workspace = true 11 | repository.workspace = true 12 | license.workspace = true 13 | keywords = ["rdf", "cli"] 14 | categories = ["command-line-utilities"] 15 | publish.workspace = true 16 | 17 | [features] 18 | default = ["all", "std", "unstable"] 19 | all = ["rdf/all"] 20 | std = ["rdf/std"] 21 | unstable = ["rdf/unstable"] 22 | 23 | [build-dependencies] 24 | shadow-rs = { version = "0.36", default-features = false, features = ["tzdb"] } 25 | 26 | [dependencies] 27 | clap = { version = "4.5", default-features = false } 28 | clientele = { version = "0.2", default-features = true } 29 | rdf.workspace = true 30 | rdf-borsh.workspace = true 31 | rdf-derive.workspace = true 32 | rdf-format.workspace = true 33 | rdf-model.workspace = true 34 | rdf-query.workspace = true 35 | rdf-reader.workspace = true 36 | rdf-vocab.workspace = true 37 | rdf-writer.workspace = true 38 | 39 | [[bin]] 40 | name = "rdf" 41 | path = "src/main.rs" 42 | required-features = [] 43 | -------------------------------------------------------------------------------- /lib/rdf-model/src/statement.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | #[cfg(feature = "oxrdf")] 4 | extern crate alloc; 5 | 6 | use crate::{providers, Term}; 7 | 8 | #[cfg(feature = "oxrdf")] 9 | use alloc::boxed::Box; 10 | 11 | /// An RDF statement. 12 | /// 13 | /// See: https://www.w3.org/TR/rdf12-concepts/#dfn-rdf-statement 14 | pub trait Statement { 15 | fn subject(&self) -> &dyn Term; 16 | 17 | fn predicate(&self) -> &dyn Term; 18 | 19 | fn object(&self) -> &dyn Term; 20 | 21 | fn context(&self) -> Option<&dyn Term> { 22 | None 23 | } 24 | } 25 | 26 | impl core::fmt::Debug for dyn Statement { 27 | fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { 28 | f.debug_struct("Statement") 29 | .field("subject", &self.subject().as_str()) 30 | .field("predicate", &self.predicate().as_str()) 31 | .field("object", &self.object().as_str()) 32 | .field("context", &self.context().map(|t| t.as_str())) 33 | .finish() 34 | } 35 | } 36 | 37 | #[cfg(feature = "oxrdf")] 38 | impl From for Box { 39 | fn from(quad: oxrdf::Quad) -> Self { 40 | Box::new(providers::OxrdfStatement::new(quad)) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /UNLICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /lib/rdf-borsh/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rdf-borsh" 3 | version.workspace = true 4 | authors.workspace = true 5 | edition.workspace = true 6 | rust-version.workspace = true 7 | description.workspace = true 8 | #documentation.workspace = true 9 | readme.workspace = true 10 | homepage.workspace = true 11 | repository.workspace = true 12 | license.workspace = true 13 | keywords.workspace = true 14 | categories.workspace = true 15 | publish.workspace = true 16 | 17 | [features] 18 | default = ["all", "std"] 19 | all = [] 20 | std = [ 21 | "borsh/std", 22 | "rdf-model/std", 23 | "rdf-reader/std", 24 | "rdf-writer/std", 25 | "winnow/std", 26 | ] 27 | unstable = ["rdf-model/unstable", "rdf-reader/unstable", "rdf-writer/unstable"] 28 | 29 | [dependencies] 30 | borsh = { version = "1.5", default-features = false, features = ["derive"] } 31 | lz4_flex = { version = "0.11", default-features = true } 32 | num-traits = { version = "0.2", default-features = false } 33 | num-integer = { version = "0.1", default-features = false } 34 | rdf-model = { workspace = true, features = ["borsh"] } 35 | rdf-reader.workspace = true 36 | rdf-writer.workspace = true 37 | winnow = { version = "0.7", default-features = false, features = ["simd"] } 38 | 39 | [dev-dependencies] 40 | tempfile = { version = "3.15", default-features = false } 41 | -------------------------------------------------------------------------------- /lib/rdf-model/src/alloc/heap_quad.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | use crate::{HeapTerm, Statement, Term}; 4 | 5 | /// A heap-allocated quad statement. 6 | #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] 7 | #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 8 | pub struct HeapQuad { 9 | s: HeapTerm, 10 | p: HeapTerm, 11 | o: HeapTerm, 12 | g: Option, 13 | } 14 | 15 | impl Statement for HeapQuad { 16 | fn subject(&self) -> &dyn Term { 17 | &self.s 18 | } 19 | 20 | fn predicate(&self) -> &dyn Term { 21 | &self.p 22 | } 23 | 24 | fn object(&self) -> &dyn Term { 25 | &self.o 26 | } 27 | 28 | fn context(&self) -> Option<&dyn Term> { 29 | self.g.as_ref().map(|g| g as &dyn Term) 30 | } 31 | } 32 | 33 | impl From<(HeapTerm, HeapTerm, HeapTerm)> for HeapQuad { 34 | fn from((s, p, o): (HeapTerm, HeapTerm, HeapTerm)) -> Self { 35 | Self { s, p, o, g: None } 36 | } 37 | } 38 | 39 | impl From<(HeapTerm, HeapTerm, HeapTerm, HeapTerm)> for HeapQuad { 40 | fn from((s, p, o, g): (HeapTerm, HeapTerm, HeapTerm, HeapTerm)) -> Self { 41 | Self { 42 | s, 43 | p, 44 | o, 45 | g: Some(g), 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /lib/rdf-borsh/src/borsh_triple.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | use crate::{BorshQuad, BorshTermId}; 4 | use borsh::{BorshDeserialize, BorshSerialize}; 5 | use num_integer::Integer; 6 | 7 | #[derive( 8 | Clone, 9 | Copy, 10 | Debug, 11 | Default, 12 | Eq, 13 | Hash, 14 | Ord, 15 | PartialEq, 16 | PartialOrd, 17 | BorshSerialize, 18 | BorshDeserialize, 19 | )] 20 | pub struct BorshTriple { 21 | pub subject: BorshTermId, 22 | pub predicate: BorshTermId, 23 | pub object: BorshTermId, 24 | } 25 | 26 | impl BorshTriple { 27 | pub fn new(subject: BorshTermId, predicate: BorshTermId, object: BorshTermId) -> Self { 28 | Self { 29 | subject, 30 | predicate, 31 | object, 32 | } 33 | } 34 | } 35 | 36 | impl From> for BorshTriple { 37 | fn from(triple: BorshQuad) -> Self { 38 | Self::new(triple.subject, triple.predicate, triple.object) 39 | } 40 | } 41 | 42 | impl From<(BorshTermId, BorshTermId, BorshTermId)> for BorshTriple { 43 | fn from( 44 | (subject, predicate, object): (BorshTermId, BorshTermId, BorshTermId), 45 | ) -> Self { 46 | Self::new(subject, predicate, object) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /lib/rdf-reader/src/open_path.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | extern crate std; 4 | 5 | use crate::{Reader, ReaderOptions}; 6 | use rdf_format::Format; 7 | use std::{ 8 | boxed::Box, 9 | fs::File, 10 | io::{BufReader, Read, Result}, 11 | path::Path, 12 | }; 13 | 14 | #[stability::unstable] 15 | pub fn open_path( 16 | input_path: impl AsRef, 17 | options: Option, 18 | ) -> Result> { 19 | let options = options.unwrap_or_default(); 20 | let input_format = options.format.unwrap_or_else(|| Format::Turtle); // TODO: from file extension 21 | let input_file = File::open(&input_path)?; 22 | let input_reader = BufReader::new(input_file); 23 | 24 | for_reader( 25 | input_reader, 26 | ReaderOptions { 27 | format: Some(input_format), 28 | ..options 29 | }, 30 | ) 31 | } 32 | 33 | #[stability::unstable] 34 | pub fn for_reader(reader: R, options: ReaderOptions) -> Result> { 35 | let input_format = options.format.expect("format must be specified"); 36 | let input = match input_format { 37 | #[cfg(feature = "oxrdf")] 38 | Format::Notation3 39 | | Format::NQuads 40 | | Format::NTriples 41 | | Format::RdfXml 42 | | Format::TriG 43 | | Format::Turtle => Box::new(crate::providers::OxrdfReader::new(reader, options)), 44 | 45 | _ => unimplemented!(), 46 | }; 47 | Ok(input) 48 | } 49 | -------------------------------------------------------------------------------- /lib/rdf_rs/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rdf_rs" 3 | version.workspace = true 4 | authors.workspace = true 5 | edition.workspace = true 6 | rust-version.workspace = true 7 | description.workspace = true 8 | #documentation.workspace = true 9 | readme.workspace = true 10 | homepage.workspace = true 11 | repository.workspace = true 12 | license.workspace = true 13 | keywords.workspace = true 14 | categories.workspace = true 15 | publish.workspace = true 16 | 17 | [features] 18 | default = ["all", "std"] 19 | all = ["oxrdf", "serde"] 20 | oxrdf = [ 21 | "rdf-format/oxrdf", 22 | "rdf-model/oxrdf", 23 | "rdf-reader/oxrdf", 24 | "rdf-writer/oxrdf", 25 | ] 26 | serde = [ 27 | "rdf-format/serde", 28 | "rdf-model/serde", 29 | "rdf-reader/serde", 30 | "rdf-writer/serde", 31 | ] 32 | sophia = [ 33 | "rdf-format/sophia", 34 | "rdf-model/sophia", 35 | "rdf-reader/sophia", 36 | "rdf-writer/sophia", 37 | ] 38 | std = [ 39 | "rdf-derive/std", 40 | "rdf-format/std", 41 | "rdf-model/std", 42 | "rdf-query/std", 43 | "rdf-reader/std", 44 | "rdf-vocab/std", 45 | "rdf-writer/std", 46 | ] 47 | unstable = [ 48 | "rdf-derive/unstable", 49 | "rdf-format/unstable", 50 | "rdf-model/unstable", 51 | "rdf-query/unstable", 52 | "rdf-reader/unstable", 53 | "rdf-vocab/unstable", 54 | "rdf-writer/unstable", 55 | ] 56 | 57 | [dependencies] 58 | rdf-derive.workspace = true 59 | rdf-format.workspace = true 60 | rdf-model.workspace = true 61 | rdf-query.workspace = true 62 | rdf-reader.workspace = true 63 | rdf-vocab.workspace = true 64 | rdf-writer.workspace = true 65 | -------------------------------------------------------------------------------- /lib/rdf-model/src/lib.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | //! ```rust 4 | //! # use rdf_model::*; 5 | //! ``` 6 | 7 | #![no_std] 8 | #![deny(unsafe_code)] 9 | #![allow(unused_imports)] 10 | 11 | #[doc(hidden)] 12 | pub mod prelude; 13 | 14 | mod alloc { 15 | mod heap_quad; 16 | pub use heap_quad::*; 17 | mod heap_term; 18 | pub use heap_term::*; 19 | mod heap_triple; 20 | pub use heap_triple::*; 21 | } 22 | pub use alloc::*; 23 | 24 | mod dataset; 25 | pub use dataset::*; 26 | 27 | mod document; 28 | pub use document::*; 29 | 30 | mod feature; 31 | pub use feature::*; 32 | 33 | mod graph; 34 | pub use graph::*; 35 | 36 | mod literal; 37 | pub use literal::*; 38 | 39 | mod node; 40 | pub use node::*; 41 | 42 | mod source; 43 | pub use source::*; 44 | 45 | mod statement; 46 | pub use statement::*; 47 | 48 | mod term; 49 | pub use term::*; 50 | 51 | mod term_kind; 52 | pub use term_kind::*; 53 | 54 | mod vocabulary; 55 | pub use vocabulary::*; 56 | 57 | mod traits { 58 | mod countable; 59 | pub use countable::*; 60 | 61 | mod enumerable; 62 | pub use enumerable::*; 63 | 64 | mod maybe_durable; 65 | pub use maybe_durable::*; 66 | 67 | mod maybe_indexed; 68 | pub use maybe_indexed::*; 69 | 70 | mod maybe_mutable; 71 | pub use maybe_mutable::*; 72 | 73 | mod queryable; 74 | pub use queryable::*; 75 | } 76 | pub use traits::*; 77 | 78 | mod providers { 79 | #[cfg(feature = "oxrdf")] 80 | mod oxrdf; 81 | #[cfg(feature = "oxrdf")] 82 | pub use oxrdf::*; 83 | #[cfg(feature = "sophia")] 84 | mod sophia; 85 | #[cfg(feature = "sophia")] 86 | pub use sophia::*; 87 | } 88 | -------------------------------------------------------------------------------- /lib/rdf-borsh/src/borsh_dataset.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | extern crate alloc; 4 | 5 | use crate::{BorshQuad, BorshTerm, BorshTermId, BorshTriple}; 6 | use alloc::{ 7 | collections::{BTreeMap, BTreeSet}, 8 | vec::Vec, 9 | }; 10 | use borsh::{BorshDeserialize, BorshSerialize}; 11 | use num_traits::FromPrimitive; 12 | 13 | #[derive(Clone, Debug, Default, Eq, PartialEq, BorshSerialize, BorshDeserialize)] 14 | pub struct BorshDataset { 15 | pub terms_dict: Vec, 16 | pub quads_set: BTreeSet>, 17 | #[borsh(skip)] 18 | terms_map: BTreeMap>, 19 | } 20 | 21 | impl BorshDataset { 22 | pub fn new() -> Self { 23 | Self { 24 | terms_dict: Vec::new(), 25 | quads_set: BTreeSet::new(), 26 | terms_map: BTreeMap::new(), 27 | } 28 | } 29 | 30 | pub fn quad_count(&self) -> usize { 31 | self.quads_set.len() 32 | } 33 | 34 | pub fn intern_term(&mut self, term: BorshTerm) -> core::result::Result, ()> { 35 | if let Some(&term_id) = self.terms_map.get(&term) { 36 | return Ok(term_id); 37 | } 38 | let term_id: BorshTermId = 39 | BorshTermId::from_usize(self.terms_dict.len() + 1).ok_or(())?; 40 | self.terms_dict.push(term.clone()); 41 | self.terms_map.insert(term, term_id); 42 | Ok(term_id) 43 | } 44 | 45 | pub fn insert_triple(&mut self, triple: BorshTriple) -> bool { 46 | self.quads_set.insert(triple.into()) 47 | } 48 | 49 | pub fn insert_quad(&mut self, quad: BorshQuad) -> bool { 50 | self.quads_set.insert(quad) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /lib/rdf-borsh/src/borsh_header.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | use borsh::{BorshDeserialize, BorshSerialize}; 4 | 5 | pub(crate) const MAGIC_NUMBER: [u8; 4] = *b"RDFB"; 6 | pub(crate) const VERSION_NUMBER: u8 = b'1'; 7 | pub(crate) const FLAGS: u8 = 0b00000111; 8 | 9 | #[derive( 10 | Clone, 11 | Copy, 12 | Debug, 13 | Default, 14 | Eq, 15 | Hash, 16 | Ord, 17 | PartialEq, 18 | PartialOrd, 19 | BorshSerialize, 20 | BorshDeserialize, 21 | )] 22 | pub struct BorshHeader { 23 | pub magic: [u8; 4], 24 | pub version: u8, 25 | pub flags: u8, 26 | pub quad_count: u32, 27 | } 28 | 29 | #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] 30 | pub enum BorshHeaderError { 31 | InvalidMagic, 32 | InvalidVersion, 33 | InvalidFlags, 34 | } 35 | 36 | impl BorshHeaderError { 37 | pub fn check(header: &BorshHeader) -> Result<(), Self> { 38 | if header.magic != MAGIC_NUMBER { 39 | return Err(Self::InvalidMagic); 40 | } 41 | if header.version != VERSION_NUMBER { 42 | return Err(Self::InvalidVersion); 43 | } 44 | if header.flags != FLAGS { 45 | return Err(Self::InvalidFlags); 46 | } 47 | Ok(()) 48 | } 49 | } 50 | 51 | impl core::error::Error for BorshHeaderError {} 52 | 53 | impl core::fmt::Display for BorshHeaderError { 54 | fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { 55 | match self { 56 | Self::InvalidMagic => write!(f, "invalid RDF/Borsh header"), 57 | Self::InvalidVersion => write!(f, "invalid RDF/Borsh version"), 58 | Self::InvalidFlags => write!(f, "invalid RDF/Borsh flags"), 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /lib/rdf-reader/src/providers/oxrdf.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | extern crate std; 4 | 5 | use crate::{Reader, ReaderOptions}; 6 | use core::error::Error; 7 | use oxrdfio::{RdfParser, ReaderQuadParser}; 8 | use rdf_format::Format; 9 | use rdf_model::{ 10 | Countable, Enumerable, MaybeDurable, MaybeIndexed, MaybeMutable, Source, Statement, 11 | }; 12 | use std::{boxed::Box, io::Read}; 13 | 14 | pub struct OxrdfReader { 15 | format: Format, 16 | parser: ReaderQuadParser, 17 | } 18 | 19 | impl Iterator for OxrdfReader { 20 | type Item = Result, Box>; 21 | 22 | fn next(&mut self) -> Option { 23 | match self.parser.next() { 24 | Some(Err(error)) => Some(Err(error.into())), 25 | Some(Ok(quad)) => Some(Ok(quad.into())), 26 | None => None, 27 | } 28 | } 29 | } 30 | 31 | impl OxrdfReader { 32 | pub fn new(reader: R, options: ReaderOptions) -> Self { 33 | let format = options.format.expect("format must provided"); 34 | let parser = RdfParser::from_format(format.try_into().expect("format must be compatible")) 35 | .for_reader(reader); 36 | Self { format, parser } 37 | } 38 | } 39 | 40 | impl Reader for OxrdfReader { 41 | fn format(&self) -> Format { 42 | self.format 43 | } 44 | } 45 | 46 | impl Source for OxrdfReader {} 47 | 48 | impl Enumerable for OxrdfReader {} 49 | 50 | impl Countable for OxrdfReader { 51 | fn count(&self) -> usize { 52 | 0 // TODO 53 | } 54 | } 55 | 56 | impl MaybeDurable for OxrdfReader {} 57 | 58 | impl MaybeIndexed for OxrdfReader {} 59 | 60 | impl MaybeMutable for OxrdfReader {} 61 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | # See: https://doc.rust-lang.org/cargo/reference/manifest.html 2 | 3 | [workspace] 4 | members = ["bin/*", "lib/*"] 5 | default-members = ["bin/*", "lib/*"] 6 | resolver = "2" 7 | 8 | [workspace.package] 9 | version = "0.2.2" 10 | authors = ["Arto Bendiken"] 11 | edition = "2021" 12 | rust-version = "1.81" 13 | description = "RDF.rs is a Rust framework for working with RDF knowledge graphs." 14 | #documentation = "https://docs.rs/rdf-model/" 15 | readme = true 16 | homepage = "https://github.com/rust-rdf" 17 | repository = "https://github.com/rust-rdf/rdf.rs" 18 | license = "Unlicense" 19 | keywords = ["rdf", "knowledge-graph", "linked-data", "semantic-web"] 20 | categories = ["data-structures", "no-std"] 21 | publish = true 22 | 23 | [workspace.dependencies] 24 | dogma = { version = "0.1", default-features = false, features = ["traits"] } 25 | rdf = { package = "rdf_rs", version = "=0.2.2", default-features = true } 26 | rdf-borsh = { version = "=0.2.2", default-features = true } 27 | rdf-derive = { version = "=0.2.2", default-features = true } 28 | rdf-format = { version = "=0.2.2", default-features = true } 29 | rdf-model = { version = "=0.2.2", default-features = true } 30 | rdf-query = { version = "=0.2.2", default-features = true } 31 | rdf-reader = { version = "=0.2.2", default-features = true } 32 | rdf-vocab = { version = "=0.2.2", default-features = true } 33 | rdf-writer = { version = "=0.2.2", default-features = true } 34 | 35 | [patch.crates-io] 36 | rdf-cli = { path = "bin/rdf" } 37 | rdf_rs = { path = "lib/rdf_rs" } 38 | rdf-borsh = { path = "lib/rdf-borsh" } 39 | rdf-derive = { path = "lib/rdf-derive" } 40 | rdf-format = { path = "lib/rdf-format" } 41 | rdf-model = { path = "lib/rdf-model" } 42 | rdf-query = { path = "lib/rdf-query" } 43 | rdf-reader = { path = "lib/rdf-reader" } 44 | rdf-vocab = { path = "lib/rdf-vocab" } 45 | rdf-writer = { path = "lib/rdf-writer" } 46 | -------------------------------------------------------------------------------- /lib/xsd/README.md: -------------------------------------------------------------------------------- 1 | # XSD.rs: XML Schema for Rust 2 | 3 | [![License](https://img.shields.io/badge/license-Public%20Domain-blue.svg)](https://unlicense.org) 4 | [![Compatibility](https://img.shields.io/badge/rust-1.81%2B-blue)](https://rust-lang.org) 5 | [![Package](https://img.shields.io/crates/v/xsd)](https://crates.io/crates/xsd) 6 | 7 | 🚧 _This is presently under heavy construction._ 8 | 9 | ## ✨ Features 10 | 11 | - Supports `no_std` environments from the get-go. 12 | - 100% pure and safe Rust with minimal dependencies and no bloat. 13 | - 100% free and unencumbered public domain software. 14 | - Adheres to the Rust API Guidelines in its [naming conventions]. 15 | 16 | ## 🛠️ Prerequisites 17 | 18 | - [Rust](https://rust-lang.org) 1.81+ 19 | 20 | ## ⬇️ Installation 21 | 22 | ### Installation via Cargo 23 | 24 | ```bash 25 | cargo add xsd 26 | ``` 27 | 28 | ## 👉 Examples 29 | 30 | ### Importing the library 31 | 32 | ```rust 33 | use xsd::*; 34 | ``` 35 | 36 | ## 📚 Reference 37 | 38 | ## 👨‍💻 Development 39 | 40 | ```bash 41 | git clone https://github.com/rust-rdf/rdf.rs.git 42 | ``` 43 | 44 | - - - 45 | 46 | [![Share on Twitter](https://img.shields.io/badge/share%20on-twitter-03A9F4?logo=twitter)](https://twitter.com/share?url=https://github.com/rust-rdf/rdf.rs/tree/master/lib/xsd&text=XSD.rs) 47 | [![Share on Reddit](https://img.shields.io/badge/share%20on-reddit-red?logo=reddit)](https://reddit.com/submit?url=https://github.com/rust-rdf/rdf.rs/tree/master/lib/xsd&title=XSD.rs) 48 | [![Share on Hacker News](https://img.shields.io/badge/share%20on-hacker%20news-orange?logo=ycombinator)](https://news.ycombinator.com/submitlink?u=https://github.com/rust-rdf/rdf.rs/tree/master/lib/xsd&t=XSD.rs) 49 | [![Share on Facebook](https://img.shields.io/badge/share%20on-facebook-1976D2?logo=facebook)](https://www.facebook.com/sharer/sharer.php?u=https://github.com/rust-rdf/rdf.rs/tree/master/lib/xsd) 50 | 51 | [naming conventions]: https://rust-lang.github.io/api-guidelines/naming.html 52 | -------------------------------------------------------------------------------- /bin/rdf/src/main.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | #![deny(unsafe_code)] 4 | #![allow(unused)] 5 | 6 | mod commands; 7 | mod exit; 8 | 9 | use crate::exit::ExitCode; 10 | use clientele::{ 11 | crates::{ 12 | camino::Utf8PathBuf, 13 | clap::{Parser, Subcommand}, 14 | }, 15 | StandardOptions, 16 | }; 17 | 18 | /// RDF.rs Command-Line Interface (CLI) 19 | #[derive(Debug, Parser)] 20 | #[command(name = "RDF.rs")] 21 | #[command(arg_required_else_help = true)] 22 | struct Options { 23 | #[clap(flatten)] 24 | flags: StandardOptions, 25 | 26 | #[command(subcommand)] 27 | command: Option, 28 | } 29 | 30 | #[derive(Debug, Subcommand)] 31 | enum Command { 32 | /// Query the registry of RDF formats 33 | Format { 34 | #[command(subcommand)] 35 | command: FormatCommand, 36 | }, 37 | 38 | /// Count RDF statements in input files 39 | Count { 40 | /// The input files 41 | files: Vec, 42 | }, 43 | 44 | /// Parse input files in a given RDF format 45 | Parse { 46 | /// The input files 47 | files: Vec, 48 | }, 49 | } 50 | 51 | #[derive(Debug, Subcommand)] 52 | enum FormatCommand { 53 | /// List known RDF formats 54 | List {}, 55 | } 56 | 57 | pub fn main() -> Result<(), ExitCode> { 58 | // Load environment variables from `.env`: 59 | clientele::dotenv().ok(); 60 | 61 | // Expand wildcards and @argfiles: 62 | let args = clientele::args_os()?; 63 | 64 | // Parse command-line options: 65 | let options = Options::parse_from(args); 66 | 67 | if options.flags.version { 68 | println!("RDF.rs {}", env!("CARGO_PKG_VERSION")); 69 | return Ok(()); 70 | } 71 | 72 | if options.flags.license { 73 | println!("This is free and unencumbered software released into the public domain."); 74 | return Ok(()); 75 | } 76 | 77 | // Configure verbose/debug output: 78 | if options.flags.verbose > 0 || options.flags.debug { 79 | // TODO: configure tracing 80 | } 81 | 82 | use commands::*; 83 | match options.command.unwrap() { 84 | Command::Format { command } => match command { 85 | FormatCommand::List {} => format::list::list(&options.flags), 86 | }, 87 | Command::Count { files } => count::count(files, &options.flags), 88 | Command::Parse { files } => parse::parse(files, &options.flags), 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /lib/rdf-borsh/src/borsh_writer.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | extern crate alloc; 4 | 5 | use crate::{BorshDataset, BorshTermId, FLAGS, MAGIC_NUMBER, VERSION_NUMBER}; 6 | use alloc::boxed::Box; 7 | use borsh::{ 8 | io::{Result, Write}, 9 | BorshSerialize, 10 | }; 11 | use lz4_flex::frame::FrameEncoder; 12 | use rdf_model::{Statement, Term}; 13 | use rdf_writer::{Format, Writer}; 14 | 15 | pub struct BorshWriter { 16 | #[allow(unused)] 17 | sink: Box, 18 | #[allow(unused)] 19 | dataset: BorshDataset, 20 | } 21 | 22 | impl core::fmt::Debug for BorshWriter { 23 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 24 | f.debug_struct("BorshWriter") 25 | .field("dataset", &self.dataset) 26 | .finish() 27 | } 28 | } 29 | 30 | impl BorshWriter { 31 | pub fn new(sink: Box) -> Result { 32 | Ok(Self { 33 | sink, 34 | dataset: BorshDataset::new(), 35 | }) 36 | } 37 | 38 | pub fn quad_count(&self) -> usize { 39 | self.dataset.quads_set.len() 40 | } 41 | 42 | pub fn intern_term(&mut self, term: &dyn Term) -> Result> { 43 | self.dataset 44 | .intern_term(term.into()) 45 | .map_err(|_| borsh::io::Error::other("term dictionary overflow")) 46 | } 47 | 48 | #[allow(unused_mut)] 49 | pub fn finish(mut self) -> Result<()> { 50 | self.sink.write_all(&MAGIC_NUMBER)?; 51 | self.sink.write_all(&[VERSION_NUMBER])?; 52 | self.sink.write_all(&[FLAGS])?; 53 | 54 | let quad_count = self.dataset.quad_count() as u32; 55 | self.sink.write_all(quad_count.to_le_bytes().as_ref())?; 56 | 57 | let mut compressor = FrameEncoder::new(self.sink); 58 | self.dataset.serialize(&mut compressor)?; 59 | compressor.finish()?; 60 | 61 | Ok(()) 62 | } 63 | } 64 | 65 | impl Writer for BorshWriter { 66 | type Error = borsh::io::Error; 67 | 68 | fn format(&self) -> Format { 69 | todo!() // TODO 70 | } 71 | 72 | fn write_statement(&mut self, statement: &dyn Statement) -> Result<()> { 73 | let s = self.intern_term(statement.subject())?; 74 | let p = self.intern_term(statement.predicate())?; 75 | let o = self.intern_term(statement.object())?; 76 | let c = match statement.context() { 77 | Some(c) => self.intern_term(c)?, 78 | None => BorshTermId::default(), 79 | }; 80 | self.dataset.insert_quad((s, p, o, c).into()); 81 | Ok(()) 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /lib/rdf-borsh/src/borsh_quad.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | use crate::{BorshTermId, BorshTriple}; 4 | use borsh::{BorshDeserialize, BorshSerialize}; 5 | use num_integer::Integer; 6 | 7 | #[derive( 8 | Clone, 9 | Copy, 10 | Debug, 11 | Default, 12 | Eq, 13 | Hash, 14 | Ord, 15 | PartialEq, 16 | PartialOrd, 17 | BorshSerialize, 18 | BorshDeserialize, 19 | )] 20 | pub struct BorshQuad { 21 | pub context: BorshTermId, 22 | pub subject: BorshTermId, 23 | pub predicate: BorshTermId, 24 | pub object: BorshTermId, 25 | } 26 | 27 | impl BorshQuad { 28 | pub fn new( 29 | subject: BorshTermId, 30 | predicate: BorshTermId, 31 | object: BorshTermId, 32 | context: BorshTermId, 33 | ) -> Self { 34 | Self { 35 | context, 36 | subject, 37 | predicate, 38 | object, 39 | } 40 | } 41 | } 42 | 43 | impl From> for BorshQuad { 44 | fn from(triple: BorshTriple) -> Self { 45 | Self::new( 46 | triple.subject, 47 | triple.predicate, 48 | triple.object, 49 | BorshTermId::default(), 50 | ) 51 | } 52 | } 53 | 54 | impl From<(BorshTermId, BorshTermId, BorshTermId)> for BorshQuad { 55 | fn from( 56 | (subject, predicate, object): (BorshTermId, BorshTermId, BorshTermId), 57 | ) -> Self { 58 | Self::new(subject, predicate, object, BorshTermId::default()) 59 | } 60 | } 61 | 62 | impl 63 | From<( 64 | BorshTermId, 65 | BorshTermId, 66 | BorshTermId, 67 | BorshTermId, 68 | )> for BorshQuad 69 | { 70 | fn from( 71 | (subject, predicate, object, context): ( 72 | BorshTermId, 73 | BorshTermId, 74 | BorshTermId, 75 | BorshTermId, 76 | ), 77 | ) -> Self { 78 | Self::new(subject, predicate, object, context) 79 | } 80 | } 81 | 82 | impl 83 | From<( 84 | BorshTermId, 85 | BorshTermId, 86 | BorshTermId, 87 | Option>, 88 | )> for BorshQuad 89 | { 90 | fn from( 91 | (subject, predicate, object, context): ( 92 | BorshTermId, 93 | BorshTermId, 94 | BorshTermId, 95 | Option>, 96 | ), 97 | ) -> Self { 98 | Self::new(subject, predicate, object, context.unwrap_or_default()) 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RDF.rs: RDF for Rust 2 | 3 | [![License](https://img.shields.io/badge/license-Public%20Domain-blue.svg)](https://unlicense.org) 4 | [![Compatibility](https://img.shields.io/badge/rust-1.81%2B-blue)](https://rust-lang.org) 5 | [![Package](https://img.shields.io/crates/v/rdf_rs)](https://crates.io/crates/rdf_rs) 6 | [![Documentation](https://docs.rs/rdf_rs/badge.svg)](https://docs.rs/rdf_rs/) 7 | 8 | **RDF.rs** is a [Rust] framework for working with [RDF] knowledge graphs. 9 | 10 | 🚧 _This is presently under heavy construction._ 11 | 12 | ## ✨ Features 13 | 14 | - 100% pure and safe Rust with minimal dependencies and no bloat. 15 | - Supports `no_std` environments from the get-go. 16 | - Supports opting out of any feature using comprehensive [feature flags]. 17 | - Adheres to the Rust API Guidelines in its [naming conventions]. 18 | - 100% free and unencumbered public domain software. 19 | 20 | ## 🛠️ Prerequisites 21 | 22 | - [Rust] 1.81+ 23 | 24 | ## ⬇️ Installation 25 | 26 | ### Installation via Cargo 27 | 28 | ```bash 29 | cargo add rdf_rs --rename rdf 30 | ``` 31 | 32 | ### Installation in `Cargo.toml` (with all features enabled) 33 | 34 | ```toml 35 | [dependencies] 36 | rdf = { package = "rdf_rs", version = "0.2" } 37 | ``` 38 | 39 | ### Installation in `Cargo.toml` (with only specific features enabled) 40 | 41 | ```toml 42 | [dependencies] 43 | rdf = { package = "rdf_rs", version = "0.2", default-features = false, features = ["serde"] } 44 | ``` 45 | 46 | ## 👉 Examples 47 | 48 | ### Importing the library 49 | 50 | ```rust,compile_fail 51 | use rdf::*; 52 | ``` 53 | 54 | ## 📚 Reference 55 | 56 | https://docs.rs/rdf_rs/ 57 | 58 | ## 👨‍💻 Development 59 | 60 | ```bash 61 | git clone https://github.com/rust-rdf/rdf.rs.git 62 | ``` 63 | 64 | --- 65 | 66 | [![Share on X](https://img.shields.io/badge/share%20on-x-03A9F4?logo=x)](https://x.com/intent/post?url=https://github.com/rust-rdf/rdf.rs&text=RDF.rs) 67 | [![Share on Reddit](https://img.shields.io/badge/share%20on-reddit-red?logo=reddit)](https://reddit.com/submit?url=https://github.com/rust-rdf/rdf.rs&title=RDF.rs) 68 | [![Share on Hacker News](https://img.shields.io/badge/share%20on-hn-orange?logo=ycombinator)](https://news.ycombinator.com/submitlink?u=https://github.com/rust-rdf/rdf.rs&t=RDF.rs) 69 | [![Share on Facebook](https://img.shields.io/badge/share%20on-fb-1976D2?logo=facebook)](https://www.facebook.com/sharer/sharer.php?u=https://github.com/rust-rdf/rdf.rs) 70 | [![Share on LinkedIn](https://img.shields.io/badge/share%20on-linkedin-3949AB?logo=linkedin)](https://www.linkedin.com/sharing/share-offsite/?url=https://github.com/rust-rdf/rdf.rs) 71 | 72 | [feature flags]: https://github.com/rust-rdf/rdf.rs/blob/master/lib/rdf_rs/Cargo.toml 73 | [naming conventions]: https://rust-lang.github.io/api-guidelines/naming.html 74 | 75 | [RDF]: https://www.w3.org/TR/rdf12-concepts/ 76 | [Rust]: https://rust-lang.org 77 | -------------------------------------------------------------------------------- /lib/rdf-model/src/alloc/heap_term.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | extern crate alloc; 4 | 5 | use crate::{Term, TermKind}; 6 | use alloc::{ 7 | borrow::Cow, 8 | string::{String, ToString}, 9 | }; 10 | 11 | /// A heap-allocated term. 12 | #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] 13 | #[cfg_attr( 14 | feature = "borsh", 15 | derive(borsh::BorshSerialize, borsh::BorshDeserialize) 16 | )] 17 | #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 18 | pub enum HeapTerm { 19 | Iri(String), 20 | BNode(String), 21 | Literal(String), 22 | LiteralWithDatatype(String, String), 23 | LiteralWithLanguage(String, String), 24 | } 25 | 26 | impl HeapTerm { 27 | pub fn iri(value: impl AsRef) -> Self { 28 | Self::Iri(String::from(value.as_ref())) 29 | } 30 | 31 | pub fn bnode(id: impl AsRef) -> Self { 32 | Self::BNode(String::from(id.as_ref())) 33 | } 34 | 35 | pub fn literal(value: impl AsRef) -> Self { 36 | Self::Literal(String::from(value.as_ref())) 37 | } 38 | 39 | pub fn literal_with_language(value: impl AsRef, language: impl AsRef) -> Self { 40 | Self::LiteralWithLanguage( 41 | String::from(value.as_ref()), 42 | String::from(language.as_ref()), 43 | ) 44 | } 45 | 46 | pub fn literal_with_datatype(value: impl AsRef, datatype: impl AsRef) -> Self { 47 | Self::LiteralWithDatatype( 48 | String::from(value.as_ref()), 49 | String::from(datatype.as_ref()), 50 | ) 51 | } 52 | } 53 | 54 | impl Term for HeapTerm { 55 | fn kind(&self) -> TermKind { 56 | match self { 57 | Self::Iri(_) => TermKind::Iri, 58 | Self::BNode(_) => TermKind::BNode, 59 | Self::Literal(_) 60 | | Self::LiteralWithLanguage(_, _) 61 | | Self::LiteralWithDatatype(_, _) => TermKind::Literal, 62 | } 63 | } 64 | 65 | fn as_str(&self) -> Cow { 66 | match self { 67 | Self::Iri(s) => Cow::Borrowed(s), 68 | Self::BNode(s) => Cow::Borrowed(s), 69 | Self::Literal(s) 70 | | Self::LiteralWithLanguage(s, _) 71 | | Self::LiteralWithDatatype(s, _) => Cow::Borrowed(s), 72 | } 73 | } 74 | } 75 | 76 | impl From<&dyn Term> for HeapTerm { 77 | fn from(term: &dyn Term) -> Self { 78 | match term.kind() { 79 | TermKind::Iri => Self::iri(term.as_str()), 80 | TermKind::BNode => Self::bnode(term.as_str()), 81 | TermKind::Literal => Self::literal(term.as_str()), // TODO 82 | } 83 | } 84 | } 85 | 86 | impl From<&str> for HeapTerm { 87 | fn from(value: &str) -> Self { 88 | Self::literal(value) 89 | } 90 | } 91 | 92 | impl From for HeapTerm { 93 | fn from(value: String) -> Self { 94 | Self::literal(&value) 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /lib/rdf-borsh/src/borsh_term.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | extern crate alloc; 4 | 5 | use alloc::{borrow::Cow, string::String}; 6 | use rdf_model::{HeapTerm, Term, TermKind}; 7 | 8 | #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] 9 | pub struct BorshTerm(pub(crate) HeapTerm); 10 | 11 | impl Term for BorshTerm { 12 | fn kind(&self) -> TermKind { 13 | self.0.kind() 14 | } 15 | 16 | fn as_str(&self) -> Cow { 17 | self.0.as_str() 18 | } 19 | } 20 | 21 | impl From<&str> for BorshTerm { 22 | fn from(value: &str) -> Self { 23 | Self(HeapTerm::from(value)) 24 | } 25 | } 26 | 27 | impl From for BorshTerm { 28 | fn from(value: String) -> Self { 29 | Self(HeapTerm::from(value)) 30 | } 31 | } 32 | 33 | impl From for BorshTerm { 34 | fn from(term: HeapTerm) -> Self { 35 | Self(term) 36 | } 37 | } 38 | 39 | impl From<&dyn Term> for BorshTerm { 40 | fn from(term: &dyn Term) -> Self { 41 | Self(HeapTerm::from(term)) 42 | } 43 | } 44 | 45 | impl borsh::BorshSerialize for BorshTerm { 46 | fn serialize(&self, writer: &mut W) -> borsh::io::Result<()> { 47 | match &self.0 { 48 | HeapTerm::Iri(value) => { 49 | 0x01u8.serialize(writer)?; 50 | value.serialize(writer) 51 | } 52 | HeapTerm::BNode(value) => { 53 | 0x02u8.serialize(writer)?; 54 | value.serialize(writer) 55 | } 56 | HeapTerm::Literal(value) => { 57 | 0x03u8.serialize(writer)?; 58 | value.serialize(writer) 59 | } 60 | HeapTerm::LiteralWithDatatype(value, datatype) => { 61 | 0x04u8.serialize(writer)?; 62 | value.serialize(writer)?; 63 | datatype.serialize(writer) 64 | } 65 | HeapTerm::LiteralWithLanguage(value, language) => { 66 | 0x05u8.serialize(writer)?; 67 | value.serialize(writer)?; 68 | language.serialize(writer) 69 | } 70 | } 71 | } 72 | } 73 | 74 | impl borsh::BorshDeserialize for BorshTerm { 75 | fn deserialize_reader(reader: &mut R) -> borsh::io::Result { 76 | Ok(BorshTerm(match u8::deserialize_reader(reader)? { 77 | 0x01 => { 78 | let value = String::deserialize_reader(reader)?; 79 | HeapTerm::Iri(value) 80 | } 81 | 0x02 => { 82 | let value = String::deserialize_reader(reader)?; 83 | HeapTerm::BNode(value) 84 | } 85 | 0x03 => { 86 | let value = String::deserialize_reader(reader)?; 87 | HeapTerm::Literal(value) 88 | } 89 | 0x04 => { 90 | let value = String::deserialize_reader(reader)?; 91 | let datatype = String::deserialize_reader(reader)?; 92 | HeapTerm::LiteralWithDatatype(value, datatype) 93 | } 94 | 0x05 => { 95 | let value = String::deserialize_reader(reader)?; 96 | let language = String::deserialize_reader(reader)?; 97 | HeapTerm::LiteralWithLanguage(value, language) 98 | } 99 | _ => return Err(borsh::io::ErrorKind::InvalidData.into()), 100 | })) 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /lib/rdf-model/src/providers/oxrdf.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | extern crate alloc; 4 | 5 | use crate::{Statement, Term, TermKind}; 6 | use alloc::{borrow::Cow, string::String}; 7 | use oxrdf::Quad; 8 | 9 | pub struct OxrdfStatement { 10 | subject: OxrdfSubject, 11 | predicate: OxrdfNamedNode, 12 | object: OxrdfTerm, 13 | context: OxrdfGraphName, 14 | } 15 | 16 | impl OxrdfStatement { 17 | pub fn new(quad: oxrdf::Quad) -> OxrdfStatement { 18 | Self { 19 | subject: OxrdfSubject { 20 | inner: quad.subject, 21 | }, 22 | predicate: OxrdfNamedNode { 23 | inner: quad.predicate, 24 | }, 25 | object: OxrdfTerm { inner: quad.object }, 26 | context: OxrdfGraphName { 27 | inner: quad.graph_name, 28 | }, 29 | } 30 | } 31 | } 32 | 33 | impl Statement for OxrdfStatement { 34 | fn subject(&self) -> &dyn Term { 35 | &self.subject 36 | } 37 | 38 | fn predicate(&self) -> &dyn Term { 39 | &self.predicate 40 | } 41 | 42 | fn object(&self) -> &dyn Term { 43 | &self.object 44 | } 45 | 46 | fn context(&self) -> Option<&dyn Term> { 47 | use oxrdf::GraphName; 48 | match &self.context.inner { 49 | GraphName::NamedNode(_) => Some(&self.context), 50 | GraphName::BlankNode(_) => Some(&self.context), 51 | GraphName::DefaultGraph => None, 52 | } 53 | } 54 | } 55 | 56 | pub struct OxrdfSubject { 57 | inner: oxrdf::Subject, 58 | } 59 | 60 | impl Term for OxrdfSubject { 61 | fn kind(&self) -> TermKind { 62 | use oxrdf::Subject; 63 | match &self.inner { 64 | Subject::NamedNode(_) => TermKind::Iri, 65 | Subject::BlankNode(_) => TermKind::BNode, 66 | #[cfg(feature = "rdf-star")] 67 | Subject::Triple(_) => todo!("RDF-star support not implemented yet"), // TODO 68 | } 69 | } 70 | 71 | fn as_str(&self) -> Cow { 72 | use oxrdf::Subject; 73 | match &self.inner { 74 | Subject::NamedNode(node) => Cow::Borrowed(node.as_str()), 75 | Subject::BlankNode(node) => Cow::Borrowed(node.as_str()), 76 | #[cfg(feature = "rdf-star")] 77 | Subject::Triple(_) => todo!("RDF-star support not implemented yet"), // TODO 78 | } 79 | } 80 | } 81 | 82 | pub struct OxrdfNamedNode { 83 | inner: oxrdf::NamedNode, 84 | } 85 | 86 | impl Term for OxrdfNamedNode { 87 | fn kind(&self) -> TermKind { 88 | TermKind::Iri 89 | } 90 | 91 | fn as_str(&self) -> Cow { 92 | Cow::Borrowed(self.inner.as_str()) 93 | } 94 | } 95 | 96 | pub struct OxrdfTerm { 97 | inner: oxrdf::Term, 98 | } 99 | 100 | impl Term for OxrdfTerm { 101 | fn kind(&self) -> TermKind { 102 | use oxrdf::Term; 103 | match &self.inner { 104 | Term::NamedNode(_) => TermKind::Iri, 105 | Term::BlankNode(_) => TermKind::BNode, 106 | Term::Literal(_) => TermKind::Literal, 107 | #[cfg(feature = "rdf-star")] 108 | Term::Triple(_) => todo!("RDF-star support not implemented yet"), // TODO 109 | } 110 | } 111 | 112 | fn as_str(&self) -> Cow { 113 | use oxrdf::Term; 114 | match &self.inner { 115 | Term::NamedNode(node) => Cow::Borrowed(node.as_str()), 116 | Term::BlankNode(node) => Cow::Borrowed(node.as_str()), 117 | Term::Literal(lit) => Cow::Borrowed(lit.value()), // TODO 118 | #[cfg(feature = "rdf-star")] 119 | Term::Triple(_) => todo!("RDF-star support not implemented yet"), // TODO 120 | } 121 | } 122 | } 123 | 124 | pub struct OxrdfGraphName { 125 | inner: oxrdf::GraphName, 126 | } 127 | 128 | impl Term for OxrdfGraphName { 129 | fn kind(&self) -> TermKind { 130 | use oxrdf::GraphName; 131 | match &self.inner { 132 | GraphName::NamedNode(_) => TermKind::Iri, 133 | GraphName::BlankNode(_) => TermKind::BNode, 134 | GraphName::DefaultGraph => todo!(), // TODO 135 | } 136 | } 137 | 138 | fn as_str(&self) -> Cow { 139 | use oxrdf::GraphName; 140 | match &self.inner { 141 | GraphName::NamedNode(node) => Cow::Borrowed(node.as_str()), 142 | GraphName::BlankNode(node) => Cow::Borrowed(node.as_str()), 143 | GraphName::DefaultGraph => Cow::Borrowed(""), // TODO 144 | } 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /lib/rdf-borsh/src/borsh_reader.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | extern crate alloc; 4 | 5 | use alloc::{boxed::Box, collections::BTreeMap, vec::Vec}; 6 | use borsh::{ 7 | io::{Read, Result}, 8 | BorshDeserialize, 9 | }; 10 | use core::error::Error; 11 | use lz4_flex::frame::FrameDecoder; 12 | use rdf_model::{ 13 | Countable, Enumerable, HeapQuad, MaybeDurable, MaybeIndexed, MaybeMutable, Source, Statement, 14 | }; 15 | use rdf_reader::{Format, Reader}; 16 | 17 | use crate::{parse_header, BorshQuad, BorshTerm, BorshTermId}; 18 | 19 | pub struct BorshReader { 20 | decompressor: FrameDecoder, 21 | 22 | term_dict: BTreeMap, BorshTerm>, 23 | 24 | quad_count: usize, 25 | read_count: usize, 26 | } 27 | 28 | impl BorshReader { 29 | pub fn new(mut source: R) -> Result { 30 | let quad_count = { 31 | let mut buf = [0u8; 10]; 32 | source.read_exact(&mut buf)?; 33 | parse_header(&mut &buf[..]).map_err(|_| borsh::io::ErrorKind::InvalidData)? 34 | }; 35 | 36 | let mut decompressor = FrameDecoder::new(source); 37 | 38 | let term_dict = { 39 | Vec::::deserialize_reader(&mut decompressor)? 40 | .into_iter() 41 | .fold(BTreeMap::new(), |mut acc, term| { 42 | let id = BorshTermId::from(acc.len() as u16 + 1); 43 | acc.insert(id, term); 44 | acc 45 | }) 46 | }; 47 | 48 | let _quad_count = { 49 | let mut buf = [0u8; 4]; 50 | decompressor.read_exact(&mut buf)?; 51 | u32::from_le_bytes(buf) 52 | }; 53 | 54 | // rest of `source` is the quads section block 55 | 56 | Ok(Self { 57 | decompressor, 58 | quad_count: quad_count as _, 59 | term_dict, 60 | read_count: 0usize, 61 | }) 62 | } 63 | } 64 | 65 | impl Reader for BorshReader { 66 | fn format(&self) -> Format { 67 | todo!() // TODO 68 | } 69 | } 70 | 71 | impl Source for BorshReader {} 72 | impl Enumerable for BorshReader {} 73 | impl MaybeDurable for BorshReader {} 74 | impl MaybeIndexed for BorshReader {} 75 | impl MaybeMutable for BorshReader {} 76 | 77 | impl Countable for BorshReader { 78 | fn count(&self) -> usize { 79 | self.quad_count 80 | } 81 | } 82 | 83 | impl Iterator for BorshReader { 84 | type Item = core::result::Result, Box>; 85 | 86 | fn next(&mut self) -> Option { 87 | if self.len() == 0 { 88 | return None; 89 | } 90 | 91 | let quad = match BorshQuad::::deserialize_reader(&mut self.decompressor) { 92 | Ok(q) => q, 93 | Err(e) => return Some(Err(Box::new(e))), 94 | }; 95 | 96 | let Some(s) = self.term_dict.get(&quad.subject) else { 97 | return Some(Err(Box::new(borsh::io::Error::new( 98 | borsh::io::ErrorKind::InvalidData, 99 | "subject has unknown term ID", 100 | )))); 101 | }; 102 | let Some(p) = self.term_dict.get(&quad.predicate) else { 103 | return Some(Err(Box::new(borsh::io::Error::new( 104 | borsh::io::ErrorKind::InvalidData, 105 | "predicate has unknown term ID", 106 | )))); 107 | }; 108 | let Some(o) = self.term_dict.get(&quad.object) else { 109 | return Some(Err(Box::new(borsh::io::Error::new( 110 | borsh::io::ErrorKind::InvalidData, 111 | "object has unknown term ID", 112 | )))); 113 | }; 114 | 115 | let stmt = if quad.context.is_zero() { 116 | HeapQuad::from((s.0.clone(), p.0.clone(), o.0.clone())) 117 | } else { 118 | let Some(g) = self.term_dict.get(&quad.context) else { 119 | return Some(Err(Box::new(borsh::io::Error::new( 120 | borsh::io::ErrorKind::InvalidData, 121 | "context has unknown term ID", 122 | )))); 123 | }; 124 | HeapQuad::from((s.0.clone(), p.0.clone(), o.0.clone(), g.0.clone())) 125 | }; 126 | 127 | self.read_count += 1; 128 | 129 | Some(Ok(Box::new(stmt))) 130 | } 131 | 132 | fn size_hint(&self) -> (usize, Option) { 133 | let rem = self.quad_count - self.read_count; 134 | (rem, Some(rem)) 135 | } 136 | } 137 | 138 | impl ExactSizeIterator for BorshReader {} 139 | -------------------------------------------------------------------------------- /lib/rdf-borsh/src/lib.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | //! ```rust 4 | //! # use rdf_borsh::*; 5 | //! let reader = BorshReader::new(Box::new(std::io::stdin())); 6 | //! let writer = BorshWriter::new(Box::new(std::io::stdout())); 7 | //! ``` 8 | 9 | #![no_std] 10 | #![deny(unsafe_code)] 11 | 12 | mod borsh_dataset; 13 | pub use borsh_dataset::*; 14 | 15 | mod borsh_header; 16 | pub use borsh_header::*; 17 | 18 | mod borsh_quad; 19 | pub use borsh_quad::*; 20 | 21 | mod borsh_reader; 22 | pub use borsh_reader::*; 23 | 24 | mod borsh_term; 25 | pub use borsh_term::*; 26 | 27 | mod borsh_term_id; 28 | pub use borsh_term_id::*; 29 | 30 | mod borsh_triple; 31 | pub use borsh_triple::*; 32 | 33 | mod borsh_writer; 34 | pub use borsh_writer::*; 35 | 36 | mod parse; 37 | pub use parse::parse_dataset; 38 | pub(crate) use parse::*; 39 | 40 | #[cfg(test)] 41 | mod tests { 42 | extern crate alloc; 43 | extern crate std; 44 | 45 | // use super::*; 46 | // use alloc::{boxed::Box, collections::BTreeMap, vec, vec::Vec}; 47 | // use borsh::io::Read; 48 | // use rdf_model::{HeapQuad, HeapTerm}; 49 | // use rdf_writer::Writer; 50 | // 51 | // #[test] 52 | // #[ignore = "the trait bound `HeapQuad: From<(BorshTerm, BorshTerm, BorshTerm, BorshTerm)>` is not satisfied"] 53 | // fn borsh_roundtrip() -> Result<(), std::io::Error> { 54 | // let temp_file = tempfile::NamedTempFile::new().unwrap(); 55 | // std::println!("{:?}", temp_file); 56 | // let mut w = BorshWriter::new(Box::new(temp_file.reopen().unwrap()))?; 57 | 58 | // let orig_stmts = vec![ 59 | // HeapQuad::from(( 60 | // HeapTerm::from("foo-1").into(), 61 | // HeapTerm::from("bar-1").into(), 62 | // HeapTerm::from("baz-1").into(), 63 | // HeapTerm::from("qux-1").into(), 64 | // )), 65 | // HeapQuad::from(( 66 | // HeapTerm::from("foo-2").into(), 67 | // HeapTerm::from("bar-2").into(), 68 | // HeapTerm::from("baz-2").into(), 69 | // HeapTerm::from("qux-2").into(), 70 | // )), 71 | // ]; 72 | 73 | // orig_stmts 74 | // .iter() 75 | // .try_for_each(|stmt| w.write_statement(stmt)) 76 | // .unwrap(); 77 | 78 | // std::println!("{:?}", w); 79 | 80 | // w.finish().unwrap(); 81 | 82 | // let mut buf = Vec::new(); 83 | // temp_file.reopen().unwrap().read_to_end(&mut buf).unwrap(); 84 | // std::println!("{buf:?}"); 85 | // let parser_stmts: Vec = { 86 | // let (terms, quads) = parse_dataset(&mut buf.as_slice()).unwrap(); 87 | 88 | // let dict = terms.into_iter().fold(BTreeMap::new(), |mut acc, term| { 89 | // let id = BorshTermId::from(acc.len() as u16 + 1); 90 | // acc.insert(id, term); 91 | // acc 92 | // }); 93 | 94 | // std::println!("{dict:?} ; {quads:?}"); 95 | 96 | // quads 97 | // .into_iter() 98 | // .map( 99 | // |BorshQuad { 100 | // context, 101 | // subject, 102 | // predicate, 103 | // object, 104 | // }| { 105 | // HeapQuad::from(( 106 | // dict.get(&subject).unwrap().clone(), 107 | // dict.get(&predicate).unwrap().clone(), 108 | // dict.get(&object).unwrap().clone(), 109 | // dict.get(&context).unwrap().clone(), 110 | // )) 111 | // }, 112 | // ) 113 | // .collect() 114 | // }; 115 | 116 | // let reader_stmts: Vec = { 117 | // BorshReader::new(temp_file) 118 | // .unwrap() 119 | // .collect::, _>>() 120 | // .unwrap() 121 | // .into_iter() 122 | // .map(|stmt| { 123 | // HeapQuad::from(( 124 | // stmt.subject().into(), 125 | // stmt.predicate().into(), 126 | // stmt.object().into(), 127 | // stmt.context().unwrap().into(), 128 | // )) 129 | // }) 130 | // .collect() 131 | // }; 132 | 133 | // assert_eq!(orig_stmts, parser_stmts); 134 | // assert_eq!(orig_stmts, reader_stmts); 135 | 136 | // Ok(()) 137 | // } 138 | } 139 | -------------------------------------------------------------------------------- /lib/rdf-format/src/format.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | extern crate alloc; 4 | 5 | use crate::prelude::{vec, Vec}; 6 | use alloc::borrow::Cow; 7 | use dogma::traits::{Labeled, Named}; 8 | 9 | pub const FORMATS: [(&'static str, Format); 11] = [ 10 | ("hdt", Format::Hdt), 11 | ("jsonld", Format::JsonLd), 12 | ("n3", Format::Notation3), 13 | ("nq", Format::NQuads), 14 | ("nt", Format::NTriples), 15 | ("rj", Format::RdfJson), 16 | ("rdf", Format::RdfXml), 17 | ("trig", Format::TriG), 18 | ("trix", Format::TriX), 19 | ("ttl", Format::Turtle), 20 | ("yamlld", Format::YamlLd), 21 | ]; 22 | 23 | #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] 24 | #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 25 | pub enum Format { 26 | Hdt, 27 | JsonLd, 28 | Notation3, 29 | NQuads, 30 | NTriples, 31 | RdfJson, 32 | RdfXml, 33 | TriG, 34 | TriX, 35 | Turtle, 36 | YamlLd, 37 | } 38 | 39 | impl Named for Format { 40 | fn name(&self) -> Cow { 41 | use Format::*; 42 | Cow::Borrowed(match self { 43 | Hdt => "hdt", 44 | JsonLd => "json-ld", 45 | Notation3 => "n3", 46 | NQuads => "n-quads", 47 | NTriples => "n-triples", 48 | RdfJson => "rdfjson", 49 | RdfXml => "rdfxml", 50 | TriG => "trig", 51 | TriX => "trix", 52 | Turtle => "turtle", 53 | YamlLd => "yaml-ld", 54 | }) 55 | } 56 | } 57 | 58 | impl Labeled for Format { 59 | fn label(&self) -> Cow { 60 | use Format::*; 61 | Cow::Borrowed(match self { 62 | Hdt => "HDT", 63 | JsonLd => "JSON-LD", 64 | Notation3 => "Notation3", 65 | NQuads => "N-Quads", 66 | NTriples => "N-Triples", 67 | RdfJson => "RDF/JSON", 68 | RdfXml => "RDF/XML", 69 | TriG => "TriG", 70 | TriX => "TriX", 71 | Turtle => "Turtle", 72 | YamlLd => "YAML-LD", 73 | }) 74 | } 75 | } 76 | 77 | impl Format { 78 | pub fn from_extension(extension: &str) -> Option { 79 | for (format_extension, format) in FORMATS { 80 | if extension.eq_ignore_ascii_case(format_extension) { 81 | return Some(format); 82 | } 83 | } 84 | None 85 | } 86 | 87 | pub fn extension(&self) -> &str { 88 | use Format::*; 89 | match self { 90 | Hdt => "hdt", 91 | JsonLd => "jsonld", 92 | Notation3 => "n3", 93 | NQuads => "nq", 94 | NTriples => "nt", 95 | RdfJson => "rj", 96 | RdfXml => "rdf", 97 | TriG => "trig", 98 | TriX => "trix", 99 | Turtle => "ttl", 100 | YamlLd => "yamlld", 101 | } 102 | } 103 | 104 | pub fn extensions(&self) -> Vec<&str> { 105 | use Format::*; 106 | match self { 107 | YamlLd => vec!["yamlld", "yaml", "yml"], 108 | _ => vec![self.extension()], 109 | } 110 | } 111 | 112 | pub fn is_binary(&self) -> bool { 113 | use Format::*; 114 | matches!(self, Hdt) 115 | } 116 | 117 | pub fn is_text(&self) -> bool { 118 | !self.is_binary() 119 | } 120 | } 121 | 122 | impl core::fmt::Display for Format { 123 | fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { 124 | f.write_str(&self.label()) 125 | } 126 | } 127 | 128 | #[cfg(feature = "oxrdf")] 129 | impl TryFrom<&oxrdfio::RdfFormat> for Format { 130 | type Error = (); 131 | 132 | fn try_from(format: &oxrdfio::RdfFormat) -> Result { 133 | use oxrdfio::RdfFormat; 134 | Ok(match format { 135 | RdfFormat::N3 => Format::Notation3, 136 | RdfFormat::NQuads => Format::NQuads, 137 | RdfFormat::NTriples => Format::NTriples, 138 | RdfFormat::RdfXml => Format::RdfXml, 139 | RdfFormat::TriG => Format::TriG, 140 | RdfFormat::Turtle => Format::Turtle, 141 | _ => return Err(()), 142 | }) 143 | } 144 | } 145 | 146 | #[cfg(feature = "oxrdf")] 147 | impl TryInto for Format { 148 | type Error = (); 149 | 150 | fn try_into(self) -> Result { 151 | TryInto::::try_into(&self) 152 | } 153 | } 154 | 155 | #[cfg(feature = "oxrdf")] 156 | impl TryInto for &Format { 157 | type Error = (); 158 | 159 | fn try_into(self) -> Result { 160 | use oxrdfio::RdfFormat; 161 | Ok(match self { 162 | Format::Notation3 => RdfFormat::N3, 163 | Format::NQuads => RdfFormat::NQuads, 164 | Format::NTriples => RdfFormat::NTriples, 165 | Format::RdfXml => RdfFormat::RdfXml, 166 | Format::TriG => RdfFormat::TriG, 167 | Format::Turtle => RdfFormat::Turtle, 168 | _ => return Err(()), 169 | }) 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /lib/rdf-borsh/src/parse.rs: -------------------------------------------------------------------------------- 1 | // This is free and unencumbered software released into the public domain. 2 | 3 | extern crate alloc; 4 | 5 | use alloc::vec::Vec; 6 | use borsh::io::Read; 7 | use lz4_flex::frame::FrameDecoder; 8 | use rdf_model::HeapTerm; 9 | use winnow::{ 10 | binary::{le_u16, le_u32, length_take, u8}, 11 | combinator::{dispatch, fail}, 12 | error::{ContextError, ErrMode, StrContext, StrContextValue}, 13 | ModalResult, Parser, 14 | }; 15 | 16 | use crate::{BorshQuad, BorshTerm, FLAGS, MAGIC_NUMBER, VERSION_NUMBER}; 17 | 18 | #[derive(Debug)] 19 | pub enum ParseError { 20 | Io(borsh::io::Error), 21 | Parse(ErrMode), 22 | } 23 | 24 | pub fn parse_dataset( 25 | input: &mut &[u8], 26 | ) -> Result<(Vec, Vec>), ParseError> { 27 | let _quad_count = parse_header(input).map_err(ParseError::Parse)?; 28 | 29 | let mut decompressor = FrameDecoder::new(input); 30 | let mut buf = Vec::new(); 31 | decompressor.read_to_end(&mut buf).map_err(ParseError::Io)?; 32 | 33 | let mut input = buf.as_slice(); 34 | let terms = parse_term_dictionary(&mut input).map_err(ParseError::Parse)?; 35 | let quads = parse_quads_section(&mut input).map_err(ParseError::Parse)?; 36 | 37 | Ok((terms, quads)) 38 | } 39 | 40 | pub fn parse_header(input: &mut &[u8]) -> ModalResult { 41 | MAGIC_NUMBER 42 | .context(StrContext::Label("magic number")) 43 | .context(StrContext::Expected(StrContextValue::StringLiteral("RDFB"))) 44 | .parse_next(input)?; 45 | VERSION_NUMBER 46 | .context(StrContext::Label("version number")) 47 | .parse_next(input)?; 48 | FLAGS 49 | .context(StrContext::Label("flags")) 50 | .parse_next(input)?; 51 | le_u32 52 | .context(StrContext::Label("number of quads")) 53 | .parse_next(input) 54 | } 55 | 56 | pub fn parse_term_dictionary(input: &mut &[u8]) -> ModalResult> { 57 | let term_count = le_u32 58 | .context(StrContext::Label("term dictionary count")) 59 | .parse_next(input)?; 60 | let mut terms = Vec::with_capacity(term_count as usize); 61 | for _ in 0..term_count { 62 | terms.push(parse_term.parse_next(input)?) 63 | } 64 | Ok(terms) 65 | } 66 | 67 | pub fn parse_quads_section(input: &mut &[u8]) -> ModalResult>> { 68 | let quad_count = le_u32 69 | .context(StrContext::Label("quad count")) 70 | .parse_next(input)?; 71 | let mut quads = Vec::with_capacity(quad_count as usize); 72 | for _ in 0..quad_count { 73 | quads.push(parse_quad.parse_next(input)?) 74 | } 75 | Ok(quads) 76 | } 77 | 78 | pub fn parse_term(input: &mut &[u8]) -> ModalResult { 79 | dispatch!(u8; 80 | 0x01 => parse_iri, 81 | 0x02 => parse_blank_node, 82 | 0x03 => parse_plain_literal, 83 | 0x04 => parse_typed_literal, 84 | 0x05 => parse_tagged_literal, 85 | _ => fail, 86 | ) 87 | .context(StrContext::Label("term")) 88 | .parse_next(input) 89 | } 90 | 91 | pub fn parse_quad(input: &mut &[u8]) -> ModalResult> { 92 | let (g, s, p, o) = (le_u16, le_u16, le_u16, le_u16) 93 | .context(StrContext::Label("quad")) 94 | .parse_next(input)?; 95 | 96 | Ok(BorshQuad::new(s.into(), p.into(), o.into(), g.into())) 97 | } 98 | 99 | pub fn parse_iri(input: &mut &[u8]) -> ModalResult { 100 | let to_term = |data| { 101 | core::str::from_utf8(data) 102 | .map(HeapTerm::iri) 103 | .map(BorshTerm::from) 104 | }; 105 | 106 | length_take(le_u32).try_map(to_term).parse_next(input) 107 | } 108 | 109 | pub fn parse_blank_node(input: &mut &[u8]) -> ModalResult { 110 | let to_term = |data| { 111 | core::str::from_utf8(data) 112 | .map(HeapTerm::bnode) 113 | .map(BorshTerm::from) 114 | }; 115 | 116 | length_take(le_u32).try_map(to_term).parse_next(input) 117 | } 118 | 119 | pub fn parse_plain_literal(input: &mut &[u8]) -> ModalResult { 120 | let to_term = |data| { 121 | core::str::from_utf8(data) 122 | .map(HeapTerm::literal) 123 | .map(BorshTerm::from) 124 | }; 125 | 126 | length_take(le_u32).try_map(to_term).parse_next(input) 127 | } 128 | 129 | pub fn parse_typed_literal(input: &mut &[u8]) -> ModalResult { 130 | let to_term = |(data, datatype)| { 131 | let data = core::str::from_utf8(data)?; 132 | let datatype = core::str::from_utf8(datatype)?; 133 | Ok::(BorshTerm::from(HeapTerm::literal_with_datatype( 134 | data, datatype, 135 | ))) 136 | }; 137 | 138 | (length_take(le_u32), length_take(le_u32)) 139 | .try_map(to_term) 140 | .parse_next(input) 141 | } 142 | 143 | pub fn parse_tagged_literal(input: &mut &[u8]) -> ModalResult { 144 | let to_term = |(data, tag)| { 145 | let data = core::str::from_utf8(data)?; 146 | let tag = core::str::from_utf8(tag)?; 147 | Ok::(BorshTerm::from(HeapTerm::literal_with_language( 148 | data, tag, 149 | ))) 150 | }; 151 | 152 | (length_take(le_u32), length_take(le_u32)) 153 | .try_map(to_term) 154 | .parse_next(input) 155 | } 156 | --------------------------------------------------------------------------------