fidl_next_codec/wire/string/
optional.rs1use core::fmt;
6use core::mem::MaybeUninit;
7use core::str::from_utf8;
8
9use munge::munge;
10
11use crate::{
12 Constrained, Decode, DecodeError, Decoder, EncodableOption, EncodeError, EncodeOption,
13 EncodeOptionRef, Encoder, FromWireOption, FromWireOptionRef, IntoNatural, Slot,
14 ValidationError, Wire, WireOptionalVector, WireString, WireVector,
15};
16
17#[repr(transparent)]
19pub struct WireOptionalString<'de> {
20 vec: WireOptionalVector<'de, u8>,
21}
22
23unsafe impl Wire for WireOptionalString<'static> {
24 type Decoded<'de> = WireOptionalString<'de>;
25
26 #[inline]
27 fn zero_padding(out: &mut MaybeUninit<Self>) {
28 munge!(let Self { vec } = out);
29 WireOptionalVector::<u8>::zero_padding(vec);
30 }
31}
32
33impl WireOptionalString<'_> {
34 #[inline]
36 pub fn encode_present(out: &mut MaybeUninit<Self>, len: u64) {
37 munge!(let Self { vec } = out);
38 WireOptionalVector::encode_present(vec, len);
39 }
40
41 #[inline]
43 pub fn encode_absent(out: &mut MaybeUninit<Self>) {
44 munge!(let Self { vec } = out);
45 WireOptionalVector::encode_absent(vec);
46 }
47
48 #[inline]
50 pub fn is_some(&self) -> bool {
51 self.vec.is_some()
52 }
53
54 #[inline]
56 pub fn is_none(&self) -> bool {
57 self.vec.is_none()
58 }
59
60 #[inline]
62 pub fn as_ref(&self) -> Option<&WireString<'_>> {
63 self.vec.as_ref().map(|vec| unsafe { &*(vec as *const WireVector<'_, u8>).cast() })
64 }
65
66 fn validate_max_len(slot: Slot<'_, Self>, limit: u64) -> Result<(), crate::ValidationError> {
68 munge!(let Self { vec } = slot);
69 match WireOptionalVector::validate_max_len(vec, limit) {
70 Ok(()) => Ok(()),
71 Err(ValidationError::VectorTooLong { count, limit }) => {
72 Err(ValidationError::StringTooLong { count, limit })
73 }
74 Err(e) => Err(e),
75 }
76 }
77}
78
79impl Constrained for WireOptionalString<'_> {
80 type Constraint = u64;
81
82 fn validate(slot: Slot<'_, Self>, constraint: Self::Constraint) -> Result<(), ValidationError> {
83 Self::validate_max_len(slot, constraint)
84 }
85}
86
87impl fmt::Debug for WireOptionalString<'_> {
88 #[inline]
89 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
90 self.as_ref().fmt(f)
91 }
92}
93
94unsafe impl<D: Decoder + ?Sized> Decode<D> for WireOptionalString<'static> {
95 #[inline]
96 fn decode(slot: Slot<'_, Self>, decoder: &mut D, constraint: u64) -> Result<(), DecodeError> {
97 munge!(let Self { mut vec } = slot);
98
99 let result = unsafe { WireOptionalVector::decode_raw(vec.as_mut(), decoder, constraint) };
100 match result {
101 Ok(()) => (),
102 Err(DecodeError::Validation(ValidationError::VectorTooLong { count, limit })) => {
103 return Err(DecodeError::Validation(ValidationError::StringTooLong {
104 count,
105 limit,
106 }));
107 }
108 Err(e) => return Err(e),
109 }
110 let vec = unsafe { vec.deref_unchecked() };
111 if let Some(bytes) = vec.as_ref() {
112 if !bytes.as_slice().is_ascii() {
114 let _ = from_utf8(bytes)?;
117 }
118 }
119
120 Ok(())
121 }
122}
123
124impl EncodableOption for String {
125 type EncodedOption = WireOptionalString<'static>;
126}
127
128unsafe impl<E: Encoder + ?Sized> EncodeOption<E> for String {
129 #[inline]
130 fn encode_option(
131 this: Option<Self>,
132 encoder: &mut E,
133 out: &mut MaybeUninit<Self::EncodedOption>,
134 constraint: u64,
135 ) -> Result<(), EncodeError> {
136 <&str>::encode_option(this.as_deref(), encoder, out, constraint)
137 }
138}
139
140unsafe impl<E: Encoder + ?Sized> EncodeOptionRef<E> for String {
141 #[inline]
142 fn encode_option_ref(
143 this: Option<&Self>,
144 encoder: &mut E,
145 out: &mut MaybeUninit<Self::EncodedOption>,
146 constraint: u64,
147 ) -> Result<(), EncodeError> {
148 <&str>::encode_option(this.map(String::as_str), encoder, out, constraint)
149 }
150}
151
152impl EncodableOption for &str {
153 type EncodedOption = WireOptionalString<'static>;
154}
155
156unsafe impl<E: Encoder + ?Sized> EncodeOption<E> for &str {
157 #[inline]
158 fn encode_option(
159 this: Option<Self>,
160 encoder: &mut E,
161 out: &mut MaybeUninit<Self::EncodedOption>,
162 _constraint: u64,
163 ) -> Result<(), EncodeError> {
164 if let Some(string) = this {
165 encoder.write(string.as_bytes());
166 WireOptionalString::encode_present(out, string.len() as u64);
167 } else {
168 WireOptionalString::encode_absent(out);
169 }
170 Ok(())
171 }
172}
173
174impl FromWireOption<WireOptionalString<'_>> for String {
175 #[inline]
176 fn from_wire_option(wire: WireOptionalString<'_>) -> Option<Self> {
177 Vec::from_wire_option(wire.vec).map(|vec| unsafe { String::from_utf8_unchecked(vec) })
178 }
179}
180
181impl IntoNatural for WireOptionalString<'_> {
182 type Natural = Option<String>;
183}
184
185impl FromWireOptionRef<WireOptionalString<'_>> for String {
186 #[inline]
187 fn from_wire_option_ref(wire: &WireOptionalString<'_>) -> Option<Self> {
188 Vec::from_wire_option_ref(&wire.vec).map(|vec| unsafe { String::from_utf8_unchecked(vec) })
189 }
190}