s2n_codec/
zerocopy.rs

1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4use core::{
5    cmp::Ordering,
6    fmt,
7    hash::{Hash, Hasher},
8};
9pub use zerocopy::*;
10
11#[cfg(feature = "generator")]
12use bolero_generator::prelude::*;
13
14/// Define a codec implementation for a zerocopy value that implements
15/// `FromBytes`, `IntoBytes`, and `Unaligned`.
16#[macro_export]
17macro_rules! zerocopy_value_codec {
18    ($name:ident) => {
19        impl<'a> $crate::DecoderValue<'a> for $name
20        where
21            $name: $crate::zerocopy::FromBytes,
22        {
23            #[inline]
24            fn decode(buffer: $crate::DecoderBuffer<'a>) -> $crate::DecoderBufferResult<'a, Self> {
25                let (value, buffer) = <&'a $name as $crate::DecoderValue>::decode(buffer)?;
26                Ok((*value, buffer))
27            }
28        }
29
30        impl<'a> $crate::DecoderValue<'a> for &'a $name
31        where
32            $name: $crate::zerocopy::FromBytes,
33        {
34            #[inline]
35            fn decode(buffer: $crate::DecoderBuffer<'a>) -> $crate::DecoderBufferResult<'a, Self> {
36                let (value, buffer) = buffer.decode_slice(core::mem::size_of::<$name>())?;
37                let value = value.into_less_safe_slice();
38                let value = unsafe {
39                    // Safety: the type implements FromBytes
40                    &*(value as *const _ as *const $name)
41                };
42                Ok((value, buffer.into()))
43            }
44        }
45
46        impl<'a> $crate::DecoderValueMut<'a> for $name
47        where
48            $name: $crate::zerocopy::FromBytes,
49        {
50            #[inline]
51            fn decode_mut(
52                buffer: $crate::DecoderBufferMut<'a>,
53            ) -> $crate::DecoderBufferMutResult<'a, Self> {
54                let (value, buffer) = <&'a $name as $crate::DecoderValueMut>::decode_mut(buffer)?;
55                Ok((*value, buffer))
56            }
57        }
58
59        impl<'a> $crate::DecoderValueMut<'a> for &'a $name
60        where
61            $name: $crate::zerocopy::FromBytes,
62        {
63            #[inline]
64            fn decode_mut(
65                buffer: $crate::DecoderBufferMut<'a>,
66            ) -> $crate::DecoderBufferMutResult<'a, Self> {
67                let (value, buffer) =
68                    <&'a mut $name as $crate::DecoderValueMut>::decode_mut(buffer)?;
69                Ok((value, buffer))
70            }
71        }
72
73        impl<'a> $crate::DecoderValueMut<'a> for &'a mut $name
74        where
75            $name: $crate::zerocopy::FromBytes,
76        {
77            #[inline]
78            fn decode_mut(
79                buffer: $crate::DecoderBufferMut<'a>,
80            ) -> $crate::DecoderBufferMutResult<'a, Self> {
81                let (value, buffer) = buffer.decode_slice(core::mem::size_of::<$name>())?;
82                let value = value.into_less_safe_slice();
83                let value = unsafe {
84                    // Safety: the type implements FromBytes
85                    &mut *(value as *mut _ as *mut $name)
86                };
87
88                Ok((value, buffer.into()))
89            }
90        }
91
92        impl $crate::EncoderValue for $name
93        where
94            $name: $crate::zerocopy::IntoBytes,
95        {
96            #[inline]
97            fn encoding_size(&self) -> usize {
98                core::mem::size_of::<$name>()
99            }
100
101            #[inline]
102            fn encoding_size_for_encoder<E: $crate::Encoder>(&self, _encoder: &E) -> usize {
103                core::mem::size_of::<$name>()
104            }
105
106            #[inline]
107            fn encode<E: $crate::Encoder>(&self, encoder: &mut E) {
108                let bytes = unsafe {
109                    // Safety: the type implements IntoBytes
110                    core::slice::from_raw_parts(
111                        self as *const $name as *const u8,
112                        core::mem::size_of::<$name>(),
113                    )
114                };
115                encoder.write_slice(bytes);
116            }
117        }
118
119        impl<'a> $crate::EncoderValue for &'a $name
120        where
121            $name: $crate::zerocopy::IntoBytes,
122        {
123            #[inline]
124            fn encoding_size(&self) -> usize {
125                core::mem::size_of::<$name>()
126            }
127
128            #[inline]
129            fn encoding_size_for_encoder<E: $crate::Encoder>(&self, _encoder: &E) -> usize {
130                ::core::mem::size_of::<$name>()
131            }
132
133            #[inline]
134            fn encode<E: $crate::Encoder>(&self, encoder: &mut E) {
135                let bytes = unsafe {
136                    // Safety: the type implements IntoBytes
137                    core::slice::from_raw_parts(
138                        *self as *const $name as *const u8,
139                        core::mem::size_of::<$name>(),
140                    )
141                };
142                encoder.write_slice(bytes);
143            }
144        }
145
146        impl<'a> $crate::EncoderValue for &'a mut $name
147        where
148            $name: $crate::zerocopy::IntoBytes,
149        {
150            #[inline]
151            fn encoding_size(&self) -> usize {
152                core::mem::size_of::<$name>()
153            }
154
155            #[inline]
156            fn encoding_size_for_encoder<E: $crate::Encoder>(&self, _encoder: &E) -> usize {
157                ::core::mem::size_of::<$name>()
158            }
159
160            #[inline]
161            fn encode<E: $crate::Encoder>(&self, encoder: &mut E) {
162                let bytes = unsafe {
163                    // Safety: the type implements IntoBytes
164                    core::slice::from_raw_parts(
165                        *self as *const $name as *const u8,
166                        core::mem::size_of::<$name>(),
167                    )
168                };
169                encoder.write_slice(bytes);
170            }
171        }
172    };
173}
174
175// The `zerocopy` crate provides integer types that are able to be referenced
176// in an endian-independent method. This macro wraps those types and implements
177// a few convenience traits.
178macro_rules! zerocopy_network_integer {
179    ($native:ident, $name:ident) => {
180        #[derive(
181            Clone,
182            Copy,
183            Default,
184            Eq,
185            Immutable,
186            $crate::zerocopy::FromBytes,
187            $crate::zerocopy::IntoBytes,
188            $crate::zerocopy::Unaligned,
189        )]
190        #[repr(C)]
191        pub struct $name(::zerocopy::byteorder::$name<NetworkEndian>);
192
193        impl $name {
194            pub const ZERO: Self = Self(::zerocopy::byteorder::$name::ZERO);
195
196            #[inline(always)]
197            pub fn new(value: $native) -> Self {
198                value.into()
199            }
200
201            #[inline(always)]
202            pub fn get(&self) -> $native {
203                self.get_be().to_be()
204            }
205
206            #[inline(always)]
207            pub fn get_be(&self) -> $native {
208                unsafe {
209                    $native::from_ne_bytes(
210                        *(self.0.as_bytes().as_ptr()
211                            as *const [u8; ::core::mem::size_of::<$native>()]),
212                    )
213                }
214            }
215
216            #[inline(always)]
217            pub fn set(&mut self, value: $native) {
218                self.0.as_mut_bytes().copy_from_slice(&value.to_be_bytes());
219            }
220
221            #[inline(always)]
222            pub fn set_be(&mut self, value: $native) {
223                self.0.as_mut_bytes().copy_from_slice(&value.to_ne_bytes());
224            }
225        }
226
227        impl PartialEq for $name {
228            #[inline]
229            fn eq(&self, other: &Self) -> bool {
230                self.cmp(other) == Ordering::Equal
231            }
232        }
233
234        impl PartialEq<$native> for $name {
235            #[inline]
236            fn eq(&self, other: &$native) -> bool {
237                self.partial_cmp(other) == Some(Ordering::Equal)
238            }
239        }
240
241        impl PartialOrd for $name {
242            #[inline]
243            fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
244                Some(self.cmp(other))
245            }
246        }
247
248        impl PartialOrd<$native> for $name {
249            #[inline]
250            fn partial_cmp(&self, other: &$native) -> Option<Ordering> {
251                Some(self.get().cmp(other))
252            }
253        }
254
255        impl Ord for $name {
256            #[inline]
257            fn cmp(&self, other: &Self) -> Ordering {
258                self.get_be().cmp(&other.get_be())
259            }
260        }
261
262        impl Hash for $name {
263            fn hash<H: Hasher>(&self, state: &mut H) {
264                self.get().hash(state);
265            }
266        }
267
268        impl fmt::Debug for $name {
269            fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
270                write!(formatter, "{}", self.get())
271            }
272        }
273
274        impl fmt::Display for $name {
275            fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
276                write!(formatter, "{}", self.get())
277            }
278        }
279
280        impl From<$native> for $name {
281            #[inline]
282            fn from(value: $native) -> Self {
283                Self(::zerocopy::byteorder::$name::new(value))
284            }
285        }
286
287        impl From<$name> for $native {
288            #[inline]
289            fn from(v: $name) -> $native {
290                v.get()
291            }
292        }
293
294        #[cfg(feature = "generator")]
295        impl TypeGenerator for $name {
296            fn generate<D: bolero_generator::Driver>(driver: &mut D) -> Option<Self> {
297                Some(Self::new(driver.produce()?))
298            }
299        }
300
301        #[cfg(kani)]
302        impl kani::Arbitrary for $name {
303            fn any() -> Self {
304                Self::new(kani::any())
305            }
306        }
307
308        zerocopy_value_codec!($name);
309    };
310}
311
312zerocopy_network_integer!(i16, I16);
313zerocopy_network_integer!(u16, U16);
314zerocopy_network_integer!(i32, I32);
315zerocopy_network_integer!(u32, U32);
316zerocopy_network_integer!(i64, I64);
317zerocopy_network_integer!(u64, U64);
318zerocopy_network_integer!(i128, I128);
319zerocopy_network_integer!(u128, U128);
320
321#[test]
322fn zerocopy_struct_test() {
323    use crate::DecoderBuffer;
324
325    #[derive(Copy, Clone, Debug, PartialEq, PartialOrd, FromBytes, IntoBytes, Unaligned)]
326    #[repr(C)]
327    struct UdpHeader {
328        source_port: U16,
329        destination_port: U16,
330        payload_len: U16,
331        checksum: U16,
332    }
333
334    zerocopy_value_codec!(UdpHeader);
335
336    let buffer = vec![0, 1, 0, 2, 0, 3, 0, 4];
337    let decoder = DecoderBuffer::new(&buffer);
338    let (mut header, _) = decoder.decode().unwrap();
339
340    ensure_codec_round_trip_value!(UdpHeader, header).unwrap();
341    ensure_codec_round_trip_value!(&UdpHeader, &header).unwrap();
342    ensure_codec_round_trip_value_mut!(&mut UdpHeader, &mut header).unwrap();
343
344    assert_eq!(header.source_port, 1u16);
345    assert_eq!(header.destination_port, 2u16);
346    assert_eq!(header.payload_len, 3u16);
347    assert_eq!(header.checksum, 4u16);
348}