Skip to main content

gamut_core/
lib.rs

1//! Core traits, image buffers, dimensions, and error types shared across the gamut codecs.
2//!
3//! This crate is dependency-free with respect to the format crates: every codec in the
4//! workspace builds on the [`Encoder`] / [`Decoder`] traits and the [`Error`] type defined
5//! here, so that callers get a single, consistent error surface regardless of format.
6#![forbid(unsafe_code)]
7
8/// Errors produced by gamut encoders and decoders.
9///
10/// Marked `#[non_exhaustive]` so additional variants can be added as formats land without a
11/// breaking change.
12#[derive(Debug, thiserror::Error)]
13#[non_exhaustive]
14pub enum Error {
15    /// The input data was malformed, truncated, or otherwise not valid for the format.
16    #[error("invalid input: {0}")]
17    InvalidInput(&'static str),
18    /// The requested format, profile, or feature is not yet supported.
19    #[error("unsupported: {0}")]
20    Unsupported(&'static str),
21}
22
23/// Convenience result type for gamut operations.
24pub type Result<T> = core::result::Result<T, Error>;
25
26/// Width and height of an image, in pixels.
27#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
28pub struct Dimensions {
29    /// Image width in pixels.
30    pub width: u32,
31    /// Image height in pixels.
32    pub height: u32,
33}
34
35/// Encodes an in-memory image into a compressed byte stream.
36///
37/// Implementations append the encoded bytes to `out` rather than allocating a fresh buffer,
38/// keeping hot paths allocation-conscious for callers that reuse a scratch buffer.
39pub trait Encoder {
40    /// Encode `pixels` (described by `dims`) into `out`, returning the number of bytes written.
41    ///
42    /// # Errors
43    ///
44    /// Returns [`Error::InvalidInput`] if `pixels` does not match `dims`, or
45    /// [`Error::Unsupported`] if the requested configuration is not implemented.
46    fn encode(&self, pixels: &[u8], dims: Dimensions, out: &mut Vec<u8>) -> Result<usize>;
47}
48
49/// Decodes a compressed byte stream into raw pixels.
50pub trait Decoder {
51    /// Decode `data` into `out`, returning the decoded image [`Dimensions`].
52    ///
53    /// # Errors
54    ///
55    /// Returns [`Error::InvalidInput`] if `data` is malformed, or [`Error::Unsupported`] if
56    /// the stream uses a feature that is not implemented.
57    fn decode(&self, data: &[u8], out: &mut Vec<u8>) -> Result<Dimensions>;
58}
59
60#[cfg(test)]
61mod tests {
62    use super::*;
63
64    #[test]
65    fn error_displays_and_dimensions_fields() {
66        assert!(!Error::Unsupported("x").to_string().is_empty());
67        assert!(!Error::InvalidInput("y").to_string().is_empty());
68        let d = Dimensions {
69            width: 1920,
70            height: 1080,
71        };
72        assert_eq!(d.width, 1920);
73        assert_eq!(d.height, 1080);
74    }
75}