1use {
2 crate::{DataType, Literal},
3 std::str::FromStr,
4};
5
6#[derive(Debug)]
10pub enum Term {
11 Iri(Literal),
12 Literal(Literal),
13 BlankNode(Literal),
14}
15
16const ACCEPTABLE_IRI_PROTOCOLS: [&str; 3] = ["http://", "https://", "s3://"];
17
18impl Term {
19 pub fn from_static(iri_str: &'static str) -> Result<Self, ekg_error::Error> {
20 Self::new_iri_from_str(iri_str)
21 }
22
23 pub fn new_iri(iri: &fluent_uri::Uri<&str>) -> Result<Self, ekg_error::Error> {
24 for acceptable_protocol in ACCEPTABLE_IRI_PROTOCOLS.iter() {
25 if iri.as_str().starts_with(acceptable_protocol) {
26 return Ok(Term::Iri(Literal::from_iri(iri)?));
27 }
28 }
29 Err(ekg_error::Error::InvalidIri(
30 iri.as_str().to_string(),
31 ))
32 }
33
34 pub fn new_iri_from_str(iri_str: &str) -> Result<Self, ekg_error::Error> {
35 Term::new_iri(&fluent_uri::Uri::parse(iri_str)?)
36 }
37
38 pub fn new_str(str: &str) -> Result<Self, ekg_error::Error> {
39 Ok(Term::Literal(Literal::from_str(str)?))
40 }
41
42 pub fn new_blank_node(str: &str) -> Result<Self, ekg_error::Error> {
43 Ok(Term::BlankNode(
44 Literal::from_type_and_buffer(DataType::BlankNode, str, None)?.unwrap(),
45 ))
46 }
47
48 pub fn display_turtle<'a, 'b>(&'a self) -> impl std::fmt::Display + 'a + 'b
59 where 'a: 'b {
60 struct TurtleTerm<'b>(&'b Term);
61 impl<'b> std::fmt::Display for TurtleTerm<'b> {
62 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
63 let value = match self.0 {
64 Term::Iri(value) => value,
65 Term::Literal(value) => value,
66 Term::BlankNode(value) => value,
67 };
68 value.display_turtle().fmt(f)
69 }
70 }
71 TurtleTerm(self)
72 }
73}
74
75impl FromStr for Term {
76 type Err = ekg_error::Error;
77
78 fn from_str(str: &str) -> Result<Self, Self::Err> { Term::new_str(str) }
79}
80
81impl From<Literal> for Term {
82 fn from(value: Literal) -> Self { value.as_term() }
83}
84
85#[cfg(test)]
86mod tests {
87 #[test_log::test]
88 fn test_term_01() {
89 let uri = fluent_uri::Uri::parse("https://whatever.url/").unwrap();
90 assert_eq!(uri.to_string(), "https://whatever.url/");
91 assert_eq!(uri.path().as_str(), "/");
92 let term = crate::Term::new_iri(&uri).unwrap();
93 let turtle = term.display_turtle().to_string();
94
95 assert_eq!(turtle, "<https://whatever.url/>");
96 }
97
98 #[test_log::test]
99 fn test_term_02() {
100 let term = crate::Term::new_iri(
101 &fluent_uri::Uri::parse("unknown-protocol://whatever.url").unwrap(),
102 );
103 assert!(term.is_err());
104 assert!(matches!(
105 term.unwrap_err(),
106 ekg_error::Error::InvalidIri(_)
107 ));
108 }
109
110 #[test_log::test]
111 fn test_term_03() {
112 let term = crate::Term::from_static("https:/x/whatever.url");
114 assert!(term.is_err());
115 assert!(matches!(
116 term.unwrap_err(),
117 ekg_error::Error::InvalidIri(_)
118 ));
119 }
120
121 #[test_log::test]
122 fn test_term_04() {
123 let term = crate::Term::new_str("some string").unwrap();
124
125 let turtle = format!("{}", term.display_turtle());
126
127 assert_eq!(turtle, "\"some string\"");
128 }
129
130 #[test_log::test]
131 fn test_term_05() -> Result<(), ekg_error::Error> {
132 let term: crate::Term = "some string".parse()?;
133
134 let turtle = format!("{}", term.display_turtle());
135
136 assert_eq!(turtle, "\"some string\"");
137
138 Ok(())
139 }
140
141 #[test_log::test]
142 fn test_term_06() -> Result<(), ekg_error::Error> {
143 let term: crate::Term = "\"some string\"^^xsd:string".parse()?;
144
145 let turtle = format!("{}", term.display_turtle());
146
147 assert_eq!(turtle, "\"\"some string\"^^xsd:string\""); Ok(())
150 }
151
152 #[test_log::test]
153 fn test_fluent_uri_01() -> Result<(), ekg_error::Error> {
154 let uri =
155 fluent_uri::Uri::parse("https://placeholder.kg/ontology/abc#xyz").map_err(|e| {
156 println!("{}", e);
157 ekg_error::Error::Unknown
158 })?;
159
160 assert_eq!(
161 uri.to_string().as_str(),
162 "https://placeholder.kg/ontology/abc#xyz"
163 );
164 Ok(())
165 }
166
167 #[test_log::test]
168 fn test_fluent_uri_02() -> Result<(), ekg_error::Error> {
169 let uri = fluent_uri::Uri::parse("https://placeholder.kg/ontology/abc#").map_err(|e| {
170 println!("{}", e);
171 ekg_error::Error::Unknown
172 })?;
173
174 assert_eq!(
175 uri.to_string().as_str(),
176 "https://placeholder.kg/ontology/abc#"
177 );
178 Ok(())
179 }
180
181 #[test_log::test]
182 fn test_fluent_uri_03() -> Result<(), ekg_error::Error> {
183 let uri = fluent_uri::Uri::parse("https://placeholder.kg/ontology/abc/").map_err(|e| {
184 println!("{}", e);
185 ekg_error::Error::Unknown
186 })?;
187
188 assert_eq!(
189 uri.to_string().as_str(),
190 "https://placeholder.kg/ontology/abc/"
191 );
192 Ok(())
193 }
194}