1use crate::{BytesRef, DecodeValue, EncodeValue, Error, Header, Length, Reader, Result, Writer};
5use core::str;
6
7#[derive(Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
9#[repr(transparent)]
10pub struct StringRef(str);
11
12impl StringRef {
13 pub const fn new(s: &str) -> Result<&Self> {
16 match Length::new_usize(s.len()) {
17 Ok(_) => Ok(Self::new_unchecked(s)),
18 Err(err) => Err(err),
19 }
20 }
21
22 pub(crate) const fn new_unchecked(s: &str) -> &Self {
24 #[allow(unsafe_code)]
26 unsafe {
27 &*(core::ptr::from_ref::<str>(s) as *const Self)
28 }
29 }
30
31 pub fn from_bytes(bytes: &[u8]) -> Result<&Self> {
33 Self::new(str::from_utf8(bytes)?)
34 }
35
36 pub fn as_str(&self) -> &str {
38 &self.0
39 }
40
41 pub fn as_bytes(&self) -> &[u8] {
43 self.0.as_bytes()
44 }
45
46 pub fn len(&self) -> Length {
48 debug_assert!(u32::try_from(self.0.len()).is_ok());
49
50 #[allow(clippy::cast_possible_truncation)] Length::new(self.0.len() as u32)
52 }
53
54 pub fn is_empty(&self) -> bool {
56 self.0.is_empty()
57 }
58}
59
60impl AsRef<str> for StringRef {
61 fn as_ref(&self) -> &str {
62 self.as_str()
63 }
64}
65
66impl AsRef<[u8]> for StringRef {
67 fn as_ref(&self) -> &[u8] {
68 self.as_bytes()
69 }
70}
71
72impl AsRef<BytesRef> for StringRef {
73 fn as_ref(&self) -> &BytesRef {
74 BytesRef::new_unchecked(self.as_bytes())
75 }
76}
77
78impl<'a> DecodeValue<'a> for &'a StringRef {
79 type Error = Error;
80
81 fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
82 StringRef::from_bytes(<&'a BytesRef>::decode_value(reader, header)?.as_slice())
83 }
84}
85
86impl EncodeValue for StringRef {
87 fn value_len(&self) -> Result<Length> {
88 Ok(self.len())
89 }
90
91 fn encode_value(&self, writer: &mut impl Writer) -> Result<()> {
92 writer.write(self.as_ref())
93 }
94}
95
96#[cfg(feature = "alloc")]
97pub(crate) mod allocating {
98 use super::StringRef;
99 use crate::{
100 BytesRef, DecodeValue, EncodeValue, Error, Header, Length, Reader, Result, Writer,
101 };
102 use alloc::{borrow::ToOwned, string::String};
103 use core::{borrow::Borrow, ops::Deref, str};
104
105 #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
107 pub struct StringOwned {
108 pub(crate) inner: String,
110
111 pub(crate) length: Length,
113 }
114
115 impl StringOwned {
116 pub fn new(s: String) -> Result<Self> {
119 let length = Length::try_from(s.len())?;
120
121 Ok(Self { inner: s, length })
122 }
123
124 pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
126 Ok(Self {
127 inner: String::from_utf8(bytes.to_vec())?,
128 length: Length::try_from(bytes.len())?,
129 })
130 }
131
132 pub fn as_str(&self) -> &str {
134 &self.inner
135 }
136
137 pub fn as_bytes(&self) -> &[u8] {
139 self.inner.as_bytes()
140 }
141
142 pub fn len(&self) -> Length {
144 self.length
145 }
146
147 pub fn is_empty(&self) -> bool {
149 self.len() == Length::ZERO
150 }
151 }
152
153 impl AsRef<str> for StringOwned {
154 fn as_ref(&self) -> &str {
155 self.as_str()
156 }
157 }
158
159 impl AsRef<[u8]> for StringOwned {
160 fn as_ref(&self) -> &[u8] {
161 self.as_bytes()
162 }
163 }
164
165 impl AsRef<BytesRef> for StringOwned {
166 fn as_ref(&self) -> &BytesRef {
167 BytesRef::new_unchecked(self.as_bytes())
168 }
169 }
170
171 impl AsRef<StringRef> for StringOwned {
172 fn as_ref(&self) -> &StringRef {
173 StringRef::new_unchecked(&self.inner)
174 }
175 }
176
177 impl Borrow<StringRef> for StringOwned {
178 fn borrow(&self) -> &StringRef {
179 StringRef::new_unchecked(&self.inner)
180 }
181 }
182
183 impl Deref for StringOwned {
184 type Target = StringRef;
185
186 fn deref(&self) -> &StringRef {
187 self.borrow()
188 }
189 }
190
191 impl<'a> DecodeValue<'a> for StringOwned {
192 type Error = Error;
193
194 fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
195 Self::from_bytes(<&'a BytesRef>::decode_value(reader, header)?.as_slice())
196 }
197 }
198
199 impl EncodeValue for StringOwned {
200 fn value_len(&self) -> Result<Length> {
201 Ok(self.length)
202 }
203
204 fn encode_value(&self, writer: &mut impl Writer) -> Result<()> {
205 writer.write(self.as_ref())
206 }
207 }
208
209 impl ToOwned for StringRef {
210 type Owned = StringOwned;
211
212 fn to_owned(&self) -> StringOwned {
213 StringOwned {
214 inner: self.as_str().into(),
215 length: self.len(),
216 }
217 }
218 }
219}