fidl_next_codec/wire/string/
required.rs1use core::fmt;
6use core::mem::MaybeUninit;
7use core::ops::Deref;
8use core::str::{from_utf8, from_utf8_unchecked};
9
10use munge::munge;
11
12use crate::{
13 Constrained, Decode, DecodeError, Decoder, Encode, EncodeError, Encoder, FromWire, FromWireRef,
14 IntoNatural, Slot, ValidationError, Wire, wire,
15};
16
17use std::string::String as StdString;
18
19#[repr(transparent)]
21pub struct String<'de> {
22 vec: wire::Vector<'de, u8>,
23}
24
25unsafe impl Wire for String<'static> {
28 type Narrowed<'de> = String<'de>;
29
30 #[inline]
31 fn zero_padding(out: &mut MaybeUninit<Self>) {
32 munge!(let Self { vec } = out);
33 wire::Vector::<u8>::zero_padding(vec);
34 }
35}
36
37impl String<'_> {
38 #[inline]
40 pub fn encode_present(out: &mut MaybeUninit<Self>, len: u64) {
41 munge!(let Self { vec } = out);
42 wire::Vector::encode_present(vec, len);
43 }
44
45 #[inline]
47 pub fn len(&self) -> usize {
48 self.vec.len()
49 }
50
51 #[inline]
53 pub fn is_empty(&self) -> bool {
54 self.len() == 0
55 }
56
57 #[inline]
59 pub fn as_str(&self) -> &str {
60 unsafe { from_utf8_unchecked(self.vec.as_slice()) }
62 }
63
64 fn validate_max_len(slot: Slot<'_, Self>, limit: u64) -> Result<(), ValidationError> {
66 munge!(let Self { vec } = slot);
67 match wire::Vector::validate_max_len(vec, limit) {
68 Ok(()) => Ok(()),
69 Err(ValidationError::VectorTooLong { count, limit }) => {
70 Err(ValidationError::StringTooLong { count, limit })
71 }
72 Err(e) => Err(e),
73 }
74 }
75}
76
77impl Constrained for String<'_> {
78 type Constraint = u64;
79
80 fn validate(slot: Slot<'_, Self>, constraint: u64) -> Result<(), ValidationError> {
81 Self::validate_max_len(slot, constraint)
82 }
83}
84
85impl Deref for String<'_> {
86 type Target = str;
87
88 #[inline]
89 fn deref(&self) -> &Self::Target {
90 self.as_str()
91 }
92}
93
94impl fmt::Debug for String<'_> {
95 #[inline]
96 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
97 self.as_str().fmt(f)
98 }
99}
100
101impl<U: ?Sized> PartialEq<&U> for String<'_>
102where
103 for<'de> String<'de>: PartialEq<U>,
104{
105 fn eq(&self, other: &&U) -> bool {
106 self == *other
107 }
108}
109
110impl PartialEq for String<'_> {
111 fn eq(&self, other: &Self) -> bool {
112 self.as_str() == other.as_str()
113 }
114}
115
116impl PartialEq<str> for String<'_> {
117 fn eq(&self, other: &str) -> bool {
118 self.as_str() == other
119 }
120}
121
122unsafe impl<'de, D: Decoder<'de> + ?Sized> Decode<D> for String<'de> {
126 #[inline]
127 fn decode(slot: Slot<'_, Self>, decoder: &mut D, constraint: u64) -> Result<(), DecodeError> {
128 munge!(let Self { mut vec } = slot);
129
130 match unsafe { wire::Vector::decode_raw(vec.as_mut(), decoder, constraint) } {
132 Ok(()) => (),
133 Err(DecodeError::Validation(ValidationError::VectorTooLong { count, limit })) => {
134 return Err(DecodeError::Validation(ValidationError::StringTooLong {
135 count,
136 limit,
137 }));
138 }
139 Err(e) => {
140 return Err(e);
141 }
142 };
143 let vec = unsafe { vec.deref_unchecked() };
145
146 if !vec.as_slice().is_ascii() {
148 let _ = from_utf8(vec.as_slice())?;
151 }
152
153 Ok(())
154 }
155}
156
157unsafe impl<E: Encoder + ?Sized> Encode<String<'static>, E> for StdString {
159 #[inline]
160 fn encode(
161 self,
162 encoder: &mut E,
163 out: &mut MaybeUninit<String<'static>>,
164 constraint: u64,
165 ) -> Result<(), EncodeError> {
166 self.as_str().encode(encoder, out, constraint)
167 }
168}
169
170unsafe impl<E: Encoder + ?Sized> Encode<String<'static>, E> for &StdString {
172 #[inline]
173 fn encode(
174 self,
175 encoder: &mut E,
176 out: &mut MaybeUninit<String<'static>>,
177 constraint: u64,
178 ) -> Result<(), EncodeError> {
179 self.as_str().encode(encoder, out, constraint)
180 }
181}
182
183unsafe impl<E: Encoder + ?Sized> Encode<String<'static>, E> for &str {
186 #[inline]
187 fn encode(
188 self,
189 encoder: &mut E,
190 out: &mut MaybeUninit<String<'static>>,
191 _constraint: u64,
192 ) -> Result<(), EncodeError> {
193 encoder.write(self.as_bytes());
194 String::encode_present(out, self.len() as u64);
195 Ok(())
196 }
197}
198
199impl FromWire<String<'_>> for StdString {
200 #[inline]
201 fn from_wire(wire: String<'_>) -> Self {
202 StdString::from_wire_ref(&wire)
203 }
204}
205
206impl IntoNatural for String<'_> {
207 type Natural = StdString;
208}
209
210impl FromWireRef<String<'_>> for StdString {
211 #[inline]
212 fn from_wire_ref(wire: &String<'_>) -> Self {
213 unsafe { StdString::from_utf8_unchecked(Vec::from_wire_ref(&wire.vec)) }
215 }
216}
217
218#[cfg(test)]
219mod tests {
220 use crate::{DecoderExt as _, EncoderExt as _, chunks, wire};
221
222 #[test]
223 fn decode_string() {
224 assert_eq!(
225 chunks![
226 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
227 0xff, 0xff, 0x30, 0x31, 0x32, 0x33, 0x00, 0x00, 0x00, 0x00,
228 ]
229 .as_mut_slice()
230 .decode_with_constraint::<wire::String<'_>>(1000)
231 .unwrap(),
232 "0123",
233 );
234 assert_eq!(
235 chunks![
236 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
237 0xff, 0xff,
238 ]
239 .as_mut_slice()
240 .decode_with_constraint::<wire::String<'_>>(1000)
241 .unwrap(),
242 "",
243 );
244 }
245
246 #[test]
247 fn encode_string() {
248 assert_eq!(
249 Vec::encode_with_constraint(Some("0123".to_string()), 1000).unwrap(),
250 chunks![
251 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
252 0xff, 0xff, 0x30, 0x31, 0x32, 0x33, 0x00, 0x00, 0x00, 0x00,
253 ],
254 );
255 assert_eq!(
256 Vec::encode_with_constraint(Some(String::new()), 1000).unwrap(),
257 chunks![
258 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
259 0xff, 0xff,
260 ],
261 );
262 }
263}