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::ops::Deref;
7use core::str::{from_utf8, from_utf8_unchecked};
8
9use munge::munge;
10
11use crate::{
12    Decode, DecodeError, Decoder, Encodable, Encode, EncodeError, Encoder, Slot, TakeFrom,
13    WireVector, ZeroPadding,
14};
15
16/// A FIDL string
17#[repr(transparent)]
18pub struct WireString {
19    vec: WireVector<u8>,
20}
21
22unsafe impl ZeroPadding for WireString {
23    #[inline]
24    unsafe fn zero_padding(ptr: *mut Self) {
25        unsafe {
26            WireVector::<u8>::zero_padding(ptr.cast());
27        }
28    }
29}
30
31impl WireString {
32    /// Encodes that a string is present in a slot.
33    #[inline]
34    pub fn encode_present(slot: Slot<'_, Self>, len: u64) {
35        munge!(let Self { vec } = slot);
36        WireVector::encode_present(vec, len);
37    }
38
39    /// Returns the length of the string in bytes.
40    #[inline]
41    pub fn len(&self) -> usize {
42        self.vec.len()
43    }
44
45    /// Returns whether the string is empty.
46    #[inline]
47    pub fn is_empty(&self) -> bool {
48        self.len() == 0
49    }
50
51    /// Returns a reference to the underlying `str`.
52    #[inline]
53    pub fn as_str(&self) -> &str {
54        unsafe { from_utf8_unchecked(self.vec.as_slice()) }
55    }
56}
57
58impl Deref for WireString {
59    type Target = str;
60
61    #[inline]
62    fn deref(&self) -> &Self::Target {
63        self.as_str()
64    }
65}
66
67impl fmt::Debug for WireString {
68    #[inline]
69    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70        self.as_str().fmt(f)
71    }
72}
73
74unsafe impl<D: Decoder + ?Sized> Decode<D> for WireString {
75    #[inline]
76    fn decode(slot: Slot<'_, Self>, decoder: &mut D) -> Result<(), DecodeError> {
77        munge!(let Self { mut vec } = slot);
78
79        unsafe {
80            WireVector::decode_raw(vec.as_mut(), decoder)?;
81        }
82        let vec = unsafe { vec.deref_unchecked() };
83
84        // Check if the string is valid ASCII (fast path)
85        if !vec.as_slice().is_ascii() {
86            // Fall back to checking if the string is valid UTF-8 (slow path)
87            // We're using `from_utf8` more like an `is_utf8` here.
88            let _ = from_utf8(vec.as_slice())?;
89        }
90
91        Ok(())
92    }
93}
94
95impl Encodable for String {
96    type Encoded = WireString;
97}
98
99impl<E: Encoder + ?Sized> Encode<E> for String {
100    #[inline]
101    fn encode(
102        &mut self,
103        encoder: &mut E,
104        slot: Slot<'_, Self::Encoded>,
105    ) -> Result<(), EncodeError> {
106        encoder.write(self.as_bytes());
107        WireString::encode_present(slot, self.len() as u64);
108        Ok(())
109    }
110}
111
112impl TakeFrom<WireString> for String {
113    #[inline]
114    fn take_from(from: &WireString) -> Self {
115        from.to_string()
116    }
117}