Skip to main content

craft_codec/
codec.rs

1use crate::{Config, Error, FrameSizes, FrameSpec, Metadata, Result};
2use crate::{compression::CompressionState, crypto::EncryptionState};
3
4/// Synchronous frame encoder constructed entirely from metadata with reusable codec storage.
5///
6/// The caller owns the frame index and must never encrypt different payloads
7/// with the same key/index. Use a fresh key for each immutable object. This
8/// type performs no I/O, scheduling, implicit indexing, or retries.
9pub struct Encoder {
10    config: Config,
11    compression: CompressionState,
12    encryption: EncryptionState,
13}
14
15impl TryFrom<&Metadata> for Encoder {
16    type Error = Error;
17
18    fn try_from(metadata: &Metadata) -> Result<Self> {
19        let config = metadata.config().clone();
20        Ok(Self {
21            compression: CompressionState::new(config.compression())?,
22            encryption: EncryptionState::new(config.encryption())?,
23            config,
24        })
25    }
26}
27
28impl TryFrom<Metadata> for Encoder {
29    type Error = Error;
30
31    fn try_from(metadata: Metadata) -> Result<Self> {
32        Self::try_from(&metadata)
33    }
34}
35
36impl Encoder {
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    /// Encode raw bytes into an owned buffer, leaving the input unchanged.
52    /// Return the stored bytes and lengths to append to metadata.
53    /// Empty/oversized frames and out-of-policy indices are refused.
54    /// Allocation and encoding failures are returned as errors.
55    pub fn encode_frame_alloc(
56        &mut self,
57        index: u64,
58        buffer: &[u8],
59    ) -> Result<(Vec<u8>, FrameSizes)> {
60        let capacity = buffer
61            .len()
62            .checked_add(self.encryption.overhead())
63            .ok_or(Error::Overflow)?;
64        let mut encoded = Vec::new();
65        encoded
66            .try_reserve(capacity)
67            .map_err(|_| Error::Allocation)?;
68        encoded.extend_from_slice(buffer);
69        let sizes = self.encode_frame(index, &mut encoded)?;
70        Ok((encoded, sizes))
71    }
72
73    fn encode_inner(&mut self, index: u64, buffer: &mut Vec<u8>) -> Result<FrameSizes> {
74        let raw = buffer.len() as u64;
75        self.config.validate_frame(index, raw, raw)?;
76        self.compression.encode(buffer)?;
77        let payload = buffer.len() as u64;
78        self.encryption.seal(index, buffer)?;
79        Ok(FrameSizes { raw, payload })
80    }
81}
82
83/// Synchronous frame decoder. It knows no logical ranges or I/O offsets.
84/// Authentication precedes decompression. Reuse one instance and the caller's
85/// buffer to amortize allocations. Compression may swap the buffer allocation.
86pub struct Decoder {
87    config: Config,
88    compression: CompressionState,
89    encryption: EncryptionState,
90}
91
92impl TryFrom<&Metadata> for Decoder {
93    type Error = Error;
94
95    fn try_from(metadata: &Metadata) -> Result<Self> {
96        let config = metadata.config().clone();
97        Ok(Self {
98            compression: CompressionState::new(config.compression())?,
99            encryption: EncryptionState::new(config.encryption())?,
100            config,
101        })
102    }
103}
104
105impl TryFrom<Metadata> for Decoder {
106    type Error = Error;
107
108    fn try_from(metadata: Metadata) -> Result<Self> {
109        Self::try_from(&metadata)
110    }
111}
112
113impl Decoder {
114    /// Replace one complete stored frame with its complete decoded bytes.
115    /// On failure the buffer is cleared. No unauthenticated bytes are returned.
116    /// Clearing the buffer is not a promise to zero its allocation or scratch.
117    pub fn decode_frame(&mut self, spec: FrameSpec, buffer: &mut Vec<u8>) -> Result<()> {
118        let result = self.decode_inner(spec, buffer);
119        if result.is_err() {
120            buffer.clear();
121        }
122        result
123    }
124
125    fn decode_inner(&mut self, spec: FrameSpec, buffer: &mut Vec<u8>) -> Result<()> {
126        if spec.config != self.config {
127            return Err(Error::ProfileMismatch);
128        }
129        if buffer.len() != spec.stored_len() {
130            return Err(Error::InvalidStoredLength);
131        }
132        self.encryption.open(spec.index(), buffer)?;
133        if spec.payload_len() < spec.raw_len() {
134            self.compression.decode(buffer, spec.raw_len())?;
135        }
136        if buffer.len() != spec.raw_len() {
137            return Err(Error::DecompressionFailed);
138        }
139        Ok(())
140    }
141}