html_types/attributes/
value.rs1use derive_more::Display;
2use std::borrow::Cow;
3
4#[derive(Debug, PartialEq, Eq)]
5pub struct InvalidValueError {}
6
7#[derive(Clone, Debug, PartialEq, Eq, Display)]
8pub struct Value<'a>(Cow<'a, str>);
9
10macro_rules! value {
11 ($name:ident $tag:expr) => {
12 pub const $name: Value<'static> = Value(Cow::Borrowed($tag));
13 };
14}
15
16impl<'a> Value<'a> {
17 pub fn is_valid(str: &str) -> bool {
21 let allowed = |c: char| -> bool {
22 char::is_alphabetic(c)
23 || c == ':'
24 || c == '/'
25 || c == '.'
26 || char::is_whitespace(c)
27 || c == '-'
28 };
29 str.chars().all(allowed)
30 }
31
32 pub fn create(str: &'a str) -> Result<Value<'a>, InvalidValueError> {
33 match Self::is_valid(str) {
34 true => Ok(Value(Cow::Borrowed(str))),
35 false => Err(InvalidValueError {}),
36 }
37 }
38
39 pub fn owned<S>(str: S) -> Result<Value<'a>, InvalidValueError>
40 where
41 S: Into<String>,
42 {
43 let str = str.into();
44 let valid = Self::is_valid(&str);
45 match valid {
46 true => Ok(Value(Cow::Owned(str))),
47 false => Err(InvalidValueError {}),
48 }
49 }
50
51 value!(TEXT_CSS "text/css");
55 value!(STYLESHEET "stylesheet");
56 value!(UTF_8 "UTF-8");
57 value!(EN "en");
58}
59
60#[cfg(test)]
61mod tests {
62 use super::*;
63
64 #[test]
65 fn url_is_valid() {
66 let url = "http://google.com";
67 let node = Value::create(url);
68 let expected = Result::Ok(Value(Cow::Borrowed(url)));
69 assert_eq!(node, expected);
70 }
71
72 #[test]
73 fn namespacing_is_valid() {
74 let id = "test-id";
75 let node = Value::create(id);
76 let expected = Result::Ok(Value(Cow::Borrowed(id)));
77 assert_eq!(node, expected);
78 }
79}