1#[repr(C)]
6#[derive(Clone, Copy)]
7pub struct FixedByteStr<const N: usize> {
8 pub raw: [u8; N],
9 pub len: usize,
10}
11
12impl<const N: usize> FixedByteStr<N> {
13 pub fn new() -> Self {
14 Self {
15 raw: [0; N],
16 len: 0,
17 }
18 }
19 pub fn from_str(s: &str) -> Self {
20 assert!(s.len() <= N, "String length exceeds maximum length");
21 let mut str = Self {
22 raw: [0; N],
23 len: s.len(),
24 };
25 str.raw[..s.len()].copy_from_slice(s.as_bytes());
26 str
27 }
28
29 pub fn as_str(&self) -> &str {
30 core::str::from_utf8(&self.raw[..self.len]).unwrap()
31 }
32
33 pub fn as_slice(&self) -> &[u8; N] {
34 &self.raw
35 }
36}
37
38impl<const N: usize> core::fmt::Debug for FixedByteStr<N> {
39 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
40 f.debug_tuple("FixedByteStr")
41 .field(&self.as_str())
42 .finish()
43 }
44}
45
46impl<const N: usize> core::fmt::Display for FixedByteStr<N> {
47 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
48 f.write_str(self.as_str())
49 }
50}
51
52impl<const N: usize> core::fmt::Write for FixedByteStr<N> {
53 fn write_str(&mut self, s: &str) -> core::fmt::Result {
54 let len = s.len();
55 let remaining = N.saturating_sub(self.len);
56
57 if len > remaining {
58 return Err(core::fmt::Error);
59 }
60
61 self.raw[self.len..self.len + len].copy_from_slice(s.as_bytes());
62
63 self.len += len;
64 Ok(())
65 }
66}
67
68#[cfg(test)]
69mod tests {
70 use super::*;
71 use std::fmt::Write;
72
73 #[test]
74 fn test_str() {
75 let mut str = FixedByteStr::<11>::new();
76 str.write_str("Hello World").unwrap();
77 assert_eq!(str.as_str(), "Hello World");
78 }
79
80 #[test]
81 fn test_from_str() {
82 let str = FixedByteStr::<11>::from_str("Hello World");
83 assert_eq!(str.as_str(), "Hello World");
84 }
85
86 #[test]
87 fn test_str_overflow() {
88 let mut str = FixedByteStr::<11>::new();
89 str.write_str("Hello World").unwrap();
90 assert!(str.write_str("Hello World").is_err());
91 }
92
93 #[test]
94 fn test_str_display() {
95 let str = FixedByteStr::<11>::from_str("Hello World");
96 assert_eq!(format!("{}", str), "Hello World");
97 }
98
99 #[test]
100 #[should_panic]
101 fn test_str_from_str_overflow() {
102 _ = FixedByteStr::<11>::from_str("Hello World!");
103 }
104}