Skip to main content

craft_codec/
codec.rs

1use crate::{
2    CompressionCodec, Config, EncryptionCodec, Error, FrameSizes, FrameSpec, Framing, Result,
3};
4
5/// Zero-sized identity transform, usable for compression, encryption, or both.
6#[derive(Clone, Copy, Debug, Default)]
7pub struct Identity;
8impl crate::sealed::Sealed for Identity {}
9
10/// Synchronous, statically dispatched frame encoder with reusable codec storage.
11///
12/// The caller owns the frame index and must never encrypt different payloads
13/// with the same key/index. Use a fresh key for each immutable object. This
14/// type performs no I/O, scheduling, implicit indexing, or retries.
15pub struct Encoder<C = Identity, E = Identity> {
16    config: Config,
17    compression: C,
18    encryption: E,
19}
20
21impl<C: CompressionCodec, E: EncryptionCodec> Encoder<C, E> {
22    /// Create an encoder. Codec types determine the metadata profile.
23    pub fn new(framing: Framing, compression: C, encryption: E) -> Result<Self> {
24        let config = Config::new(framing, C::FORMAT, E::FORMAT)?;
25        Ok(Self {
26            config,
27            compression,
28            encryption,
29        })
30    }
31
32    /// Settings to use when constructing the object's metadata.
33    pub fn config(&self) -> Config {
34        self.config
35    }
36
37    /// Replace raw bytes with stored bytes, returning lengths to append to metadata.
38    /// Empty/oversized frames and out-of-policy indices are refused.
39    /// On any error the buffer is cleared, but its allocation is retained.
40    ///
41    /// This does not append metadata: the caller does that after successful I/O.
42    /// The metadata builder enforces that a short fixed frame is the last frame.
43    pub fn encode_frame(&mut self, index: u64, buffer: &mut Vec<u8>) -> Result<FrameSizes> {
44        let result = self.encode_inner(index, buffer);
45        if result.is_err() {
46            buffer.clear();
47        }
48        result
49    }
50
51    fn encode_inner(&mut self, index: u64, buffer: &mut Vec<u8>) -> Result<FrameSizes> {
52        let raw = buffer.len() as u64;
53        self.config.validate_frame(index, raw, raw)?;
54        self.compression.encode(buffer)?;
55        let payload = buffer.len() as u64;
56        self.encryption.seal(index, buffer)?;
57        Ok(FrameSizes { raw, payload })
58    }
59}
60
61/// Synchronous frame decoder. It knows no logical ranges or I/O offsets.
62/// Authentication precedes decompression. Reuse one instance and the caller's
63/// buffer to amortize allocations. Compression may swap the buffer allocation.
64pub struct Decoder<C = Identity, E = Identity> {
65    config: Config,
66    compression: C,
67    encryption: E,
68}
69
70impl<C: CompressionCodec, E: EncryptionCodec> Decoder<C, E> {
71    /// Create a decoder matching the object's metadata and the supplied key.
72    pub fn new(config: Config, compression: C, encryption: E) -> Result<Self> {
73        if config.compression() != C::FORMAT || config.encryption() != E::FORMAT {
74            return Err(Error::ProfileMismatch);
75        }
76        Ok(Self {
77            config,
78            compression,
79            encryption,
80        })
81    }
82
83    /// Replace one complete stored frame with its complete decoded bytes.
84    /// On failure the buffer is cleared. No unauthenticated bytes are returned.
85    /// Clearing the buffer is not a promise to zero its allocation or scratch.
86    pub fn decode_frame(&mut self, spec: FrameSpec, buffer: &mut Vec<u8>) -> Result<()> {
87        let result = self.decode_inner(spec, buffer);
88        if result.is_err() {
89            buffer.clear();
90        }
91        result
92    }
93
94    fn decode_inner(&mut self, spec: FrameSpec, buffer: &mut Vec<u8>) -> Result<()> {
95        if spec.config != self.config {
96            return Err(Error::ProfileMismatch);
97        }
98        if buffer.len() != spec.stored_len() {
99            return Err(Error::InvalidStoredLength);
100        }
101        self.encryption.open(spec.index(), buffer)?;
102        if spec.payload_len() < spec.raw_len() {
103            self.compression.decode(buffer, spec.raw_len())?;
104        }
105        if buffer.len() != spec.raw_len() {
106            return Err(Error::DecompressionFailed);
107        }
108        Ok(())
109    }
110}