1use core::{fmt, mem};
3
4use alloc::vec::Vec;
5
6pub const STATIC_SIZE: usize = mem::size_of::<usize>() * 2;
8
9#[derive(Clone)]
10enum State<'a> {
11 Slice(&'a [u8]),
13 Static([u8; STATIC_SIZE]),
15 Heap(Vec<u8>),
17}
18
19const _: () = {
20 assert!(mem::size_of::<State>() == 24);
21};
22
23#[repr(transparent)]
24#[derive(Clone)]
25pub struct String<'a> {
27 state: State<'a>
28}
29
30impl<'a> String<'a> {
31 #[inline]
32 pub const fn try_new_c(string: &'a [u8]) -> Option<Self> {
36 if string[string.len() - 1] == 0 {
37 Some(Self {
38 state: State::Slice(string)
39 })
40 } else {
41 None
42 }
43 }
44
45 #[inline]
46 pub const fn new_c(string: &'a [u8]) -> Self {
50 if string[string.len() - 1] == 0 {
51 Self {
52 state: State::Slice(string)
53 }
54 } else {
55 panic!("string is not NULL terminated")
56 }
57 }
58
59 pub fn new(string: &'a [u8]) -> Self {
64 let state = if let Some(this) = Self::try_new_c(string) {
65 this.state
66 } else if string.len() < STATIC_SIZE {
67 let mut buffer = [0u8; STATIC_SIZE];
68 buffer[..string.len()].copy_from_slice(string);
69 buffer[string.len()] = 0;
70 State::Static(buffer)
71 } else {
72 let mut buffer = Vec::with_capacity(string.len().saturating_add(1));
73 buffer.extend_from_slice(string);
74 buffer.push(0);
75 State::Heap(buffer)
76 };
77
78 Self {
79 state
80 }
81 }
82
83 pub fn as_ptr(&self) -> *const u8 {
85 match &self.state {
86 State::Heap(buf) => buf.as_ptr(),
87 State::Static(buf) => buf.as_ptr() as _,
88 State::Slice(buf) => buf.as_ptr(),
89 }
90 }
91
92 pub fn as_bytes(&self) -> &[u8] {
94 match &self.state {
95 State::Heap(buf) => &buf[..buf.len()-1],
96 State::Static(buf) => {
97 let mut cursor = 0;
98 while cursor < STATIC_SIZE {
99 if buf[cursor] == 0 {
100 break;
101 }
102 cursor = cursor.saturating_add(1);
103 }
104 &buf[..cursor]
105 },
106 State::Slice(buf) => &buf[..buf.len()-1],
107 }
108 }
109}
110
111impl fmt::Debug for String<'_> {
112 #[inline]
113 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
114 fmt::Debug::fmt(self.as_bytes(), fmt)
115 }
116}
117
118impl PartialEq<[u8]> for String<'_> {
119 #[inline(always)]
120 fn eq(&self, other: &[u8]) -> bool {
121 PartialEq::eq(self.as_bytes(), other)
122 }
123}
124
125impl PartialEq<&[u8]> for String<'_> {
126 #[inline(always)]
127 fn eq(&self, other: &&[u8]) -> bool {
128 PartialEq::eq(self.as_bytes(), *other)
129 }
130}
131
132impl PartialEq<str> for String<'_> {
133 #[inline(always)]
134 fn eq(&self, other: &str) -> bool {
135 PartialEq::eq(self.as_bytes(), other.as_bytes())
136 }
137}
138
139impl<'a> From<&'a [u8]> for String<'a> {
140 #[inline]
141 fn from(value: &'a [u8]) -> Self {
142 Self::new(value)
143 }
144}
145
146impl<'a> From<&'a str> for String<'a> {
147 #[inline]
148 fn from(value: &'a str) -> Self {
149 Self::new(value.as_bytes())
150 }
151}