1#![no_std]
50
51#![cfg_attr(feature = "use-nightly-features", feature(extend_one))]
52
53use core::fmt::{self, Display};
54use core::ops::{Deref, DerefMut};
55use core::str::{self, FromStr, Utf8Error};
56
57extern crate alloc;
58use alloc::vec::Vec;
59use alloc::boxed::Box;
60
61use tiny_vec::TinyVec;
62pub mod iter;
63
64pub mod drain;
65
66const MAX_N_STACK_ELEMENTS: usize = tiny_vec::n_elements_for_stack::<u8>();
67
68pub struct TinyString<const N: usize = MAX_N_STACK_ELEMENTS>(TinyVec<u8, N>);
70
71impl<const N: usize> TinyString<N> {
72
73 #[inline]
75 pub const fn new() -> Self {
76 Self(TinyVec::new())
77 }
78
79 pub fn with_capacity(cap: usize) -> Self {
81 Self(TinyVec::with_capacity(cap))
82 }
83
84 pub fn from_utf8(utf8: TinyVec<u8, N>) -> Result<Self,Utf8Error> {
89 str::from_utf8(utf8.as_slice())?;
90 Ok(Self(utf8))
91 }
92
93 #[inline(always)]
98 pub const unsafe fn from_utf8_unchecked(utf8: TinyVec<u8, N>) -> Self {
99 Self(utf8)
100 }
101
102 #[inline]
104 pub const fn len(&self) -> usize { self.0.len() }
105
106 #[inline]
108 pub const fn is_empty(&self) -> bool { self.0.is_empty() }
109
110 #[inline]
112 pub const fn capacity(&self) -> usize { self.0.capacity() }
113
114 #[inline]
116 pub const fn as_str(&self) -> &str {
117 unsafe { str::from_utf8_unchecked(self.0.as_slice()) }
118 }
119
120 #[inline]
122 pub const fn as_mut_str(&mut self) -> &mut str {
123 unsafe { str::from_utf8_unchecked_mut(self.0.as_mut_slice()) }
124 }
125
126 #[inline]
130 pub const fn as_ptr(&self) -> *const u8 {
131 self.0.as_ptr()
132 }
133
134 #[inline]
138 pub const fn as_mut_ptr(&mut self) -> *mut u8 {
139 self.0.as_mut_ptr()
140 }
141
142 #[inline]
144 pub const fn as_bytes(&self) -> &[u8] {
145 self.0.as_slice()
146 }
147
148 pub fn push(&mut self, c: char) {
150 let len = c.len_utf8();
151 if len == 1 {
152 self.0.push(c as u8);
153 } else {
154 let mut buf = [0_u8; 4];
155 c.encode_utf8(&mut buf);
156 self.0.extend_from_slice(&buf[..len]);
157 }
158 }
159
160 pub fn pop(&mut self) -> Option<char> {
174 let c = self.chars().next_back()?;
175 let new_len = self.len() - c.len_utf8();
176 unsafe {
177 self.0.set_len(new_len);
178 }
179 Some(c)
180 }
181
182 #[inline]
184 pub fn push_str(&mut self, s: &str) {
185 self.0.extend_from_slice_copied(s.as_bytes());
186 }
187
188 #[inline]
190 pub fn shrink_to_fit(&mut self) {
191 self.0.shrink_to_fit();
192 }
193
194 #[inline]
207 pub fn clear(&mut self) {
208 self.0.clear();
209 }
210
211 #[inline]
213 pub fn reserve(&mut self, n: usize) {
214 self.0.reserve(n);
215 }
216
217 #[inline]
219 pub fn reserve_exact(&mut self, n: usize) {
220 self.0.reserve_exact(n);
221 }
222
223 pub fn into_boxed_str(self) -> Box<str> {
236 let b = self.0.into_boxed_slice();
237 unsafe { alloc::str::from_boxed_utf8_unchecked(b) }
238 }
239}
240
241impl<const N: usize> Default for TinyString<N> {
242 fn default() -> Self {
243 Self::new()
244 }
245}
246
247impl<const N: usize> Deref for TinyString<N> {
248 type Target = str;
249
250 fn deref(&self) -> &Self::Target {
251 self.as_str()
252 }
253}
254
255impl<const N: usize> DerefMut for TinyString<N> {
256 fn deref_mut(&mut self) -> &mut Self::Target {
257 self.as_mut_str()
258 }
259}
260
261impl<const N: usize> From<&str> for TinyString<N> {
262 fn from(value: &str) -> Self {
263 let mut s = Self::with_capacity(value.len());
264 s.push_str(value);
265 s
266 }
267}
268
269impl<const N: usize> TryFrom<&[u8]> for TinyString<N> {
270 type Error = Utf8Error;
271
272 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
273 str::from_utf8(value)?;
274 Ok(unsafe { Self::from_utf8_unchecked(TinyVec::from_slice_copied(value)) })
275 }
276}
277
278impl<const N: usize> TryFrom<TinyVec<u8, N>> for TinyString<N> {
279 type Error = Utf8Error;
280
281 fn try_from(value: TinyVec<u8, N>) -> Result<Self, Self::Error> {
282 Self::from_utf8(value)
283 }
284}
285
286impl<const N: usize> TryFrom<Vec<u8>> for TinyString<N> {
287 type Error = Utf8Error;
288
289 fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
290 str::from_utf8(value.as_slice())?;
291 Ok(unsafe { Self::from_utf8_unchecked(TinyVec::from_vec(value)) })
292 }
293}
294
295impl<const N: usize> From<TinyString<N>> for TinyVec<u8, N> {
296 fn from(value: TinyString<N>) -> Self {
297 value.0
298 }
299}
300
301impl<const N: usize> From<TinyString<N>> for Vec<u8> {
302 fn from(value: TinyString<N>) -> Self {
303 value.0.into_vec()
304 }
305}
306
307impl<const N: usize> From<TinyString<N>> for Box<str> {
308 fn from(value: TinyString<N>) -> Self {
309 value.into_boxed_str()
310 }
311}
312
313impl<const N: usize> FromIterator<char> for TinyString<N> {
314 fn from_iter<T: IntoIterator<Item = char>>(iter: T) -> Self {
315 let mut s = Self::new();
316 s.extend(iter);
317 s
318 }
319}
320
321impl<const N: usize> Extend<char> for TinyString<N> {
322 fn extend<T: IntoIterator<Item = char>>(&mut self, iter: T) {
323 let iter = iter.into_iter();
324 let cap = match iter.size_hint() {
325 (_, Some(n)) => n,
326 (n, _) => n,
327 };
328 self.reserve(cap);
329 for c in iter {
330 self.push(c);
331 }
332 }
333
334 #[cfg(feature = "use-nightly-features")]
335 fn extend_one(&mut self, item: char) {
336 self.push(item);
337 }
338}
339
340impl<const N: usize, S> PartialEq<S> for TinyString<N>
341where
342 S: AsRef<[u8]>
343{
344 fn eq(&self, other: &S) -> bool {
345 self.as_bytes() == other.as_ref()
346 }
347}
348
349impl<const N: usize> Eq for TinyString<N> { }
350
351impl<const N: usize> AsRef<[u8]> for TinyString<N> {
352 fn as_ref(&self) -> &[u8] {
353 self.as_bytes()
354 }
355}
356
357impl<const N: usize> AsRef<str> for TinyString<N> {
358 fn as_ref(&self) -> &str {
359 self.as_str()
360 }
361}
362
363impl<const N: usize> AsMut<str> for TinyString<N> {
364 fn as_mut(&mut self) -> &mut str {
365 self.as_mut_str()
366 }
367}
368
369impl<const N: usize> fmt::Debug for TinyString<N> {
370 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
371 write!(f, "{:?}", self.bytes())
372 }
373}
374
375impl<const N: usize> Display for TinyString<N> {
376 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
377 write!(f, "{}", self.as_str())
378 }
379}
380
381impl<const N: usize> FromStr for TinyString<N> {
382 type Err = core::convert::Infallible;
383
384 fn from_str(s: &str) -> Result<Self, Self::Err> {
385 Ok(Self::from(s))
386 }
387}
388
389#[cfg(test)]
390mod test;