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
34unsafe impl Wire for Unit {
35    type Narrowed<'de> = Self;
36
37    #[inline]
38    fn zero_padding(_: &mut MaybeUninit<Self>) {}
39}
40
41impl fmt::Debug for Unit {
42    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43        f.debug_struct("Unit").finish()
44    }
45}
46
47impl fmt::Display for Unit {
48    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49        write!(f, "Unit")
50    }
51}
52
53unsafe impl<D: ?Sized> Decode<D> for Unit {
54    fn decode(
55        slot: Slot<'_, Self>,
56        _: &mut D,
57        _: Self::Constraint,
58    ) -> Result<(), crate::DecodeError> {
59        let value = unsafe { slot.as_ptr().cast::<u8>().read() };
60        match value {
61            0 => Ok(()),
62            invalid => Err(DecodeError::InvalidUnit(invalid)),
63        }
64    }
65}
66
67unsafe impl<E: ?Sized> Encode<Unit, E> for () {
68    fn encode(self, _: &mut E, out: &mut MaybeUninit<Unit>, _: ()) -> Result<(), EncodeError> {
69        let _ = out.write(Unit::Unit);
70        Ok(())
71    }
72}
73
74unsafe impl<E: ?Sized> Encode<Unit, E> for &() {
75    fn encode(
76        self,
77        encoder: &mut E,
78        out: &mut MaybeUninit<Unit>,
79        constraint: (),
80    ) -> Result<(), EncodeError> {
81        Encode::encode((), encoder, out, constraint)
82    }
83}
84
85unsafe impl<E> EncodeOption<wire::Box<'static, Unit>, E> for ()
86where
87    E: Encoder + ?Sized,
88{
89    #[inline]
90    fn encode_option(
91        this: Option<Self>,
92        encoder: &mut E,
93        out: &mut MaybeUninit<wire::Box<'static, Unit>>,
94        constraint: (),
95    ) -> Result<(), EncodeError> {
96        if let Some(value) = this {
97            encoder.encode_next_with_constraint(value, constraint)?;
98            wire::Box::encode_present(out);
99        } else {
100            wire::Box::encode_absent(out);
101        }
102
103        Ok(())
104    }
105}
106
107unsafe impl<E> EncodeOption<wire::Box<'static, Unit>, E> for &()
108where
109    E: Encoder + ?Sized,
110{
111    #[inline]
112    fn encode_option(
113        this: Option<Self>,
114        encoder: &mut E,
115        out: &mut MaybeUninit<wire::Box<'static, Unit>>,
116        constraint: (),
117    ) -> Result<(), EncodeError> {
118        <()>::encode_option(this.cloned(), encoder, out, constraint)
119    }
120}
121
122impl From<()> for Unit {
123    fn from(_: ()) -> Self {
124        Self::Unit
125    }
126}
127
128impl<'a> From<&'a ()> for Unit {
129    fn from(_: &'a ()) -> Self {
130        Self::Unit
131    }
132}
133
134impl From<Unit> for () {
135    fn from(_: Unit) -> Self {}
136}
137
138impl<'a> From<&'a Unit> for () {
139    fn from(_: &'a Unit) -> Self {}
140}
141
142impl FromWire<Unit> for () {
143    fn from_wire(wire: Unit) -> Self {
144        Self::from_wire_ref(&wire)
145    }
146}
147
148impl FromWireRef<Unit> for () {
149    fn from_wire_ref(_: &Unit) -> Self {}
150}
151
152impl IntoNatural for Unit {
153    type Natural = ();
154}
155
156#[cfg(test)]
157mod tests {
158    use crate::{DecoderExt as _, EncoderExt as _, chunks, wire};
159
160    #[test]
161    fn decode_unit() {
162        assert_eq!(
163            chunks![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
164                .as_mut_slice()
165                .decode::<wire::Unit>()
166                .unwrap(),
167            wire::Unit::Unit,
168        );
169    }
170
171    #[test]
172    fn encode_unit() {
173        assert_eq!(
174            Vec::encode(()).unwrap(),
175            chunks![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
176        );
177    }
178}