Skip to main content

prefixmap/iri/
iri_ref.rs

1use crate::PrefixMap;
2use crate::error::{DerefError, IriRefError, PrefixMapError};
3use crate::iri::deref_iri::DerefIri;
4use iri_s::IriS;
5use iri_s::error::IriSError;
6use serde::Serialize;
7use std::borrow::Cow;
8use std::{fmt::Display, str::FromStr};
9
10/// An IRI reference, which can be either a full IRI or a prefixed name
11// TODO - Move to iri_s crate
12#[derive(Serialize, Debug, PartialEq, Hash, Eq, Clone, PartialOrd, Ord)]
13#[serde(into = "String")]
14pub enum IriRef {
15    Iri(IriS),
16    Prefixed { prefix: String, local: String },
17}
18
19/// Functions for working with [`IriRef`]
20impl IriRef {
21    /// Tries to get the IRI
22    ///
23    /// Usually you want to use [`self.get_iri_prefixmap`] instead
24    ///
25    /// Returns a reference to the IRI if successful, or an [`IriRefError`] if it is a prefixed name
26    pub fn get_iri(&self) -> Result<&IriS, IriRefError> {
27        match self {
28            IriRef::Iri(iri) => Ok(iri),
29            IriRef::Prefixed { prefix, local } => Err(IriRefError {
30                prefix: prefix.clone(),
31                local: local.clone(),
32            }),
33        }
34    }
35
36    /// Gets the IRI, resolving prefixed names using the provided [`PrefixMap`]
37    ///
38    /// Returns a [`Cow`], which is borrowed if the [`IriRef`] is already an IRI, or owned if it was a prefixed name.
39    /// If the prefixed name cannot be resolved, returns a [`PrefixMapError`]
40    pub fn get_iri_prefixmap(&self, prefixmap: &PrefixMap) -> Result<Cow<'_, IriS>, PrefixMapError> {
41        match self {
42            IriRef::Iri(iri) => Ok(Cow::Borrowed(iri)),
43            IriRef::Prefixed { prefix, local } => prefixmap.resolve_prefix_local(prefix, local).map(Cow::Owned),
44        }
45    }
46
47    /// Creates a prefixed name [`IriRef`] from the given prefix and local part
48    pub fn prefixed<S: Into<String>>(prefix: S, local: S) -> IriRef {
49        IriRef::Prefixed {
50            prefix: prefix.into(),
51            local: local.into(),
52        }
53    }
54
55    /// Creates an ['IriRef'] from an [`IriS`]
56    pub fn iri(iri: IriS) -> IriRef {
57        IriRef::Iri(iri)
58    }
59}
60
61impl DerefIri for IriRef {
62    fn deref_iri(self, base: Option<&IriS>, prefixmap: Option<&PrefixMap>) -> Result<Self, DerefError> {
63        match self {
64            IriRef::Iri(iri_s) => {
65                let resolved = match base {
66                    None => iri_s,
67                    Some(base) => base.resolve(iri_s)?,
68                };
69                Ok(IriRef::Iri(resolved))
70            },
71            IriRef::Prefixed { prefix, local } => {
72                let prefixmap = match prefixmap {
73                    None => return Err(DerefError::NoPrefixMapPrefixedName { prefix, local }),
74                    Some(pm) => pm,
75                };
76
77                let iri =
78                    prefixmap
79                        .resolve_prefix_local(&prefix, &local)
80                        .map_err(|e| DerefError::DerefPrefixMapError {
81                            alias: prefix,
82                            local,
83                            error: Box::new(e),
84                        })?;
85
86                Ok(IriRef::Iri(iri))
87            },
88        }
89    }
90}
91
92impl TryFrom<&str> for IriRef {
93    type Error = IriSError;
94
95    fn try_from(value: &str) -> Result<Self, Self::Error> {
96        FromStr::from_str(value)
97    }
98}
99
100impl FromStr for IriRef {
101    type Err = IriSError;
102
103    fn from_str(s: &str) -> Result<Self, Self::Err> {
104        Ok(IriRef::Iri(IriS::from_str(s)?))
105    }
106}
107
108impl From<IriRef> for IriS {
109    fn from(iri_ref: IriRef) -> IriS {
110        match iri_ref {
111            IriRef::Iri(iri_s) => iri_s,
112            IriRef::Prefixed { prefix, local } => {
113                panic!("Cannot convert prefixed name {prefix}:{local} to IriS without context")
114            },
115        }
116    }
117}
118
119impl From<IriS> for IriRef {
120    fn from(i: IriS) -> IriRef {
121        IriRef::Iri(i)
122    }
123}
124
125impl From<IriRef> for String {
126    fn from(iri_ref: IriRef) -> String {
127        match iri_ref {
128            IriRef::Iri(i) => i.as_str().to_string(),
129            IriRef::Prefixed { prefix, local } => format!("{prefix}:{local}"),
130        }
131    }
132}
133
134impl Display for IriRef {
135    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
136        match self {
137            IriRef::Iri(i) => write!(f, "{i}"),
138            IriRef::Prefixed { prefix, local } => write!(f, "{prefix}:{local}"),
139        }
140    }
141}