Skip to main content

fidl_next_codec/wire/
unit.rs

1// Copyright 2025 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;
7
8use crate::{
9    Constrained, Decode, DecodeError, Encode, EncodeError, EncodeOption, Encoder, EncoderExt,
10    FromWire, FromWireRef, IntoNatural, Slot, ValidationError, Wire, wire,
11};
12
13/// The empty FIDL "unit" struct.
14///
15/// FIDL wire type layouts follow the same rules as C/C++ type layout rules.
16/// Because every object must have a unique address, the empty "unit" type must
17/// be be a single byte that is set to zero.
18#[repr(u8)]
19#[derive(Clone, Copy, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
20pub enum Unit {
21    /// Empty structs are represented as a single 0u8.
22    #[default]
23    Unit = 0,
24}
25
26impl Constrained for Unit {
27    type Constraint = ();
28
29    fn validate(_: Slot<'_, Self>, _: Self::Constraint) -> Result<(), ValidationError> {
30        Ok(())
31    }
32}
33
34// SAFETY: `Unit` is a repr(u8) enum with size 1 and no padding.
35unsafe impl Wire for Unit {
36    type Narrowed<'de> = Self;
37
38    #[inline]
39    fn zero_padding(_: &mut MaybeUninit<Self>) {}
40}
41
42impl fmt::Debug for Unit {
43    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44        f.debug_struct("Unit").finish()
45    }
46}
47
48impl fmt::Display for Unit {
49    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50        write!(f, "Unit")
51    }
52}
53
54// SAFETY: `Unit` is decoded by reading a byte and validating it is 0.
55unsafe impl<D: ?Sized> Decode<D> for Unit {
56    fn decode(
57        slot: Slot<'_, Self>,
58        _: &mut D,
59        _: Self::Constraint,
60    ) -> Result<(), crate::DecodeError> {
61        // SAFETY: `slot` is guaranteed to contain a valid `Unit` (1 byte).
62        let value = unsafe { slot.as_ptr().cast::<u8>().read() };
63        match value {
64            0 => Ok(()),
65            invalid => Err(DecodeError::InvalidUnit(invalid)),
66        }
67    }
68}
69
70// SAFETY: Encoding `()` to `Unit` writes `Unit::Unit` (0) to the output slot.
71unsafe impl<E: ?Sized> Encode<Unit, E> for () {
72    fn encode(self, _: &mut E, out: &mut MaybeUninit<Unit>, _: ()) -> Result<(), EncodeError> {
73        let _ = out.write(Unit::Unit);
74        Ok(())
75    }
76}
77
78// SAFETY: Delegates to `()` implementation.
79unsafe impl<E: ?Sized> Encode<Unit, E> for &() {
80    fn encode(
81        self,
82        encoder: &mut E,
83        out: &mut MaybeUninit<Unit>,
84        constraint: (),
85    ) -> Result<(), EncodeError> {
86        Encode::encode((), encoder, out, constraint)
87    }
88}
89
90// SAFETY: Encoding optional `()` delegates to `Box::encode_present` or `Box::encode_absent`.
91unsafe impl<E> EncodeOption<wire::Box<'static, Unit>, E> for ()
92where
93    E: Encoder + ?Sized,
94{
95    #[inline]
96    fn encode_option(
97        this: Option<Self>,
98        encoder: &mut E,
99        out: &mut MaybeUninit<wire::Box<'static, Unit>>,
100        constraint: (),
101    ) -> Result<(), EncodeError> {
102        if let Some(value) = this {
103            encoder.encode_next_with_constraint(value, constraint)?;
104            wire::Box::encode_present(out);
105        } else {
106            wire::Box::encode_absent(out);
107        }
108
109        Ok(())
110    }
111}
112
113// SAFETY: Delegates to `()` implementation.
114unsafe impl<E> EncodeOption<wire::Box<'static, Unit>, E> for &()
115where
116    E: Encoder + ?Sized,
117{
118    #[inline]
119    fn encode_option(
120        this: Option<Self>,
121        encoder: &mut E,
122        out: &mut MaybeUninit<wire::Box<'static, Unit>>,
123        constraint: (),
124    ) -> Result<(), EncodeError> {
125        <()>::encode_option(this.cloned(), encoder, out, constraint)
126    }
127}
128
129impl From<()> for Unit {
130    fn from(_: ()) -> Self {
131        Self::Unit
132    }
133}
134
135impl<'a> From<&'a ()> for Unit {
136    fn from(_: &'a ()) -> Self {
137        Self::Unit
138    }
139}
140
141impl From<Unit> for () {
142    fn from(_: Unit) -> Self {}
143}
144
145impl<'a> From<&'a Unit> for () {
146    fn from(_: &'a Unit) -> Self {}
147}
148
149impl FromWire<Unit> for () {
150    fn from_wire(wire: Unit) -> Self {
151        Self::from_wire_ref(&wire)
152    }
153}
154
155impl FromWireRef<Unit> for () {
156    fn from_wire_ref(_: &Unit) -> Self {}
157}
158
159impl IntoNatural for Unit {
160    type Natural = ();
161}
162
163#[cfg(test)]
164mod tests {
165    use crate::{DecoderExt as _, EncoderExt as _, chunks, wire};
166
167    #[test]
168    fn decode_unit() {
169        assert_eq!(
170            chunks![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
171                .as_mut_slice()
172                .decode::<wire::Unit>()
173                .unwrap(),
174            wire::Unit::Unit,
175        );
176    }
177
178    #[test]
179    fn encode_unit() {
180        assert_eq!(
181            Vec::encode(()).unwrap(),
182            chunks![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
183        );
184    }
185}