flams_ontology/uris/
mod.rs

1/*! # URIs
2 *
3 * ## Grammar
4 *
5 * | Type  |     | Cases/Def | Trait | Reference |
6 * |----------- |---- | -----|-------|---------|
7 * | [URI]      | ::= | [BaseURI]⏐[ArchiveURI]⏐[PathURI]⏐[ContentURI]⏐[NarrativeURI] | [URITrait] | [URIRef] |
8 * | [BaseURI]  | ::= | (URL with no query/fragment) | - | `&`[BaseURI] |
9 * | [ArchiveURI] | ::= | [BaseURI]`?a=`[ArchiveId] | [ArchiveURITrait] | [ArchiveURIRef] |
10 * | [PathURI]  | ::= | [ArchiveURI]`[&p=`[Name]`]` | [PathURITrait] | [PathURIRef] |
11 * | [ContentURI] | ::= | [ModuleURI]⏐[SymbolURI]   | [ContentURITrait] | [ContentURIRef] |
12 * | [NarrativeURI] | ::= | [DocumentURI]⏐[DocumentElementURI] | [NarrativeURITrait] | [NarrativeURIRef] |
13 * | [ModuleURI] | ::= | [PathURI]`&m=`[Name]`&l=`[Language] | - | `&`[ModuleURI] |
14 * | [SymbolURI] | ::= | [ModuleURI]`&s=`[Name] | - | `&`[SymbolURI] |
15 * | [DocumentURI] | ::= | [PathURI]`&d=`[Name]`&l=`[Language] | - | `&`[DocumentURI] |
16 * | [DocumentElementURI] | ::= | [DocumentURI]`&e=`[Name] | - | `&`[DocumentElementURI] |
17*/
18
19#![allow(unused_macros)]
20#![allow(unused_imports)]
21
22mod archives;
23mod base;
24mod content;
25mod errors;
26mod infix;
27mod name;
28mod narrative;
29mod paths;
30pub mod terms;
31
32pub use archives::{ArchiveId, ArchiveURI, ArchiveURIRef, ArchiveURITrait};
33pub use base::BaseURI;
34pub use content::{
35    modules::{ModuleURI, ModuleURIRef},
36    symbols::{SymbolURI, SymbolURIRef},
37    ContentURI, ContentURIRef, ContentURITrait,
38};
39pub use errors::URIParseError;
40pub use name::{InvalidURICharacter, Name, NameStep};
41pub use narrative::{
42    document_elements::DocumentElementURI, documents::DocumentURI, NarrativeURI, NarrativeURIRef,
43    NarrativeURITrait,
44};
45pub use paths::{PathURI, PathURIRef, PathURITrait};
46
47use const_format::concatcp;
48use either::Either;
49use flams_utils::parsing::StringOrStr;
50use std::fmt::{Debug, Display};
51use std::hash::Hash;
52use std::str::{FromStr, Split};
53
54#[cfg(feature = "wasm")]
55#[cfg_attr(
56    feature = "wasm",
57    wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)
58)]
59const TS_URI: &str = "export type URI = string;";
60
61pub(crate) mod macros {
62    macro_rules! debugdisplay {
63        ($s:ty) => {
64            impl std::fmt::Debug for $s {
65                #[inline]
66                fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
67                    std::fmt::Display::fmt(self, f)
68                }
69            }
70        };
71    }
72    macro_rules! serialize {
73        (as+DE $s:ty) => {
74            serialize!(as $s);
75            impl<'de> serde::Deserialize<'de> for $s {
76                fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
77                    let s = String::deserialize(deserializer)?;
78                    s.parse().map_err(serde::de::Error::custom)
79                }
80            }
81        };
82        (as $s:ty) => {
83            impl serde::Serialize for $s {
84                fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
85                    serializer.serialize_str(self.as_ref())
86                }
87            }
88        };
89        (DE $s:ty) => {
90            serialize!($s);
91            impl<'de> serde::Deserialize<'de> for $s {
92                fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
93                    let s = String::deserialize(deserializer)?;
94                    s.parse().map_err(serde::de::Error::custom)
95                }
96            }
97        };
98        ($s:ty) => {
99            impl serde::Serialize for $s {
100                fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
101                    serializer.collect_str(self)
102                }
103            }
104        };
105    }
106    pub(crate) use {debugdisplay, serialize};
107}
108use crate::languages::Language;
109pub(crate) use macros::{debugdisplay, serialize};
110
111mod sealed {
112    pub trait Sealed {}
113}
114
115macro_rules! common {
116    () => {
117        #[cfg(feature = "rdf")]
118        fn to_iri(&self) -> crate::rdf::NamedNode {
119            crate::rdf::NamedNode::new(flams_utils::escaping::IRI_ESCAPE.escape(self).to_string())
120                .unwrap_or_else(|_| unreachable!())
121        }
122        fn base(&self) -> &BaseURI;
123        fn as_uri(&self) -> URIRef;
124    };
125}
126
127#[cfg(not(feature = "serde"))]
128pub trait URIOrRefTrait: Display + Debug + Clone + Hash + sealed::Sealed {
129    common! {}
130}
131
132#[cfg(feature = "serde")]
133pub trait URIOrRefTrait:
134    Display + Debug + Clone + Hash + serde::Serialize + sealed::Sealed
135{
136    common! {}
137}
138
139#[cfg(not(feature = "serde"))]
140pub trait URITrait: URIOrRefTrait + Into<URI> {
141    type Ref<'a>: URIRefTrait<'a, Owned = Self>; // where &'a Self:Into<Self::Ref<'a>>;
142}
143
144#[cfg(feature = "serde")]
145pub trait URITrait:
146    URIOrRefTrait + serde::Deserialize<'static> + Into<URI> + FromStr + std::fmt::Display
147{
148    type Ref<'a>: URIRefTrait<'a, Owned = Self>; // where &'a Self:Into<Self::Ref<'a>>;
149}
150
151pub trait URIRefTrait<'a>: URIOrRefTrait + Copy + Into<URIRef<'a>> {
152    type Owned: URITrait<Ref<'a> = Self>;
153    fn owned(self) -> Self::Owned;
154}
155
156pub trait URIWithLanguage: URIOrRefTrait {
157    fn language(&self) -> Language;
158}
159impl<'a, A: URITrait<Ref<'a> = &'a A> + URIWithLanguage> URIWithLanguage for &'a A {
160    #[inline]
161    fn language(&self) -> Language {
162        A::language(self)
163    }
164}
165
166impl<U: URITrait> sealed::Sealed for &U {}
167impl<U: URITrait> URIOrRefTrait for &U {
168    #[inline]
169    fn base(&self) -> &BaseURI {
170        (*self).base()
171    }
172    #[inline]
173    fn as_uri(&self) -> URIRef {
174        (*self).as_uri()
175    }
176}
177
178#[derive(Clone, Hash, PartialEq, Eq)]
179pub enum URI {
180    Base(BaseURI),
181    Archive(ArchiveURI),
182    Path(PathURI),
183    Content(ContentURI),
184    Narrative(NarrativeURI),
185}
186impl sealed::Sealed for URI {}
187impl sealed::Sealed for BaseURI {}
188impl sealed::Sealed for ArchiveURI {}
189impl sealed::Sealed for PathURI {}
190impl sealed::Sealed for ContentURI {}
191impl sealed::Sealed for ModuleURI {}
192impl sealed::Sealed for SymbolURI {}
193impl sealed::Sealed for NarrativeURI {}
194impl sealed::Sealed for DocumentURI {}
195impl sealed::Sealed for DocumentElementURI {}
196
197impl From<BaseURI> for URI {
198    #[inline]
199    fn from(b: BaseURI) -> Self {
200        Self::Base(b)
201    }
202}
203impl From<ArchiveURI> for URI {
204    #[inline]
205    fn from(b: ArchiveURI) -> Self {
206        Self::Archive(b)
207    }
208}
209impl From<PathURI> for URI {
210    #[inline]
211    fn from(b: PathURI) -> Self {
212        Self::Path(b)
213    }
214}
215impl From<ContentURI> for URI {
216    #[inline]
217    fn from(b: ContentURI) -> Self {
218        Self::Content(b)
219    }
220}
221impl From<NarrativeURI> for URI {
222    #[inline]
223    fn from(b: NarrativeURI) -> Self {
224        Self::Narrative(b)
225    }
226}
227
228#[derive(Clone, Copy, Hash, PartialEq, Eq)]
229pub enum URIRef<'a> {
230    Base(&'a BaseURI),
231    Archive(ArchiveURIRef<'a>),
232    Path(PathURIRef<'a>),
233    Content(ContentURIRef<'a>),
234    Narrative(NarrativeURIRef<'a>),
235}
236impl sealed::Sealed for ArchiveURIRef<'_> {}
237impl sealed::Sealed for PathURIRef<'_> {}
238//impl sealed::Sealed for ModuleURIRef<'_> {}
239//impl sealed::Sealed for SymbolURIRef<'_> {}
240impl sealed::Sealed for URIRef<'_> {}
241impl sealed::Sealed for ContentURIRef<'_> {}
242impl sealed::Sealed for NarrativeURIRef<'_> {}
243impl<'a> From<&'a BaseURI> for URIRef<'a> {
244    #[inline]
245    fn from(b: &'a BaseURI) -> Self {
246        Self::Base(b)
247    }
248}
249impl<'a> From<&'a ArchiveURI> for URIRef<'a> {
250    #[inline]
251    fn from(b: &'a ArchiveURI) -> Self {
252        Self::Archive(b.archive_uri())
253    }
254}
255impl<'a> From<PathURIRef<'a>> for URIRef<'a> {
256    #[inline]
257    fn from(b: PathURIRef<'a>) -> Self {
258        Self::Path(b)
259    }
260}
261impl<'a> From<ArchiveURIRef<'a>> for URIRef<'a> {
262    #[inline]
263    fn from(b: ArchiveURIRef<'a>) -> Self {
264        Self::Archive(b)
265    }
266}
267impl<'a> From<ContentURIRef<'a>> for URIRef<'a> {
268    #[inline]
269    fn from(b: ContentURIRef<'a>) -> Self {
270        Self::Content(b)
271    }
272}
273impl<'a> From<NarrativeURIRef<'a>> for URIRef<'a> {
274    #[inline]
275    fn from(b: NarrativeURIRef<'a>) -> Self {
276        Self::Narrative(b)
277    }
278}
279
280macro_rules! inherit {
281    ($self:ident = $b:ident => $fun:expr) => {
282        match $self {
283            Self::Base($b) => $fun,
284            Self::Archive($b) => $fun,
285            Self::Path($b) => $fun,
286            Self::Content($b) => $fun,
287            Self::Narrative($b) => $fun,
288        }
289    };
290}
291
292impl Display for URI {
293    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
294        inherit!(self = b => Display::fmt(b,f))
295    }
296}
297debugdisplay!(URI);
298impl Display for URIRef<'_> {
299    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
300        inherit!(self = b => Display::fmt(b,f))
301    }
302}
303debugdisplay!(URIRef<'_>);
304
305impl URIOrRefTrait for URIRef<'_> {
306    #[inline]
307    fn base(&self) -> &BaseURI {
308        inherit!(self = b => b.base())
309    }
310    fn as_uri(&self) -> URIRef {
311        *self
312    }
313}
314
315impl URI {
316    fn parse_content(
317        s: &str,
318        module: &str,
319        path: impl FnOnce() -> Result<PathURI, URIParseError>,
320        mut split: Split<char>,
321    ) -> Result<ContentURI, URIParseError> {
322        let name = move || module.parse();
323        let module = move || {
324            Ok::<_, URIParseError>(ModuleURI {
325                path: path()?,
326                name: name()?,
327            })
328        };
329        let Some(next) = split.next() else {
330            return Ok(ContentURI::Module(module()?));
331        };
332        next.strip_prefix(concatcp!(SymbolURI::SEPARATOR, "="))
333            .map_or_else(
334                || {
335                    Err(URIParseError::UnrecognizedPart {
336                        original: s.to_string(),
337                    })
338                },
339                |symbol| {
340                    if split.next().is_some() {
341                        Err(URIParseError::TooManyPartsFor {
342                            uri_kind: "symbol uri",
343                            original: s.to_string(),
344                        })
345                    } else {
346                        Ok(ContentURI::Symbol(SymbolURI {
347                            module: module()?,
348                            name: symbol.parse()?,
349                        }))
350                    }
351                },
352            )
353    }
354    fn parse_narrative(
355        s: &str,
356        document: &str,
357        (language, next): (Language, Option<&str>),
358        path: impl FnOnce() -> Result<PathURI, URIParseError>,
359        mut split: Split<char>,
360    ) -> Result<NarrativeURI, URIParseError> {
361        let name = move || document.parse();
362        let document = move || {
363            Ok::<_, URIParseError>(DocumentURI {
364                path: path()?,
365                name: name()?,
366                language,
367            })
368        };
369        let Some(next) = next else {
370            return Ok(NarrativeURI::Document(document()?));
371        };
372        next.strip_prefix(concatcp!(DocumentElementURI::SEPARATOR, "="))
373            .map_or_else(
374                || {
375                    Err(URIParseError::UnrecognizedPart {
376                        original: s.to_string(),
377                    })
378                },
379                |element| {
380                    if split.next().is_some() {
381                        Err(URIParseError::TooManyPartsFor {
382                            uri_kind: "document element uri",
383                            original: s.to_string(),
384                        })
385                    } else {
386                        Ok(NarrativeURI::Element(DocumentElementURI {
387                            document: document()?,
388                            name: element.parse()?,
389                        }))
390                    }
391                },
392            )
393    }
394}
395
396impl FromStr for URI {
397    type Err = URIParseError;
398    fn from_str(s: &str) -> Result<Self, Self::Err> {
399        let (base, mut split) = match BaseURI::pre_parse(s)? {
400            Either::Left(base) => return Ok(Self::Base(base)),
401            Either::Right(c) => c,
402        };
403        let Some(next) = split.next() else {
404            unreachable!()
405        };
406        next.strip_prefix(concatcp!(ArchiveURI::SEPARATOR, "="))
407            .map_or_else(
408                || {
409                    Err(URIParseError::UnrecognizedPart {
410                        original: s.to_string(),
411                    })
412                },
413                |archive| {
414                    let archive = move || ArchiveURI {
415                        base,
416                        archive: archive.parse().unwrap_or_else(|_| unreachable!()),
417                    };
418                    let Some(next) = split.next() else {
419                        return Ok(Self::Archive(archive()));
420                    };
421                    let (path, next) =
422                        if let Some(path) = next.strip_prefix(concatcp!(PathURI::SEPARATOR, "=")) {
423                            (
424                                Either::Left(|| {
425                                    Ok(PathURI {
426                                        archive: archive(),
427                                        path: Some(path.parse()?),
428                                    })
429                                }),
430                                split.next(),
431                            )
432                        } else {
433                            (
434                                Either::Right(|| PathURI {
435                                    archive: archive(),
436                                    path: None,
437                                }),
438                                Some(next),
439                            )
440                        };
441                    let path = move || match path {
442                        Either::Left(p) => p(),
443                        Either::Right(p) => Ok(p()),
444                    };
445                    let Some(next) = next else {
446                        return Ok(Self::Path(path()?));
447                    };
448                    let mut language = || {
449                        split.next().map_or_else(
450                            || Ok((Language::default(), None)),
451                            |n| {
452                                n.strip_prefix(concatcp!(Language::SEPARATOR, "="))
453                                    .map_or_else(
454                                        || Ok((Language::default(), Some(n))),
455                                        |l| {
456                                            l.parse()
457                                                .map_err(|()| URIParseError::InvalidLanguage {
458                                                    uri_kind: "uri",
459                                                    original: s.to_string(),
460                                                })
461                                                .map(|l| (l, split.next()))
462                                        },
463                                    )
464                            },
465                        )
466                    };
467                    if let Some(module) = next.strip_prefix(concatcp!(ModuleURI::SEPARATOR, "=")) {
468                        Ok(Self::Content(Self::parse_content(s, module, path, split)?))
469                    } else if let Some(document) =
470                        next.strip_prefix(concatcp!(DocumentURI::SEPARATOR, "="))
471                    {
472                        Ok(Self::Narrative(Self::parse_narrative(
473                            s,
474                            document,
475                            language()?,
476                            path,
477                            split,
478                        )?))
479                    } else {
480                        Err(URIParseError::UnrecognizedPart {
481                            original: s.to_string(),
482                        })
483                    }
484                },
485            )
486    }
487}
488impl URIOrRefTrait for URI {
489    #[inline]
490    fn base(&self) -> &BaseURI {
491        inherit!(self = b => b.base())
492    }
493    fn as_uri(&self) -> URIRef {
494        match self {
495            Self::Base(b) => URIRef::Base(b),
496            Self::Archive(a) => URIRef::Archive(a.archive_uri()),
497            Self::Path(p) => URIRef::Path(p.as_path()),
498            Self::Content(c) => URIRef::Content(c.as_content()),
499            Self::Narrative(n) => URIRef::Narrative(n.as_narrative()),
500        }
501    }
502}
503
504impl URITrait for URI {
505    type Ref<'a> = URIRef<'a>;
506}
507impl<'a> URIRefTrait<'a> for URIRef<'a> {
508    type Owned = URI;
509    fn owned(self) -> URI {
510        match self {
511            Self::Base(b) => URI::Base(b.clone()),
512            Self::Archive(a) => URI::Archive(a.owned()),
513            Self::Path(p) => URI::Path(p.owned()),
514            Self::Content(c) => URI::Content(c.owned()),
515            Self::Narrative(n) => URI::Narrative(n.owned()),
516        }
517    }
518}
519
520#[cfg(feature = "serde")]
521mod serde_impl {
522    use super::{serialize, URIRef, URI};
523    serialize!(DE URI);
524    serialize!(URIRef<'_>);
525}