Skip to main content

ekg_identifier/iri/
a_box_base.rs

1use {
2    crate::{TBoxNamespaceIRI, iri::NamespaceIRI},
3    ekg_error::Error,
4    iref::Iri,
5    serde::{Deserialize, Serialize},
6};
7
8/// An `ABoxNamespaceIRI` is a namespace IRI for ABox resources in an EKG where
9/// we always want to use the `/` separator for local names since anything that
10/// comes after a `#` separator is not passed through to the server-side in an
11/// HTTP request.
12#[derive(Serialize, Deserialize, Clone, Debug)]
13pub struct ABoxNamespaceIRI(
14    #[serde(deserialize_with = "ekg_util::serde_util::deserialize_uri")]
15    #[serde(serialize_with = "ekg_util::serde_util::serialize_base_uri")]
16    pub iri_string::types::IriReferenceString,
17);
18
19impl ABoxNamespaceIRI {
20    #[inline]
21    pub fn as_str(&self) -> &str { self.0.as_str() }
22
23    // noinspection DuplicatedCode
24    pub fn as_base_iri(&self) -> String {
25        let str = self.as_str();
26        let last_char = str.chars().last().unwrap();
27        if last_char == '/' {
28            str.to_string()
29        } else {
30            format!("{str}/")
31        }
32    }
33
34    pub fn as_default_id_base_iri(&self) -> Result<Self, Error> {
35        use std::str::FromStr;
36        let str = self.as_str();
37        let last_char = str.chars().last().unwrap();
38        if last_char == '/' {
39            Self::from_str(format!("{str}{}/", crate::DEFAULT_ID_PATH).as_str())
40        } else {
41            Self::from_str(format!("{str}/{}/", crate::DEFAULT_ID_PATH).as_str())
42        }
43    }
44}
45
46impl NamespaceIRI for ABoxNamespaceIRI {
47    fn as_str(&self) -> &str { self.0.as_str() }
48
49    fn authority(&self) -> Option<&str> {
50        let iri = unsafe { Iri::new_unchecked(self.0.as_str()) };
51        iri.authority()
52            .and_then(|authority| {
53                match authority.host().as_str() {
54                    "127.0.0.1" | "localhost" => None,
55                    _ => Some(authority),
56                }
57            })
58            .map(|authority| authority.as_str())
59    }
60}
61
62impl std::fmt::Display for ABoxNamespaceIRI {
63    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.0) }
64}
65
66impl From<iri_string::types::IriReferenceString> for ABoxNamespaceIRI {
67    fn from(uri: iri_string::types::IriReferenceString) -> Self { Self(uri) }
68}
69
70impl std::str::FromStr for ABoxNamespaceIRI {
71    type Err = ekg_error::Error;
72
73    fn from_str(uri_str: &str) -> Result<Self, Self::Err> {
74        let last_char = uri_str.chars().last().unwrap();
75        if last_char == '/' {
76            Ok(Self(
77                iri_string::types::IriReferenceString::try_from(uri_str.to_owned())?,
78            ))
79        } else {
80            Err(ekg_error::Error::ABoxNamespaceIRIDoesNotEndWithSlash { iri: uri_str.to_owned() })
81        }
82    }
83}
84
85/// Convert a TBoxNamespaceIRI into an ABoxNamespaceIRI which only works when
86/// the TBoxNamespaceIRI ends with a slash (`/`).
87impl TryFrom<TBoxNamespaceIRI> for ABoxNamespaceIRI {
88    type Error = ekg_error::Error;
89
90    fn try_from(value: TBoxNamespaceIRI) -> Result<Self, Self::Error> { Ok(Self(value.0)) }
91}