flams_ontology/uris/
paths.rs

1use crate::uris::archives::ArchiveURIRef;
2use crate::uris::errors::URIParseError;
3use crate::uris::macros::debugdisplay;
4use crate::uris::{
5    ArchiveURI, ArchiveURITrait, BaseURI, Name, URIOrRefTrait, URIRef, URIRefTrait, URITrait, URI,
6};
7use const_format::concatcp;
8use either::Either;
9use flams_utils::parsing::StringOrStr;
10use std::fmt::Display;
11use std::str::{FromStr, Split};
12
13#[derive(Clone, PartialEq, Eq, Hash)]
14pub struct PathURI {
15    pub(super) archive: ArchiveURI,
16    pub(super) path: Option<Name>,
17}
18impl From<ArchiveURI> for PathURI {
19    #[inline]
20    fn from(archive: ArchiveURI) -> Self {
21        Self {
22            archive,
23            path: None,
24        }
25    }
26}
27impl PathURI {
28    pub const SEPARATOR: char = 'p';
29    #[inline]
30    #[must_use]
31    #[allow(clippy::missing_const_for_fn)]
32    pub fn path(&self) -> Option<&Name> {
33        self.path.as_ref()
34    }
35    #[inline]
36    #[must_use]
37    pub fn up(mut self) -> Self {
38        if let Some(name) = &mut self.path {
39            name.0.pop();
40            if name.0.is_empty() {
41                self.path = None
42            }
43        }
44        self
45    }
46}
47impl Display for PathURI {
48    #[inline]
49    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
50        Display::fmt(&self.as_path(), f)
51    }
52}
53debugdisplay!(PathURI);
54
55impl URIOrRefTrait for PathURI {
56    #[inline]
57    fn base(&self) -> &BaseURI {
58        &self.archive.base
59    }
60    #[inline]
61    fn as_uri(&self) -> URIRef {
62        URIRef::Path(self.as_path())
63    }
64}
65impl URITrait for PathURI {
66    type Ref<'a> = PathURIRef<'a>;
67}
68impl ArchiveURITrait for PathURI {
69    #[inline]
70    fn archive_uri(&self) -> ArchiveURIRef {
71        self.archive.archive_uri()
72    }
73}
74
75#[derive(Clone, Copy, PartialEq, Eq, Hash)]
76pub struct PathURIRef<'a> {
77    pub(super) archive: ArchiveURIRef<'a>,
78    pub(super) path: Option<&'a Name>,
79}
80impl<'a> From<&'a PathURI> for PathURIRef<'a> {
81    #[inline]
82    fn from(value: &'a PathURI) -> Self {
83        Self {
84            archive: value.archive.archive_uri(),
85            path: value.path.as_ref(),
86        }
87    }
88}
89impl<'a> URIOrRefTrait for PathURIRef<'a> {
90    #[inline]
91    fn base(&self) -> &'a BaseURI {
92        self.archive.base
93    }
94    #[inline]
95    fn as_uri(&self) -> URIRef<'a> {
96        URIRef::Path(*self)
97    }
98}
99impl<'a> URIRefTrait<'a> for PathURIRef<'a> {
100    type Owned = PathURI;
101    #[inline]
102    fn owned(self) -> PathURI {
103        PathURI {
104            archive: self.archive.owned(),
105            path: self.path.cloned(),
106        }
107    }
108}
109impl Display for PathURIRef<'_> {
110    #[inline]
111    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
112        if let Some(path) = self.path {
113            write!(f, "{}&{}={}", self.archive, PathURI::SEPARATOR, path)
114        } else {
115            Display::fmt(&self.archive, f)
116        }
117    }
118}
119debugdisplay!(PathURIRef<'_>);
120
121pub trait PathURITrait: ArchiveURITrait {
122    fn as_path(&self) -> PathURIRef;
123    #[inline]
124    fn path(&self) -> Option<&Name> {
125        self.as_path().path
126    }
127}
128impl PathURITrait for PathURI {
129    fn as_path(&self) -> PathURIRef {
130        PathURIRef {
131            archive: self.archive.archive_uri(),
132            path: self.path.as_ref(),
133        }
134    }
135}
136impl PathURITrait for PathURIRef<'_> {
137    #[inline]
138    fn as_path(&self) -> Self {
139        *self
140    }
141}
142impl<'a> ArchiveURITrait for PathURIRef<'a> {
143    #[inline]
144    fn archive_uri(&self) -> ArchiveURIRef<'a> {
145        self.archive
146    }
147}
148impl PathURI {
149    pub(super) fn pre_parse<R>(
150        s: &str,
151        uri_kind: &'static str,
152        f: impl FnOnce(Self, Option<&str>, Split<char>) -> Result<R, URIParseError>,
153    ) -> Result<R, URIParseError> {
154        ArchiveURI::pre_parse(s, uri_kind, |archive, mut split| {
155            let (p, n) = if let Some(p) = split.next() {
156                if let Some(p) = p.strip_prefix(concatcp!(PathURI::SEPARATOR, "=")) {
157                    (
158                        Self {
159                            archive,
160                            path: Some(p.parse()?),
161                        },
162                        None,
163                    )
164                } else {
165                    (
166                        Self {
167                            archive,
168                            path: None,
169                        },
170                        Some(p),
171                    )
172                }
173            } else {
174                (
175                    Self {
176                        archive,
177                        path: None,
178                    },
179                    None,
180                )
181            };
182            f(p, n, split)
183        })
184    }
185}
186impl FromStr for PathURI {
187    type Err = URIParseError;
188    fn from_str(s: &str) -> Result<Self, Self::Err> {
189        Self::pre_parse(s, "path uri", |u, next, mut split| {
190            if next.is_some() || split.next().is_some() {
191                return Err(URIParseError::TooManyPartsFor {
192                    uri_kind: "path uri",
193                    original: s.to_string(),
194                });
195            }
196            Ok(u)
197        })
198    }
199}
200
201#[cfg(feature = "serde")]
202mod serde_impl {
203    use super::{PathURI, PathURIRef};
204    use crate::uris::serialize;
205    serialize!(DE PathURI);
206    serialize!(PathURIRef<'_>);
207}