1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
use self::errors::*;
use crate::DmntkError;
use std::convert::TryFrom;
use uriparse::{RelativeReference, URI};
pub type OptHRef = Option<HRef>;
#[derive(Debug, Clone)]
pub struct HRef(String);
impl<'a> From<&'a HRef> for &'a str {
fn from(value: &'a HRef) -> Self {
&value.0
}
}
impl<'a> From<&'a HRef> for String {
fn from(value: &'a HRef) -> Self {
value.0.clone()
}
}
impl TryFrom<&str> for HRef {
type Error = DmntkError;
fn try_from(value: &str) -> Result<Self, Self::Error> {
if let Ok(relative_reference) = RelativeReference::try_from(value) {
let s = relative_reference.to_string();
return Ok(Self(if s.starts_with('#') { s.strip_prefix('#').unwrap().to_string() } else { s }));
}
if let Ok(uri) = URI::try_from(value) {
return Ok(Self(uri.to_string()));
}
Err(invalid_reference(value))
}
}
mod errors {
use crate::DmntkError;
#[derive(Debug, PartialEq)]
pub enum HRefError {
InvalidReference(String),
}
impl From<HRefError> for DmntkError {
fn from(e: HRefError) -> Self {
DmntkError::new("HRefError", &e.to_string())
}
}
impl std::fmt::Display for HRefError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
HRefError::InvalidReference(s) => write!(f, "invalid reference): `{}`", s),
}
}
}
pub fn invalid_reference(s: &str) -> DmntkError {
HRefError::InvalidReference(s.to_owned()).into()
}
}
#[cfg(test)]
mod tests {
use crate::HRef;
use std::convert::TryFrom;
fn assert_href(expected: &str, uri: &str) {
let href = &HRef::try_from(uri).unwrap();
let actual: &str = href.into();
assert_eq!(expected, actual);
}
#[test]
fn valid_references() {
assert_href("", "");
assert_href("ref", "#ref");
assert_href(":alfa", ":alfa");
assert_href("//beta/gamma", "//beta/gamma");
assert_href("ee412cf7-4dc9-4555-ab90-61907cb5b10e", "#ee412cf7-4dc9-4555-ab90-61907cb5b10e");
assert_href("_82032dc2-36a7-4477-9392-9921353c4b44", "#_82032dc2-36a7-4477-9392-9921353c4b44");
assert_href("https://dmntk.io/examples/example1#model2", "https://dmntk.io/examples/example1#model2");
}
#[test]
fn invalid_references() {
assert!(HRef::try_from("##").is_err());
}
#[test]
fn href_into_str() {
let href = &HRef::try_from("#_c03e81bf-a53d-47c5-9135-189935765fdc").unwrap();
let actual: &str = href.into();
assert_eq!("_c03e81bf-a53d-47c5-9135-189935765fdc", actual);
}
#[test]
fn href_into_string() {
let href = &HRef::try_from("#_c03e81bf-a53d-47c5-9135-189935765fdc").unwrap();
let actual: String = href.into();
assert_eq!("_c03e81bf-a53d-47c5-9135-189935765fdc".to_string(), actual);
}
}