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