rdf_store_rs/
namespace.rs

1use std::str::FromStr;
2// Copyright (c) 2018-2023, agnos.ai UK Ltd, all rights reserved.
3//---------------------------------------------------------------
4use iref::{Iri, IriBuf};
5use crate::RDFStoreError;
6
7/// A `Namespace` represents a namespace IRI that can also be shown
8/// in abbreviated format, also known as "prefix".
9///
10/// For instance, the namespace IRI <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
11/// can also be shown (in [RDF Turtle](https://www.w3.org/TR/turtle/#prefixed-name)
12/// or SPARQL for instance) as `rdf:`.
13/// A "local name" such as "type" in such a namespace would look
14/// like <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> or like `rdf:type`.
15#[derive(Debug, PartialEq, Eq, Clone)]
16pub struct Namespace {
17    /// assumed to end with ':'
18    pub name: String,
19    /// assumed to end with either '/' or '#'
20    pub iri:  IriBuf,
21}
22
23impl std::fmt::Display for Namespace {
24    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25        write!(
26            f,
27            "{} <{}>",
28            self.name.as_str(),
29            self.iri.as_str()
30        )
31    }
32}
33
34impl Namespace {
35    pub fn declare(name: &str, iri: &Iri) -> Self {
36        match iri.as_str().chars().last() {
37            Some('/') | Some('#') => Self { name: name.to_string(), iri: IriBuf::from_str(iri.as_str()).unwrap() },
38            _ => {
39                Self {
40                    name: name.to_string(),
41                    iri:  IriBuf::new(format!("{}/", iri)).unwrap(),
42                }
43            },
44        }
45    }
46
47    pub fn declare_from_str(name: &str, iri: &str) -> Self {
48        Self::declare(name, &Iri::new(iri).unwrap())
49    }
50
51    /// Return an identifier based on the current namespace IRI and the given
52    /// local name within that namespace.
53    pub fn with_local_name(&self, name: &str) -> Result<IriBuf, RDFStoreError> {
54        let iri_str = match *self.iri.as_bytes().last().unwrap() as char {
55            '/' | '#' => format!("{}{name}", self.iri.as_str()),
56            _ => {
57                panic!(
58                    "{} does not end with either / or #",
59                    self.iri.as_str()
60                )
61            },
62        };
63
64        Ok(IriBuf::from_str(iri_str.as_str())?)
65    }
66
67    #[cfg(all(feature = "rdftk-support", not(target_arch = "wasm32")))]
68    pub fn as_rdftk_iri_ref(&self) -> Result<rdftk_iri::IRIRef, rdftk_iri::error::Error> {
69        Ok(rdftk_iri::IRIRef::new(self.as_rdftk_iri()?))
70    }
71
72    #[cfg(all(feature = "rdftk-support", not(target_arch = "wasm32")))]
73    pub fn as_rdftk_iri(&self) -> Result<rdftk_iri::IRI, rdftk_iri::error::Error> {
74        use std::str::FromStr;
75        rdftk_iri::IRI::from_str(self.iri.as_str())
76    }
77}
78
79#[cfg(test)]
80mod tests {
81
82    #[test_log::test]
83    fn test_a_prefix() -> Result<(), crate::RDFStoreError> {
84        let namespace = crate::Namespace::declare(
85            "test:",
86            iref::iri::Iri::new("http://whatever.kom/test#").unwrap(),
87        );
88        let x = namespace.with_local_name("abc")?;
89
90        assert_eq!(x.as_str(), "http://whatever.kom/test#abc");
91        Ok(())
92    }
93
94    #[test_log::test]
95    fn test_b_prefix() -> Result<(), crate::RDFStoreError> {
96        let namespace = crate::Namespace::declare(
97            "test:",
98            iref::iri::Iri::new("http://whatever.kom/test/").unwrap(),
99        );
100        let x = namespace.with_local_name("abc")?;
101
102        assert_eq!(x.as_str(), "http://whatever.kom/test/abc");
103        Ok(())
104    }
105}