asciidoc_parser/
strings.rs1use std::{
26 borrow::{Borrow, Cow},
27 fmt,
28 hash::{Hash, Hasher},
29 ops::Deref,
30 str::from_utf8,
31};
32
33pub(crate) const MAX_INLINE_STR_LEN: usize = 3 * std::mem::size_of::<isize>() - 2;
34
35#[derive(Debug)]
38pub struct StringTooLongError;
39
40#[derive(Debug, Clone, Copy, Eq)]
43pub struct InlineStr {
44 inner: [u8; MAX_INLINE_STR_LEN],
45 len: u8,
46}
47
48impl AsRef<str> for InlineStr {
49 fn as_ref(&self) -> &str {
50 self.deref()
51 }
52}
53
54impl Hash for InlineStr {
55 fn hash<H: Hasher>(&self, state: &mut H) {
56 self.deref().hash(state);
57 }
58}
59
60impl From<char> for InlineStr {
61 fn from(c: char) -> Self {
62 let mut inner = [0u8; MAX_INLINE_STR_LEN];
63 c.encode_utf8(&mut inner);
64 let len = c.len_utf8() as u8;
65 Self { inner, len }
66 }
67}
68
69impl std::cmp::PartialEq<InlineStr> for InlineStr {
70 fn eq(&self, other: &InlineStr) -> bool {
71 self.deref() == other.deref()
72 }
73}
74
75impl TryFrom<&str> for InlineStr {
76 type Error = StringTooLongError;
77
78 fn try_from(s: &str) -> Result<InlineStr, StringTooLongError> {
79 let len = s.len();
80 if len <= MAX_INLINE_STR_LEN {
81 let mut inner = [0u8; MAX_INLINE_STR_LEN];
82 inner[..len].copy_from_slice(s.as_bytes());
83 let len = len as u8;
84 Ok(Self { inner, len })
85 } else {
86 Err(StringTooLongError)
87 }
88 }
89}
90
91impl Deref for InlineStr {
92 type Target = str;
93
94 fn deref(&self) -> &str {
95 let len = self.len as usize;
96 from_utf8(&self.inner[..len]).unwrap_or_default()
97 }
98}
99
100impl fmt::Display for InlineStr {
101 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102 write!(f, "{}", self.as_ref())
103 }
104}
105
106#[derive(Debug, Eq)]
111pub enum CowStr<'a> {
112 Boxed(Box<str>),
114 Borrowed(&'a str),
116 Inlined(InlineStr),
118}
119
120impl AsRef<str> for CowStr<'_> {
121 fn as_ref(&self) -> &str {
122 self.deref()
123 }
124}
125
126impl Hash for CowStr<'_> {
127 fn hash<H: Hasher>(&self, state: &mut H) {
128 self.deref().hash(state);
129 }
130}
131
132impl std::clone::Clone for CowStr<'_> {
133 fn clone(&self) -> Self {
134 match self {
135 CowStr::Boxed(s) => match InlineStr::try_from(&**s) {
136 Ok(inline) => CowStr::Inlined(inline),
137 Err(..) => CowStr::Boxed(s.clone()),
138 },
139 CowStr::Borrowed(s) => CowStr::Borrowed(s),
140 CowStr::Inlined(s) => CowStr::Inlined(*s),
141 }
142 }
143}
144
145impl<'a> std::cmp::PartialEq<CowStr<'a>> for CowStr<'a> {
146 fn eq(&self, other: &CowStr<'_>) -> bool {
147 self.deref() == other.deref()
148 }
149}
150
151impl<'a> From<&'a str> for CowStr<'a> {
152 fn from(s: &'a str) -> Self {
153 CowStr::Borrowed(s)
154 }
155}
156
157impl From<String> for CowStr<'_> {
158 fn from(s: String) -> Self {
159 CowStr::Boxed(s.into_boxed_str())
160 }
161}
162
163impl From<char> for CowStr<'_> {
164 fn from(c: char) -> Self {
165 CowStr::Inlined(c.into())
166 }
167}
168
169impl<'a> From<Cow<'a, str>> for CowStr<'a> {
170 fn from(s: Cow<'a, str>) -> Self {
171 match s {
172 Cow::Borrowed(s) => CowStr::Borrowed(s),
173 Cow::Owned(s) => CowStr::Boxed(s.into_boxed_str()),
174 }
175 }
176}
177
178impl<'a> From<CowStr<'a>> for Cow<'a, str> {
179 fn from(s: CowStr<'a>) -> Self {
180 match s {
181 CowStr::Boxed(s) => Cow::Owned(s.to_string()),
182 CowStr::Inlined(s) => Cow::Owned(s.to_string()),
183 CowStr::Borrowed(s) => Cow::Borrowed(s),
184 }
185 }
186}
187
188impl<'a> From<Cow<'a, char>> for CowStr<'a> {
189 fn from(s: Cow<'a, char>) -> Self {
190 CowStr::Inlined(InlineStr::from(*s))
191 }
192}
193
194impl Deref for CowStr<'_> {
195 type Target = str;
196
197 fn deref(&self) -> &str {
198 match self {
199 CowStr::Boxed(ref b) => b,
200 CowStr::Borrowed(b) => b,
201 CowStr::Inlined(ref s) => s.deref(),
202 }
203 }
204}
205
206impl Borrow<str> for CowStr<'_> {
207 fn borrow(&self) -> &str {
208 self.deref()
209 }
210}
211
212impl CowStr<'_> {
213 pub fn into_string(self) -> String {
215 match self {
216 CowStr::Boxed(b) => b.into(),
217 CowStr::Borrowed(b) => b.to_owned(),
218 CowStr::Inlined(s) => s.deref().to_owned(),
219 }
220 }
221}
222
223impl fmt::Display for CowStr<'_> {
224 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
225 write!(f, "{}", self.as_ref())
226 }
227}