xsd_types/value/string/
token.rs1use core::fmt;
2use std::{borrow::Borrow, ops::Deref, str::FromStr};
3
4use crate::ParseXsd;
5
6#[derive(Debug, thiserror::Error)]
7#[error("invalid token `{0}`")]
8pub struct InvalidToken<T = String>(pub T);
9
10#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
11#[repr(transparent)]
12pub struct Token(str);
13
14impl Token {
15 pub fn new(value: &str) -> Result<&Self, InvalidToken<&str>> {
16 if Self::validate(value) {
17 Ok(unsafe { Self::new_unchecked(value) })
18 } else {
19 Err(InvalidToken(value))
20 }
21 }
22
23 fn validate(value: &str) -> bool {
24 let mut leading = true;
25 let mut space = false;
26
27 for c in value.chars() {
28 if c == ' ' {
29 if space {
30 return false;
31 }
32
33 space = true
34 } else {
35 space = false
36 }
37
38 if matches!(c, '\t' | '\n' | '\r') || (space && leading) {
39 return false;
40 }
41
42 leading = false;
43 }
44
45 !space
46 }
47
48 pub unsafe fn new_unchecked(value: &str) -> &Self {
54 std::mem::transmute(value)
55 }
56
57 pub fn as_str(&self) -> &str {
58 &self.0
59 }
60}
61
62impl fmt::Display for Token {
63 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64 self.0.fmt(f)
65 }
66}
67
68impl ToOwned for Token {
69 type Owned = TokenBuf;
70
71 fn to_owned(&self) -> Self::Owned {
72 TokenBuf(self.0.to_owned())
73 }
74}
75
76#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
77pub struct TokenBuf(String);
78
79impl TokenBuf {
80 pub fn new(value: String) -> Result<Self, InvalidToken> {
81 if Token::validate(&value) {
82 Ok(Self(value))
83 } else {
84 Err(InvalidToken(value))
85 }
86 }
87
88 pub unsafe fn new_unchecked(value: String) -> Self {
94 Self(value)
95 }
96
97 pub fn as_token(&self) -> &Token {
98 unsafe { Token::new_unchecked(self.0.as_str()) }
99 }
100
101 pub fn into_string(self) -> String {
102 self.0
103 }
104}
105
106impl fmt::Display for TokenBuf {
107 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
108 self.0.fmt(f)
109 }
110}
111
112impl Borrow<Token> for TokenBuf {
113 fn borrow(&self) -> &Token {
114 self.as_token()
115 }
116}
117
118impl Deref for TokenBuf {
119 type Target = Token;
120
121 fn deref(&self) -> &Self::Target {
122 self.as_token()
123 }
124}
125
126impl FromStr for TokenBuf {
127 type Err = InvalidToken;
128
129 fn from_str(s: &str) -> Result<Self, Self::Err> {
130 Self::new(s.to_owned())
131 }
132}
133
134impl ParseXsd for TokenBuf {
135 type LexicalForm = crate::lexical::Token;
136}