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 Decode, DecodeError, Decoder, EncodableOption, EncodeError, EncodeOption, EncodeOptionRef,
13 Encoder, FromWireOption, FromWireOptionRef, Slot, Wire, WireOptionalVector, WireString,
14 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
67impl fmt::Debug for WireOptionalString<'_> {
68 #[inline]
69 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70 self.as_ref().fmt(f)
71 }
72}
73
74unsafe impl<D: Decoder + ?Sized> Decode<D> for WireOptionalString<'static> {
75 #[inline]
76 fn decode(slot: Slot<'_, Self>, decoder: &mut D) -> Result<(), DecodeError> {
77 munge!(let Self { mut vec } = slot);
78
79 unsafe {
80 WireOptionalVector::decode_raw(vec.as_mut(), decoder)?;
81 }
82 let vec = unsafe { vec.deref_unchecked() };
83 if let Some(bytes) = vec.as_ref() {
84 if !bytes.as_slice().is_ascii() {
86 let _ = from_utf8(bytes)?;
89 }
90 }
91
92 Ok(())
93 }
94}
95
96impl EncodableOption for String {
97 type EncodedOption = WireOptionalString<'static>;
98}
99
100unsafe impl<E: Encoder + ?Sized> EncodeOption<E> for String {
101 #[inline]
102 fn encode_option(
103 this: Option<Self>,
104 encoder: &mut E,
105 out: &mut MaybeUninit<Self::EncodedOption>,
106 ) -> Result<(), EncodeError> {
107 <&str>::encode_option(this.as_deref(), encoder, out)
108 }
109}
110
111unsafe impl<E: Encoder + ?Sized> EncodeOptionRef<E> for String {
112 #[inline]
113 fn encode_option_ref(
114 this: Option<&Self>,
115 encoder: &mut E,
116 out: &mut MaybeUninit<Self::EncodedOption>,
117 ) -> Result<(), EncodeError> {
118 <&str>::encode_option(this.map(String::as_str), encoder, out)
119 }
120}
121
122impl EncodableOption for &str {
123 type EncodedOption = WireOptionalString<'static>;
124}
125
126unsafe impl<E: Encoder + ?Sized> EncodeOption<E> for &str {
127 #[inline]
128 fn encode_option(
129 this: Option<Self>,
130 encoder: &mut E,
131 out: &mut MaybeUninit<Self::EncodedOption>,
132 ) -> Result<(), EncodeError> {
133 if let Some(string) = this {
134 encoder.write(string.as_bytes());
135 WireOptionalString::encode_present(out, string.len() as u64);
136 } else {
137 WireOptionalString::encode_absent(out);
138 }
139 Ok(())
140 }
141}
142
143impl FromWireOption<WireOptionalString<'_>> for String {
144 #[inline]
145 fn from_wire_option(wire: WireOptionalString<'_>) -> Option<Self> {
146 Vec::from_wire_option(wire.vec).map(|vec| unsafe { String::from_utf8_unchecked(vec) })
147 }
148}
149
150impl FromWireOptionRef<WireOptionalString<'_>> for String {
151 #[inline]
152 fn from_wire_option_ref(wire: &WireOptionalString<'_>) -> Option<Self> {
153 Vec::from_wire_option_ref(&wire.vec).map(|vec| unsafe { String::from_utf8_unchecked(vec) })
154 }
155}