redoubt_codec_core/
primitives.rs

1// Copyright (c) 2025-2026 Federico Hoerth <memparanoid@gmail.com>
2// SPDX-License-Identifier: GPL-3.0-only
3// See LICENSE in the repository root for full license text.
4
5#[cfg(feature = "zeroize")]
6use redoubt_zero::FastZeroizable;
7
8use crate::error::DecodeError;
9
10use super::traits::{DecodeBuffer, TryDecode, TryEncode};
11
12// Native endian - bulk copy for all architectures
13macro_rules! impl_traits_for_primitives {
14    ($($ty:ty),* $(,)?) => {
15        $(
16            impl $crate::traits::BytesRequired for $ty {
17                #[inline(always)]
18                fn encode_bytes_required(&self) -> Result<usize, $crate::error::OverflowError> {
19                    Ok(core::mem::size_of::<$ty>())
20                }
21            }
22
23            impl $crate::traits::TryEncode for $ty {
24                #[inline(always)]
25                fn try_encode_into(&mut self, buf: &mut $crate::codec_buffer::RedoubtCodecBuffer) -> Result<(), $crate::error::EncodeError> {
26                    buf.write(self)?;
27                    Ok(())
28                }
29            }
30
31            impl $crate::traits::Encode for $ty {
32                #[inline(always)]
33                fn encode_into(&mut self, buf: &mut $crate::codec_buffer::RedoubtCodecBuffer) -> Result<(), $crate::error::EncodeError> {
34                    let result = self.try_encode_into(buf);
35
36                    #[cfg(feature = "zeroize")]
37                    self.fast_zeroize();
38
39                    #[cfg(feature = "zeroize")]
40                    if result.is_err() {
41                        buf.fast_zeroize();
42                    }
43
44                    result
45                }
46            }
47
48            /// Caller is responsible for zeroizing slice and buffer on error.
49            impl $crate::traits::EncodeSlice for $ty {
50                #[inline(always)]
51                fn encode_slice_into(slice: &mut [Self], buf: &mut $crate::codec_buffer::RedoubtCodecBuffer) -> Result<(), $crate::error::EncodeError> {
52                    buf.write_slice(slice)?;
53                    Ok(())
54                }
55            }
56
57            impl $crate::traits::TryDecode for $ty {
58                #[inline(always)]
59                fn try_decode_from(&mut self, buf: &mut &mut [u8]) -> Result<(), $crate::error::DecodeError> {
60                    buf.read(self)?;
61                    Ok(())
62                }
63            }
64
65            impl $crate::traits::Decode for $ty {
66                #[inline(always)]
67                fn decode_from(&mut self, buf: &mut &mut [u8]) -> Result<(), $crate::error::DecodeError> {
68                    let result = self.try_decode_from(buf);
69
70                    #[cfg(feature = "zeroize")]
71                    if result.is_err() {
72                        self.fast_zeroize();
73                        buf.fast_zeroize();
74                    }
75
76                    result
77                }
78            }
79
80            /// Caller is responsible for zeroizing slice and buffer on error.
81            impl $crate::traits::DecodeSlice for $ty {
82                #[inline(always)]
83                fn decode_slice_from(slice: &mut [Self], buf: &mut &mut [u8]) -> Result<(), DecodeError> {
84                    buf.read_slice(slice)?;
85                    Ok(())
86                }
87            }
88
89            impl $crate::traits::PreAlloc for $ty {
90                const ZERO_INIT: bool = true;
91
92                #[inline(always)]
93                fn prealloc(&mut self, _size: usize) {
94                    // No-op: collection must preallocate memory with zeroes
95                }
96            }
97        )*
98    };
99}
100
101impl_traits_for_primitives!(
102    bool, u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64,
103);