1use crate::{Error, Result};
2use core::{
3 fmt,
4 ops::Deref,
5 str::{self, FromStr},
6};
7
8#[derive(Clone, Copy, Eq, Hash, PartialEq, PartialOrd, Ord)]
10pub(super) struct StringBuf<const N: usize> {
11 pub(super) length: u8,
13
14 pub(super) bytes: [u8; N],
16}
17
18impl<const N: usize> StringBuf<N> {
19 pub(super) const fn new(s: &str) -> Result<Self> {
21 if s.len() > N || s.len() > u8::MAX as usize {
22 return Err(Error::ValueTooLong);
23 }
24
25 let mut bytes = [0u8; N];
26 let mut i = 0;
27
28 while i < s.len() {
29 bytes[i] = s.as_bytes()[i];
30 i += 1;
31 }
32
33 Ok(Self {
34 bytes,
35 length: s.len() as u8,
36 })
37 }
38}
39
40impl<const N: usize> AsRef<str> for StringBuf<N> {
41 fn as_ref(&self) -> &str {
42 str::from_utf8(&self.bytes[..(self.length as usize)]).expect("should be valid UTF-8")
43 }
44}
45
46impl<const N: usize> Default for StringBuf<N> {
47 fn default() -> Self {
48 StringBuf {
49 bytes: [0u8; N],
50 length: 0,
51 }
52 }
53}
54
55impl<const N: usize> Deref for StringBuf<N> {
56 type Target = str;
57
58 fn deref(&self) -> &str {
59 self.as_ref()
60 }
61}
62
63impl<const N: usize> FromStr for StringBuf<N> {
64 type Err = Error;
65
66 fn from_str(s: &str) -> Result<Self> {
67 Self::new(s)
68 }
69}
70
71impl<const N: usize> TryFrom<&str> for StringBuf<N> {
72 type Error = Error;
73
74 fn try_from(s: &str) -> Result<Self> {
75 Self::new(s)
76 }
77}
78
79impl<const N: usize> fmt::Debug for StringBuf<N> {
80 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81 f.write_str(self.as_ref())
82 }
83}
84
85impl<const N: usize> fmt::Display for StringBuf<N> {
86 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87 f.write_str(self.as_ref())
88 }
89}
90
91impl<const N: usize> fmt::Write for StringBuf<N> {
92 fn write_str(&mut self, input: &str) -> fmt::Result {
93 const { debug_assert!(N <= u8::MAX as usize) }
94
95 let bytes = input.as_bytes();
96 let length = self.length as usize;
97 let new_length = length.checked_add(bytes.len()).ok_or(fmt::Error)?;
98
99 if new_length > N {
100 return Err(fmt::Error);
101 }
102
103 self.bytes[length..new_length].copy_from_slice(bytes);
104 self.length = new_length.try_into().map_err(|_| fmt::Error)?;
105
106 Ok(())
107 }
108}