redoubt_codec_core/
traits.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
5use redoubt_zero::FastZeroizable;
6
7use crate::codec_buffer::RedoubtCodecBuffer;
8use crate::error::{DecodeBufferError, DecodeError, EncodeError, OverflowError};
9
10pub trait BytesRequired {
11    fn encode_bytes_required(&self) -> Result<usize, OverflowError>;
12}
13
14/// Internal encoding trait that performs encoding without zeroization.
15///
16/// This trait separates the core encoding logic from security concerns:
17/// - **TryEncode**: Does the actual encoding work WITHOUT zeroization
18/// - **Encode**: Public API that calls `try_encode_into` and adds zeroization cleanup on error
19///
20/// This separation allows:
21/// - Internal code to skip zeroization when unnecessary
22/// - Clean separation of concerns (logic vs security)
23/// - The public API to guarantee zeroization invariants on all error paths
24pub(crate) trait TryEncode: Encode + Sized {
25    fn try_encode_into(&mut self, buf: &mut RedoubtCodecBuffer) -> Result<(), EncodeError>;
26}
27
28pub trait Encode {
29    fn encode_into(&mut self, buf: &mut RedoubtCodecBuffer) -> Result<(), EncodeError>;
30}
31
32/// Encode a slice of elements into the buffer.
33/// - Primitives: NO zeroize (collection handles it)
34/// - Collections: YES zeroize (handle their own cleanup)
35pub(crate) trait EncodeSlice: Encode + Sized {
36    fn encode_slice_into(
37        slice: &mut [Self],
38        buf: &mut RedoubtCodecBuffer,
39    ) -> Result<(), EncodeError>;
40}
41
42/// Internal decoding trait that performs decoding without zeroization.
43///
44/// This trait separates the core decoding logic from security concerns:
45/// - **TryDecode**: Does the actual decoding work WITHOUT zeroization
46/// - **Decode**: Public API that calls `try_decode_from` and adds zeroization cleanup on error
47///
48/// This separation allows:
49/// - Internal code to skip zeroization when unnecessary
50/// - Clean separation of concerns (logic vs security)
51/// - The public API to guarantee zeroization invariants on all error paths
52pub(crate) trait TryDecode {
53    fn try_decode_from(&mut self, buf: &mut &mut [u8]) -> Result<(), DecodeError>;
54}
55
56pub trait Decode {
57    fn decode_from(&mut self, buf: &mut &mut [u8]) -> Result<(), DecodeError>;
58}
59
60/// Decode a slice of elements from the buffer.
61/// - Primitives: NO zeroize (collection handles it)
62/// - Collections: YES zeroize (handle their own cleanup)
63pub(crate) trait DecodeSlice: Decode + Sized {
64    fn decode_slice_from(slice: &mut [Self], buf: &mut &mut [u8]) -> Result<(), DecodeError>;
65}
66
67pub trait DecodeBuffer {
68    fn read_usize(&mut self, dst: &mut usize) -> Result<(), DecodeBufferError>;
69    fn read<T>(&mut self, dst: &mut T) -> Result<(), DecodeBufferError>;
70    fn read_slice<T>(&mut self, dst: &mut [T]) -> Result<(), DecodeBufferError>;
71}
72
73/// Pre-allocation trait for collections.
74///
75/// `ZERO_INIT` indicates if the type can be safely initialized by zeroing memory.
76/// - `true`: Use fast memset + set_len (primitives)
77/// - `false`: Use Default::default() for each element (complex types)
78pub(crate) trait PreAlloc: Default {
79    const ZERO_INIT: bool;
80    fn prealloc(&mut self, size: usize);
81}
82
83/// Supertrait combining Encode + FastZeroizable for derive macro helpers.
84/// Used by encode_fields to zeroize all fields on error.
85pub trait EncodeZeroize: Encode + FastZeroizable {}
86impl<T: Encode + FastZeroizable> EncodeZeroize for T {}
87
88/// Supertrait combining Decode + FastZeroizable for derive macro helpers.
89/// Used by decode_fields to zeroize all fields on error.
90pub trait DecodeZeroize: Decode + FastZeroizable {}
91impl<T: Decode + FastZeroizable> DecodeZeroize for T {}