1#![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>; }
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>; }
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<'_> {}
238impl 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}