Skip to main content

zenjxl_decoder/image/
data_type.rs

1// Copyright (c) the JPEG XL Project Authors. All rights reserved.
2//
3// Use of this source code is governed by a BSD-style
4// license that can be found in the LICENSE file.
5
6use std::fmt::Debug;
7
8mod private {
9    pub trait Sealed {}
10}
11
12#[derive(Copy, Clone, PartialEq, Eq, Debug)]
13pub enum DataTypeTag {
14    U8,
15    U16,
16    U32,
17    F32,
18    I8,
19    I16,
20    I32,
21    F16,
22    F64,
23}
24
25impl DataTypeTag {
26    // Note that the const block below asserts that the implementation of this method is correct
27    // (as in, matches the size of the types that the tag corresponds to).
28    pub const fn size(&self) -> usize {
29        match self {
30            DataTypeTag::U8 | DataTypeTag::I8 => 1,
31            DataTypeTag::U16 | DataTypeTag::F16 | DataTypeTag::I16 => 2,
32            DataTypeTag::U32 | DataTypeTag::F32 | DataTypeTag::I32 => 4,
33            DataTypeTag::F64 => 8,
34        }
35    }
36}
37
38const _: () = {
39    assert!(std::mem::size_of::<i8>() == DataTypeTag::I8.size());
40    assert!(std::mem::size_of::<u8>() == DataTypeTag::U8.size());
41    assert!(std::mem::size_of::<i16>() == DataTypeTag::I16.size());
42    assert!(std::mem::size_of::<u16>() == DataTypeTag::U16.size());
43    assert!(std::mem::size_of::<crate::util::f16>() == DataTypeTag::F16.size());
44    assert!(std::mem::size_of::<i32>() == DataTypeTag::I32.size());
45    assert!(std::mem::size_of::<u32>() == DataTypeTag::U32.size());
46    assert!(std::mem::size_of::<f32>() == DataTypeTag::F32.size());
47    assert!(std::mem::size_of::<f64>() == DataTypeTag::F64.size());
48};
49
50/// Image data type trait. Implementors must be "bag-of-bits" types with no padding,
51/// guaranteed by the `bytemuck::Pod` bound.
52pub trait ImageDataType:
53    private::Sealed + bytemuck::Pod + Copy + Default + 'static + Debug + PartialEq + Send + Sync
54{
55    /// ID of this data type. Different types *must* have different values.
56    const DATA_TYPE_ID: DataTypeTag;
57
58    fn from_f64(f: f64) -> Self;
59    fn to_f64(self) -> f64;
60    #[cfg(test)]
61    fn random<R: rand::Rng>(rng: &mut R) -> Self;
62}
63
64#[cfg(test)]
65macro_rules! type_min {
66    (f32) => {
67        0.0f32
68    };
69    (f64) => {
70        0.0f64
71    };
72    ($ty: ty) => {
73        <$ty>::MIN
74    };
75}
76
77#[cfg(test)]
78macro_rules! type_max {
79    (f32) => {
80        1.0f32
81    };
82    (f64) => {
83        1.0f64
84    };
85    ($ty: ty) => {
86        <$ty>::MAX
87    };
88}
89
90macro_rules! impl_image_data_type {
91    ($ty: ident, $id: ident) => {
92        impl private::Sealed for $ty {}
93        impl ImageDataType for $ty {
94            const DATA_TYPE_ID: DataTypeTag = DataTypeTag::$id;
95            fn from_f64(f: f64) -> $ty {
96                f as $ty
97            }
98            fn to_f64(self) -> f64 {
99                self as f64
100            }
101            #[cfg(test)]
102            fn random<R: rand::Rng>(rng: &mut R) -> Self {
103                use rand::distr::{Distribution, Uniform};
104                let min = type_min!($ty);
105                let max = type_max!($ty);
106                Uniform::new_inclusive(min, max).unwrap().sample(rng)
107            }
108        }
109    };
110}
111
112impl_image_data_type!(u8, U8);
113impl_image_data_type!(u16, U16);
114impl_image_data_type!(u32, U32);
115impl_image_data_type!(f32, F32);
116impl_image_data_type!(i8, I8);
117impl_image_data_type!(i16, I16);
118impl_image_data_type!(i32, I32);
119
120// Meant to be used by the simple render pipeline and in general for
121// testing purposes.
122impl_image_data_type!(f64, F64);
123
124impl private::Sealed for crate::util::f16 {}
125impl ImageDataType for crate::util::f16 {
126    const DATA_TYPE_ID: DataTypeTag = DataTypeTag::F16;
127    fn from_f64(f: f64) -> crate::util::f16 {
128        crate::util::f16::from_f64(f)
129    }
130    fn to_f64(self) -> f64 {
131        crate::util::f16::to_f64(self)
132    }
133    #[cfg(test)]
134    fn random<R: rand::Rng>(rng: &mut R) -> Self {
135        use rand::distr::{Distribution, Uniform};
136        Self::from_f64(Uniform::new(0.0f32, 1.0f32).unwrap().sample(rng) as f64)
137    }
138}