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}