fidl_next_codec/wire/string/
required.rs

1// Copyright 2024 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use 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    Decode, DecodeError, Decoder, Encodable, Encode, EncodeError, EncodeRef, Encoder, FromWire,
14    FromWireRef, Slot, Wire, WireVector,
15};
16
17/// A FIDL string
18#[repr(transparent)]
19pub struct WireString<'de> {
20    vec: WireVector<'de, u8>,
21}
22
23unsafe impl Wire for WireString<'static> {
24    type Decoded<'de> = WireString<'de>;
25
26    #[inline]
27    fn zero_padding(out: &mut MaybeUninit<Self>) {
28        munge!(let Self { vec } = out);
29        WireVector::<u8>::zero_padding(vec);
30    }
31}
32
33impl WireString<'_> {
34    /// Encodes that a string is present in a slot.
35    #[inline]
36    pub fn encode_present(out: &mut MaybeUninit<Self>, len: u64) {
37        munge!(let Self { vec } = out);
38        WireVector::encode_present(vec, len);
39    }
40
41    /// Returns the length of the string in bytes.
42    #[inline]
43    pub fn len(&self) -> usize {
44        self.vec.len()
45    }
46
47    /// Returns whether the string is empty.
48    #[inline]
49    pub fn is_empty(&self) -> bool {
50        self.len() == 0
51    }
52
53    /// Returns a reference to the underlying `str`.
54    #[inline]
55    pub fn as_str(&self) -> &str {
56        unsafe { from_utf8_unchecked(self.vec.as_slice()) }
57    }
58}
59
60impl Deref for WireString<'_> {
61    type Target = str;
62
63    #[inline]
64    fn deref(&self) -> &Self::Target {
65        self.as_str()
66    }
67}
68
69impl fmt::Debug for WireString<'_> {
70    #[inline]
71    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72        self.as_str().fmt(f)
73    }
74}
75
76unsafe impl<D: Decoder + ?Sized> Decode<D> for WireString<'static> {
77    #[inline]
78    fn decode(slot: Slot<'_, Self>, decoder: &mut D) -> Result<(), DecodeError> {
79        munge!(let Self { mut vec } = slot);
80
81        unsafe {
82            WireVector::decode_raw(vec.as_mut(), decoder)?;
83        }
84        let vec = unsafe { vec.deref_unchecked() };
85
86        // Check if the string is valid ASCII (fast path)
87        if !vec.as_slice().is_ascii() {
88            // Fall back to checking if the string is valid UTF-8 (slow path)
89            // We're using `from_utf8` more like an `is_utf8` here.
90            let _ = from_utf8(vec.as_slice())?;
91        }
92
93        Ok(())
94    }
95}
96
97impl Encodable for String {
98    type Encoded = WireString<'static>;
99}
100
101unsafe impl<E: Encoder + ?Sized> Encode<E> for String {
102    #[inline]
103    fn encode(
104        self,
105        encoder: &mut E,
106        out: &mut MaybeUninit<Self::Encoded>,
107    ) -> Result<(), EncodeError> {
108        self.as_str().encode(encoder, out)
109    }
110}
111
112unsafe impl<E: Encoder + ?Sized> EncodeRef<E> for String {
113    #[inline]
114    fn encode_ref(
115        &self,
116        encoder: &mut E,
117        out: &mut MaybeUninit<Self::Encoded>,
118    ) -> Result<(), EncodeError> {
119        self.as_str().encode(encoder, out)
120    }
121}
122
123impl Encodable for &str {
124    type Encoded = WireString<'static>;
125}
126
127unsafe impl<E: Encoder + ?Sized> Encode<E> for &str {
128    #[inline]
129    fn encode(
130        self,
131        encoder: &mut E,
132        out: &mut MaybeUninit<Self::Encoded>,
133    ) -> Result<(), EncodeError> {
134        encoder.write(self.as_bytes());
135        WireString::encode_present(out, self.len() as u64);
136        Ok(())
137    }
138}
139
140impl FromWire<WireString<'_>> for String {
141    #[inline]
142    fn from_wire(wire: WireString<'_>) -> Self {
143        String::from_wire_ref(&wire)
144    }
145}
146
147impl FromWireRef<WireString<'_>> for String {
148    #[inline]
149    fn from_wire_ref(wire: &WireString<'_>) -> Self {
150        unsafe { String::from_utf8_unchecked(Vec::from_wire_ref(&wire.vec)) }
151    }
152}