Rust implementation of NextGraph, a Decentralized and local-first web 3.0 ecosystem
https://nextgraph.org
byzantine-fault-tolerancecrdtsdappsdecentralizede2eeeventual-consistencyjson-ldlocal-firstmarkdownocapoffline-firstp2pp2p-networkprivacy-protectionrdfrich-text-editorself-hostedsemantic-websparqlweb3collaboration
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
216 lines
6.7 KiB
216 lines
6.7 KiB
use std::fmt;
|
|
|
|
/// RDF serialization formats.
|
|
///
|
|
/// This enumeration is non exhaustive. New formats like JSON-LD might be added in the future.
|
|
#[derive(Eq, PartialEq, Debug, Clone, Copy, Hash)]
|
|
#[non_exhaustive]
|
|
pub enum RdfFormat {
|
|
/// [N3](https://w3c.github.io/N3/spec/)
|
|
N3,
|
|
/// [N-Quads](https://www.w3.org/TR/n-quads/)
|
|
NQuads,
|
|
/// [N-Triples](https://www.w3.org/TR/n-triples/)
|
|
NTriples,
|
|
/// [RDF/XML](https://www.w3.org/TR/rdf-syntax-grammar/)
|
|
RdfXml,
|
|
/// [TriG](https://www.w3.org/TR/trig/)
|
|
TriG,
|
|
/// [Turtle](https://www.w3.org/TR/turtle/)
|
|
Turtle,
|
|
}
|
|
|
|
impl RdfFormat {
|
|
/// The format canonical IRI according to the [Unique URIs for file formats registry](https://www.w3.org/ns/formats/).
|
|
///
|
|
/// ```
|
|
/// use oxrdfio::RdfFormat;
|
|
///
|
|
/// assert_eq!(
|
|
/// RdfFormat::NTriples.iri(),
|
|
/// "http://www.w3.org/ns/formats/N-Triples"
|
|
/// )
|
|
/// ```
|
|
#[inline]
|
|
pub const fn iri(self) -> &'static str {
|
|
match self {
|
|
Self::N3 => "http://www.w3.org/ns/formats/N3",
|
|
Self::NQuads => "http://www.w3.org/ns/formats/N-Quads",
|
|
Self::NTriples => "http://www.w3.org/ns/formats/N-Triples",
|
|
Self::RdfXml => "http://www.w3.org/ns/formats/RDF_XML",
|
|
Self::TriG => "http://www.w3.org/ns/formats/TriG",
|
|
Self::Turtle => "http://www.w3.org/ns/formats/Turtle",
|
|
}
|
|
}
|
|
|
|
/// The format [IANA media type](https://tools.ietf.org/html/rfc2046).
|
|
///
|
|
/// ```
|
|
/// use oxrdfio::RdfFormat;
|
|
///
|
|
/// assert_eq!(RdfFormat::NTriples.media_type(), "application/n-triples")
|
|
/// ```
|
|
#[inline]
|
|
pub const fn media_type(self) -> &'static str {
|
|
match self {
|
|
Self::N3 => "text/n3",
|
|
Self::NQuads => "application/n-quads",
|
|
Self::NTriples => "application/n-triples",
|
|
Self::RdfXml => "application/rdf+xml",
|
|
Self::TriG => "application/trig",
|
|
Self::Turtle => "text/turtle",
|
|
}
|
|
}
|
|
|
|
/// The format [IANA-registered](https://tools.ietf.org/html/rfc2046) file extension.
|
|
///
|
|
/// ```
|
|
/// use oxrdfio::RdfFormat;
|
|
///
|
|
/// assert_eq!(RdfFormat::NTriples.file_extension(), "nt")
|
|
/// ```
|
|
#[inline]
|
|
pub const fn file_extension(self) -> &'static str {
|
|
match self {
|
|
Self::N3 => "n3",
|
|
Self::NQuads => "nq",
|
|
Self::NTriples => "nt",
|
|
Self::RdfXml => "rdf",
|
|
Self::TriG => "trig",
|
|
Self::Turtle => "ttl",
|
|
}
|
|
}
|
|
|
|
/// The format name.
|
|
///
|
|
/// ```
|
|
/// use oxrdfio::RdfFormat;
|
|
///
|
|
/// assert_eq!(RdfFormat::NTriples.name(), "N-Triples")
|
|
/// ```
|
|
#[inline]
|
|
pub const fn name(self) -> &'static str {
|
|
match self {
|
|
Self::N3 => "N3",
|
|
Self::NQuads => "N-Quads",
|
|
Self::NTriples => "N-Triples",
|
|
Self::RdfXml => "RDF/XML",
|
|
Self::TriG => "TriG",
|
|
Self::Turtle => "Turtle",
|
|
}
|
|
}
|
|
|
|
/// Checks if the formats supports [RDF datasets](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-dataset) and not only [RDF graphs](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-graph).
|
|
///
|
|
/// ```
|
|
/// use oxrdfio::RdfFormat;
|
|
///
|
|
/// assert_eq!(RdfFormat::NTriples.supports_datasets(), false);
|
|
/// assert_eq!(RdfFormat::NQuads.supports_datasets(), true);
|
|
/// ```
|
|
#[inline]
|
|
pub const fn supports_datasets(self) -> bool {
|
|
matches!(self, Self::NQuads | Self::TriG)
|
|
}
|
|
|
|
/// Checks if the formats supports [RDF-star quoted triples](https://w3c.github.io/rdf-star/cg-spec/2021-12-17.html#dfn-quoted).
|
|
///
|
|
/// ```
|
|
/// use oxrdfio::RdfFormat;
|
|
///
|
|
/// assert_eq!(RdfFormat::NTriples.supports_rdf_star(), true);
|
|
/// assert_eq!(RdfFormat::RdfXml.supports_rdf_star(), false);
|
|
/// ```
|
|
#[inline]
|
|
#[cfg(feature = "rdf-star")]
|
|
pub const fn supports_rdf_star(self) -> bool {
|
|
matches!(
|
|
self,
|
|
Self::NTriples | Self::NQuads | Self::Turtle | Self::TriG
|
|
)
|
|
}
|
|
|
|
/// Looks for a known format from a media type.
|
|
///
|
|
/// It supports some media type aliases.
|
|
/// For example, "application/xml" is going to return `RdfFormat::RdfXml` even if it is not its canonical media type.
|
|
///
|
|
/// Example:
|
|
/// ```
|
|
/// use oxrdfio::RdfFormat;
|
|
///
|
|
/// assert_eq!(
|
|
/// RdfFormat::from_media_type("text/turtle; charset=utf-8"),
|
|
/// Some(RdfFormat::Turtle)
|
|
/// )
|
|
/// ```
|
|
#[inline]
|
|
pub fn from_media_type(media_type: &str) -> Option<Self> {
|
|
const MEDIA_SUBTYPES: [(&str, RdfFormat); 10] = [
|
|
("n-quads", RdfFormat::NQuads),
|
|
("n-triples", RdfFormat::NTriples),
|
|
("n3", RdfFormat::N3),
|
|
("nquads", RdfFormat::NQuads),
|
|
("ntriples", RdfFormat::NTriples),
|
|
("plain", RdfFormat::NTriples),
|
|
("rdf+xml", RdfFormat::RdfXml),
|
|
("trig", RdfFormat::TriG),
|
|
("turtle", RdfFormat::Turtle),
|
|
("xml", RdfFormat::RdfXml),
|
|
];
|
|
|
|
let (r#type, subtype) = media_type
|
|
.split_once(';')
|
|
.unwrap_or((media_type, ""))
|
|
.0
|
|
.split_once('/')?;
|
|
let r#type = r#type.trim();
|
|
if !r#type.eq_ignore_ascii_case("application") && !r#type.eq_ignore_ascii_case("text") {
|
|
return None;
|
|
}
|
|
let subtype = subtype.trim();
|
|
let subtype = subtype.strip_prefix("x-").unwrap_or(subtype);
|
|
for (candidate_subtype, candidate_id) in MEDIA_SUBTYPES {
|
|
if candidate_subtype.eq_ignore_ascii_case(subtype) {
|
|
return Some(candidate_id);
|
|
}
|
|
}
|
|
None
|
|
}
|
|
|
|
/// Looks for a known format from an extension.
|
|
///
|
|
/// It supports some aliases.
|
|
///
|
|
/// Example:
|
|
/// ```
|
|
/// use oxrdfio::RdfFormat;
|
|
///
|
|
/// assert_eq!(RdfFormat::from_extension("nt"), Some(RdfFormat::NTriples))
|
|
/// ```
|
|
#[inline]
|
|
pub fn from_extension(extension: &str) -> Option<Self> {
|
|
const MEDIA_TYPES: [(&str, RdfFormat); 8] = [
|
|
("n3", RdfFormat::N3),
|
|
("nq", RdfFormat::NQuads),
|
|
("nt", RdfFormat::NTriples),
|
|
("rdf", RdfFormat::RdfXml),
|
|
("trig", RdfFormat::TriG),
|
|
("ttl", RdfFormat::Turtle),
|
|
("txt", RdfFormat::NTriples),
|
|
("xml", RdfFormat::RdfXml),
|
|
];
|
|
for (candidate_extension, candidate_id) in MEDIA_TYPES {
|
|
if candidate_extension.eq_ignore_ascii_case(extension) {
|
|
return Some(candidate_id);
|
|
}
|
|
}
|
|
None
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for RdfFormat {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
f.write_str(self.name())
|
|
}
|
|
}
|
|
|