1use self::errors::*;
9use crate::DsntkError;
10use uriparse::URIReference;
11
12#[derive(Debug, Clone)]
14pub struct HRef {
15 namespace: Option<String>,
17 id: String,
19}
20
21impl HRef {
22 pub fn namespace(&self) -> Option<&String> {
24 self.namespace.as_ref()
25 }
26
27 pub fn id(&self) -> &str {
29 &self.id
30 }
31}
32
33impl TryFrom<&str> for HRef {
34 type Error = DsntkError;
35
36 fn try_from(s: &str) -> Result<Self, Self::Error> {
38 match URIReference::try_from(s) {
39 Ok(mut uri_reference) => {
40 uri_reference.normalize();
41 let (scheme, authority, path, query, fragment) = uri_reference.into_parts();
42 if query.is_some() {
43 return Err(err_query_not_allowed(s));
44 }
45 if fragment.is_none() {
46 return Err(err_fragment_is_missing(s));
47 }
48 let id = fragment.unwrap().to_string();
49 let base_uri = URIReference::builder()
50 .with_scheme(scheme)
51 .with_authority(authority)
52 .with_path(path)
53 .build()
54 .unwrap() .to_string();
56 let namespace = if base_uri.is_empty() { None } else { Some(base_uri) };
57 Ok(Self { namespace, id })
58 }
59 Err(reason) => Err(err_invalid_reference(s, reason.to_string())),
60 }
61 }
62}
63
64mod errors {
65 use crate::{DsntkError, ToErrorMessage};
66
67 #[derive(ToErrorMessage)]
69 struct HRefError(String);
70
71 pub fn err_invalid_reference(s: &str, reason: String) -> DsntkError {
73 HRefError(format!("invalid reference '{s}', reason: {reason}")).into()
74 }
75
76 pub fn err_fragment_is_missing(s: &str) -> DsntkError {
78 HRefError(format!("fragment is missing in reference: '{s}'")).into()
79 }
80
81 pub fn err_query_not_allowed(s: &str) -> DsntkError {
83 HRefError(format!("query is not allowed in reference: '{s}'")).into()
84 }
85}