use crate::pixel::{
BoundedChannel, FromLinear, HomogeneousPixel, LinearChannel, MonoF32, MonoF64, PlainChannel,
PlainPixel, ZeroablePixel,
};
use std::num::Saturating;
unsafe impl PlainChannel for u8 {}
unsafe impl PlainChannel for u16 {}
unsafe impl PlainChannel for u32 {}
unsafe impl PlainChannel for u64 {}
unsafe impl PlainChannel for i8 {}
unsafe impl PlainChannel for i16 {}
unsafe impl PlainChannel for i32 {}
unsafe impl PlainChannel for i64 {}
unsafe impl PlainChannel for f32 {}
unsafe impl PlainChannel for f64 {}
unsafe impl<T: PlainChannel> PlainChannel for Saturating<T> {}
unsafe impl PlainPixel for u8 {
const CHANNELS: &'static [usize] = &[1];
}
impl ZeroablePixel for u8 {
fn zero() -> Self {
0
}
}
impl FromLinear<f32> for u8 {
#[inline(always)]
fn from_linear(acc: f32) -> Self {
acc.round().clamp(0.0, u8::MAX as f32) as u8
}
}
impl FromLinear<MonoF32> for u8 {
#[inline(always)]
fn from_linear(acc: MonoF32) -> Self {
<Self as FromLinear<f32>>::from_linear(acc.0)
}
}
unsafe impl HomogeneousPixel for u8 {
type Channel = u8;
type Channels = [u8; 1];
}
unsafe impl PlainPixel for u16 {
const CHANNELS: &'static [usize] = &[2];
}
impl ZeroablePixel for u16 {
fn zero() -> Self {
0
}
}
impl FromLinear<f32> for u16 {
#[inline(always)]
fn from_linear(acc: f32) -> Self {
acc.round().clamp(0.0, u16::MAX as f32) as u16
}
}
impl FromLinear<MonoF32> for u16 {
#[inline(always)]
fn from_linear(acc: MonoF32) -> Self {
<Self as FromLinear<f32>>::from_linear(acc.0)
}
}
unsafe impl HomogeneousPixel for u16 {
type Channel = u16;
type Channels = [u16; 1];
}
unsafe impl PlainPixel for u32 {
const CHANNELS: &'static [usize] = &[4];
}
impl ZeroablePixel for u32 {
fn zero() -> Self {
0
}
}
impl FromLinear<f64> for u32 {
#[inline(always)]
fn from_linear(acc: f64) -> Self {
acc.round().clamp(0.0, u32::MAX as f64) as u32
}
}
impl FromLinear<MonoF64> for u32 {
#[inline(always)]
fn from_linear(acc: MonoF64) -> Self {
<Self as FromLinear<f64>>::from_linear(acc.0)
}
}
unsafe impl HomogeneousPixel for u32 {
type Channel = u32;
type Channels = [u32; 1];
}
unsafe impl PlainPixel for u64 {
const CHANNELS: &'static [usize] = &[8];
}
impl ZeroablePixel for u64 {
fn zero() -> Self {
0
}
}
impl FromLinear<f64> for u64 {
#[inline(always)]
fn from_linear(acc: f64) -> Self {
acc.round().clamp(0.0, u64::MAX as f64) as u64
}
}
impl FromLinear<MonoF64> for u64 {
#[inline(always)]
fn from_linear(acc: MonoF64) -> Self {
<Self as FromLinear<f64>>::from_linear(acc.0)
}
}
unsafe impl HomogeneousPixel for u64 {
type Channel = u64;
type Channels = [u64; 1];
}
unsafe impl PlainPixel for i8 {
const CHANNELS: &'static [usize] = &[1];
}
impl ZeroablePixel for i8 {
fn zero() -> Self {
0
}
}
unsafe impl HomogeneousPixel for i8 {
type Channel = i8;
type Channels = [i8; 1];
}
unsafe impl PlainPixel for i16 {
const CHANNELS: &'static [usize] = &[2];
}
impl ZeroablePixel for i16 {
fn zero() -> Self {
0
}
}
unsafe impl HomogeneousPixel for i16 {
type Channel = i16;
type Channels = [i16; 1];
}
unsafe impl PlainPixel for i32 {
const CHANNELS: &'static [usize] = &[4];
}
impl ZeroablePixel for i32 {
fn zero() -> Self {
0
}
}
unsafe impl HomogeneousPixel for i32 {
type Channel = i32;
type Channels = [i32; 1];
}
unsafe impl PlainPixel for i64 {
const CHANNELS: &'static [usize] = &[8];
}
impl ZeroablePixel for i64 {
fn zero() -> Self {
0
}
}
unsafe impl HomogeneousPixel for i64 {
type Channel = i64;
type Channels = [i64; 1];
}
unsafe impl<T> PlainPixel for Saturating<T>
where
T: PlainPixel,
{
const CHANNELS: &'static [usize] = T::CHANNELS;
}
impl<T: ZeroablePixel> ZeroablePixel for Saturating<T> {
fn zero() -> Self {
Saturating(T::zero())
}
}
impl FromLinear<f32> for Saturating<u8> {
#[inline(always)]
fn from_linear(acc: f32) -> Self {
Saturating(acc.round().clamp(0.0, u8::MAX as f32) as u8)
}
}
impl FromLinear<MonoF32> for Saturating<u8> {
#[inline(always)]
fn from_linear(acc: MonoF32) -> Self {
<Self as FromLinear<f32>>::from_linear(acc.0)
}
}
impl FromLinear<f32> for Saturating<u16> {
#[inline(always)]
fn from_linear(acc: f32) -> Self {
Saturating(acc.round().clamp(0.0, u16::MAX as f32) as u16)
}
}
impl FromLinear<MonoF32> for Saturating<u16> {
#[inline(always)]
fn from_linear(acc: MonoF32) -> Self {
<Self as FromLinear<f32>>::from_linear(acc.0)
}
}
impl FromLinear<f64> for Saturating<u32> {
#[inline(always)]
fn from_linear(acc: f64) -> Self {
Saturating(acc.round().clamp(0.0, u32::MAX as f64) as u32)
}
}
impl FromLinear<MonoF64> for Saturating<u32> {
#[inline(always)]
fn from_linear(acc: MonoF64) -> Self {
<Self as FromLinear<f64>>::from_linear(acc.0)
}
}
impl FromLinear<f64> for Saturating<u64> {
#[inline(always)]
fn from_linear(acc: f64) -> Self {
Saturating(acc.round().clamp(0.0, u64::MAX as f64) as u64)
}
}
impl FromLinear<MonoF64> for Saturating<u64> {
#[inline(always)]
fn from_linear(acc: MonoF64) -> Self {
<Self as FromLinear<f64>>::from_linear(acc.0)
}
}
impl LinearChannel<f32> for u8 {
type Accumulator = f32;
#[inline(always)]
fn to_accumulator(&self) -> f32 {
*self as f32
}
#[inline(always)]
fn scale(&self, scalar: f32) -> f32 {
*self as f32 * scalar
}
#[inline(always)]
fn scale_add(&self, scalar: f32, addend: f32) -> f32 {
#[cfg(target_feature = "fma")]
{
(*self as f32).mul_add(scalar, addend)
}
#[cfg(not(target_feature = "fma"))]
{
*self as f32 * scalar + addend
}
}
#[inline(always)]
fn uniform(scalar: f32) -> f32 {
scalar
}
}
impl LinearChannel<f32> for u16 {
type Accumulator = f32;
#[inline(always)]
fn to_accumulator(&self) -> f32 {
*self as f32
}
#[inline(always)]
fn scale(&self, scalar: f32) -> f32 {
*self as f32 * scalar
}
#[inline(always)]
fn scale_add(&self, scalar: f32, addend: f32) -> f32 {
#[cfg(target_feature = "fma")]
{
(*self as f32).mul_add(scalar, addend)
}
#[cfg(not(target_feature = "fma"))]
{
*self as f32 * scalar + addend
}
}
#[inline(always)]
fn uniform(scalar: f32) -> f32 {
scalar
}
}
impl LinearChannel<f32> for u32 {
type Accumulator = f64;
#[inline(always)]
fn to_accumulator(&self) -> f64 {
*self as f64
}
#[inline(always)]
fn scale(&self, scalar: f32) -> f64 {
*self as f64 * scalar as f64
}
#[inline(always)]
fn scale_add(&self, scalar: f32, addend: f64) -> f64 {
#[cfg(target_feature = "fma")]
{
(*self as f64).mul_add(scalar as f64, addend)
}
#[cfg(not(target_feature = "fma"))]
{
*self as f64 * scalar as f64 + addend
}
}
#[inline(always)]
fn uniform(scalar: f32) -> f64 {
scalar as f64
}
}
impl LinearChannel<f64> for u32 {
type Accumulator = f64;
#[inline(always)]
fn to_accumulator(&self) -> f64 {
*self as f64
}
#[inline(always)]
fn scale(&self, scalar: f64) -> f64 {
*self as f64 * scalar
}
#[inline(always)]
fn scale_add(&self, scalar: f64, addend: f64) -> f64 {
#[cfg(target_feature = "fma")]
{
(*self as f64).mul_add(scalar, addend)
}
#[cfg(not(target_feature = "fma"))]
{
*self as f64 * scalar + addend
}
}
#[inline(always)]
fn uniform(scalar: f64) -> f64 {
scalar
}
}
impl LinearChannel<f32> for u64 {
type Accumulator = f64;
#[inline(always)]
fn to_accumulator(&self) -> f64 {
*self as f64
}
#[inline(always)]
fn scale(&self, scalar: f32) -> f64 {
*self as f64 * scalar as f64
}
#[inline(always)]
fn scale_add(&self, scalar: f32, addend: f64) -> f64 {
#[cfg(target_feature = "fma")]
{
(*self as f64).mul_add(scalar as f64, addend)
}
#[cfg(not(target_feature = "fma"))]
{
*self as f64 * scalar as f64 + addend
}
}
#[inline(always)]
fn uniform(scalar: f32) -> f64 {
scalar as f64
}
}
impl LinearChannel<f64> for u64 {
type Accumulator = f64;
#[inline(always)]
fn to_accumulator(&self) -> f64 {
*self as f64
}
#[inline(always)]
fn scale(&self, scalar: f64) -> f64 {
*self as f64 * scalar
}
#[inline(always)]
fn scale_add(&self, scalar: f64, addend: f64) -> f64 {
#[cfg(target_feature = "fma")]
{
(*self as f64).mul_add(scalar, addend)
}
#[cfg(not(target_feature = "fma"))]
{
*self as f64 * scalar + addend
}
}
#[inline(always)]
fn uniform(scalar: f64) -> f64 {
scalar
}
}
impl LinearChannel<f32> for i8 {
type Accumulator = f32;
#[inline(always)]
fn to_accumulator(&self) -> f32 {
*self as f32
}
#[inline(always)]
fn scale(&self, scalar: f32) -> f32 {
*self as f32 * scalar
}
#[inline(always)]
fn scale_add(&self, scalar: f32, addend: f32) -> f32 {
#[cfg(target_feature = "fma")]
{
(*self as f32).mul_add(scalar, addend)
}
#[cfg(not(target_feature = "fma"))]
{
*self as f32 * scalar + addend
}
}
#[inline(always)]
fn uniform(scalar: f32) -> f32 {
scalar
}
}
impl LinearChannel<f32> for i16 {
type Accumulator = f32;
#[inline(always)]
fn to_accumulator(&self) -> f32 {
*self as f32
}
#[inline(always)]
fn scale(&self, scalar: f32) -> f32 {
*self as f32 * scalar
}
#[inline(always)]
fn scale_add(&self, scalar: f32, addend: f32) -> f32 {
#[cfg(target_feature = "fma")]
{
(*self as f32).mul_add(scalar, addend)
}
#[cfg(not(target_feature = "fma"))]
{
*self as f32 * scalar + addend
}
}
#[inline(always)]
fn uniform(scalar: f32) -> f32 {
scalar
}
}
impl LinearChannel<f32> for i32 {
type Accumulator = f64;
#[inline(always)]
fn to_accumulator(&self) -> f64 {
*self as f64
}
#[inline(always)]
fn scale(&self, scalar: f32) -> f64 {
*self as f64 * scalar as f64
}
#[inline(always)]
fn scale_add(&self, scalar: f32, addend: f64) -> f64 {
#[cfg(target_feature = "fma")]
{
(*self as f64).mul_add(scalar as f64, addend)
}
#[cfg(not(target_feature = "fma"))]
{
*self as f64 * scalar as f64 + addend
}
}
#[inline(always)]
fn uniform(scalar: f32) -> f64 {
scalar as f64
}
}
impl LinearChannel<f64> for i32 {
type Accumulator = f64;
#[inline(always)]
fn to_accumulator(&self) -> f64 {
*self as f64
}
#[inline(always)]
fn scale(&self, scalar: f64) -> f64 {
*self as f64 * scalar
}
#[inline(always)]
fn scale_add(&self, scalar: f64, addend: f64) -> f64 {
#[cfg(target_feature = "fma")]
{
(*self as f64).mul_add(scalar, addend)
}
#[cfg(not(target_feature = "fma"))]
{
*self as f64 * scalar + addend
}
}
#[inline(always)]
fn uniform(scalar: f64) -> f64 {
scalar
}
}
impl LinearChannel<f32> for i64 {
type Accumulator = f64;
#[inline(always)]
fn to_accumulator(&self) -> f64 {
*self as f64
}
#[inline(always)]
fn scale(&self, scalar: f32) -> f64 {
*self as f64 * scalar as f64
}
#[inline(always)]
fn scale_add(&self, scalar: f32, addend: f64) -> f64 {
#[cfg(target_feature = "fma")]
{
(*self as f64).mul_add(scalar as f64, addend)
}
#[cfg(not(target_feature = "fma"))]
{
*self as f64 * scalar as f64 + addend
}
}
#[inline(always)]
fn uniform(scalar: f32) -> f64 {
scalar as f64
}
}
impl LinearChannel<f64> for i64 {
type Accumulator = f64;
#[inline(always)]
fn to_accumulator(&self) -> f64 {
*self as f64
}
#[inline(always)]
fn scale(&self, scalar: f64) -> f64 {
*self as f64 * scalar
}
#[inline(always)]
fn scale_add(&self, scalar: f64, addend: f64) -> f64 {
#[cfg(target_feature = "fma")]
{
(*self as f64).mul_add(scalar, addend)
}
#[cfg(not(target_feature = "fma"))]
{
*self as f64 * scalar + addend
}
}
#[inline(always)]
fn uniform(scalar: f64) -> f64 {
scalar
}
}
impl LinearChannel<f32> for f32 {
type Accumulator = f32;
#[inline(always)]
fn to_accumulator(&self) -> f32 {
*self
}
#[inline(always)]
fn scale(&self, scalar: f32) -> f32 {
*self * scalar
}
#[inline(always)]
fn scale_add(&self, scalar: f32, addend: f32) -> f32 {
#[cfg(target_feature = "fma")]
{
self.mul_add(scalar, addend)
}
#[cfg(not(target_feature = "fma"))]
{
*self * scalar + addend
}
}
#[inline(always)]
fn uniform(scalar: f32) -> f32 {
scalar
}
}
impl LinearChannel<f32> for f64 {
type Accumulator = f64;
#[inline(always)]
fn to_accumulator(&self) -> f64 {
*self
}
#[inline(always)]
fn scale(&self, scalar: f32) -> f64 {
*self * scalar as f64
}
#[inline(always)]
fn scale_add(&self, scalar: f32, addend: f64) -> f64 {
#[cfg(target_feature = "fma")]
{
self.mul_add(scalar as f64, addend)
}
#[cfg(not(target_feature = "fma"))]
{
*self * scalar as f64 + addend
}
}
#[inline(always)]
fn uniform(scalar: f32) -> f64 {
scalar as f64
}
}
impl LinearChannel<f64> for f64 {
type Accumulator = f64;
#[inline(always)]
fn to_accumulator(&self) -> f64 {
*self
}
#[inline(always)]
fn scale(&self, scalar: f64) -> f64 {
*self * scalar
}
#[inline(always)]
fn scale_add(&self, scalar: f64, addend: f64) -> f64 {
#[cfg(target_feature = "fma")]
{
self.mul_add(scalar, addend)
}
#[cfg(not(target_feature = "fma"))]
{
*self * scalar + addend
}
}
#[inline(always)]
fn uniform(scalar: f64) -> f64 {
scalar
}
}
impl LinearChannel<f32> for Saturating<u8> {
type Accumulator = f32;
#[inline(always)]
fn to_accumulator(&self) -> f32 {
self.0 as f32
}
#[inline(always)]
fn scale(&self, scalar: f32) -> f32 {
self.0 as f32 * scalar
}
#[inline(always)]
fn scale_add(&self, scalar: f32, addend: f32) -> f32 {
#[cfg(target_feature = "fma")]
{
(self.0 as f32).mul_add(scalar, addend)
}
#[cfg(not(target_feature = "fma"))]
{
self.0 as f32 * scalar + addend
}
}
#[inline(always)]
fn uniform(scalar: f32) -> f32 {
scalar
}
}
impl LinearChannel<f32> for Saturating<u16> {
type Accumulator = f32;
#[inline(always)]
fn to_accumulator(&self) -> f32 {
self.0 as f32
}
#[inline(always)]
fn scale(&self, scalar: f32) -> f32 {
self.0 as f32 * scalar
}
#[inline(always)]
fn scale_add(&self, scalar: f32, addend: f32) -> f32 {
#[cfg(target_feature = "fma")]
{
(self.0 as f32).mul_add(scalar, addend)
}
#[cfg(not(target_feature = "fma"))]
{
self.0 as f32 * scalar + addend
}
}
#[inline(always)]
fn uniform(scalar: f32) -> f32 {
scalar
}
}
impl LinearChannel<f32> for Saturating<u32> {
type Accumulator = f64;
#[inline(always)]
fn to_accumulator(&self) -> f64 {
self.0 as f64
}
#[inline(always)]
fn scale(&self, scalar: f32) -> f64 {
self.0 as f64 * scalar as f64
}
#[inline(always)]
fn scale_add(&self, scalar: f32, addend: f64) -> f64 {
#[cfg(target_feature = "fma")]
{
(self.0 as f64).mul_add(scalar as f64, addend)
}
#[cfg(not(target_feature = "fma"))]
{
self.0 as f64 * scalar as f64 + addend
}
}
#[inline(always)]
fn uniform(scalar: f32) -> f64 {
scalar as f64
}
}
impl LinearChannel<f64> for Saturating<u32> {
type Accumulator = f64;
#[inline(always)]
fn to_accumulator(&self) -> f64 {
self.0 as f64
}
#[inline(always)]
fn scale(&self, scalar: f64) -> f64 {
self.0 as f64 * scalar
}
#[inline(always)]
fn scale_add(&self, scalar: f64, addend: f64) -> f64 {
#[cfg(target_feature = "fma")]
{
(self.0 as f64).mul_add(scalar, addend)
}
#[cfg(not(target_feature = "fma"))]
{
self.0 as f64 * scalar + addend
}
}
#[inline(always)]
fn uniform(scalar: f64) -> f64 {
scalar
}
}
impl LinearChannel<f32> for Saturating<u64> {
type Accumulator = f64;
#[inline(always)]
fn to_accumulator(&self) -> f64 {
self.0 as f64
}
#[inline(always)]
fn scale(&self, scalar: f32) -> f64 {
self.0 as f64 * scalar as f64
}
#[inline(always)]
fn scale_add(&self, scalar: f32, addend: f64) -> f64 {
#[cfg(target_feature = "fma")]
{
(self.0 as f64).mul_add(scalar as f64, addend)
}
#[cfg(not(target_feature = "fma"))]
{
self.0 as f64 * scalar as f64 + addend
}
}
#[inline(always)]
fn uniform(scalar: f32) -> f64 {
scalar as f64
}
}
impl LinearChannel<f64> for Saturating<u64> {
type Accumulator = f64;
#[inline(always)]
fn to_accumulator(&self) -> f64 {
self.0 as f64
}
#[inline(always)]
fn scale(&self, scalar: f64) -> f64 {
self.0 as f64 * scalar
}
#[inline(always)]
fn scale_add(&self, scalar: f64, addend: f64) -> f64 {
#[cfg(target_feature = "fma")]
{
(self.0 as f64).mul_add(scalar, addend)
}
#[cfg(not(target_feature = "fma"))]
{
self.0 as f64 * scalar + addend
}
}
#[inline(always)]
fn uniform(scalar: f64) -> f64 {
scalar
}
}
impl BoundedChannel for u8 {
const MAX: Self = u8::MAX;
}
impl BoundedChannel for u16 {
const MAX: Self = u16::MAX;
}
impl BoundedChannel for u32 {
const MAX: Self = u32::MAX;
}
impl BoundedChannel for u64 {
const MAX: Self = u64::MAX;
}
impl<T: BoundedChannel> BoundedChannel for Saturating<T> {
const MAX: Self = Saturating(T::MAX);
}
impl ZeroablePixel for bool {
fn zero() -> Self {
false
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn bounded_channel_unsigned_primitives() {
assert_eq!(<u8 as BoundedChannel>::MAX, u8::MAX);
assert_eq!(<u16 as BoundedChannel>::MAX, u16::MAX);
assert_eq!(<u32 as BoundedChannel>::MAX, u32::MAX);
assert_eq!(<u64 as BoundedChannel>::MAX, u64::MAX);
}
#[test]
fn bounded_channel_saturating_wraps() {
assert_eq!(<Saturating<u8> as BoundedChannel>::MAX, Saturating(u8::MAX));
assert_eq!(
<Saturating<u16> as BoundedChannel>::MAX,
Saturating(u16::MAX)
);
assert_eq!(
<Saturating<u32> as BoundedChannel>::MAX,
Saturating(u32::MAX)
);
assert_eq!(
<Saturating<u64> as BoundedChannel>::MAX,
Saturating(u64::MAX)
);
}
#[test]
fn bounded_channel_u8_is_255() {
assert_eq!(<u8 as BoundedChannel>::MAX, 255);
assert_eq!(<Saturating<u8> as BoundedChannel>::MAX, Saturating(255u8));
}
#[test]
fn bounded_channel_inventory() {
fn assert_bounded<T: BoundedChannel>() {}
assert_bounded::<u8>();
assert_bounded::<u16>();
assert_bounded::<u32>();
assert_bounded::<u64>();
assert_bounded::<Saturating<u8>>();
assert_bounded::<Saturating<u16>>();
assert_bounded::<Saturating<u32>>();
assert_bounded::<Saturating<u64>>();
}
#[test]
fn linear_channel_uniform_f32_accumulator_primitives() {
assert_eq!(<u8 as LinearChannel>::uniform(0.5), 0.5f32);
assert_eq!(<u16 as LinearChannel>::uniform(0.5), 0.5f32);
assert_eq!(<i8 as LinearChannel>::uniform(0.25), 0.25f32);
assert_eq!(<i16 as LinearChannel>::uniform(0.25), 0.25f32);
assert_eq!(<f32 as LinearChannel>::uniform(42.0), 42.0f32);
assert_eq!(<Saturating<u8> as LinearChannel>::uniform(0.5), 0.5f32);
assert_eq!(<Saturating<u16> as LinearChannel>::uniform(0.5), 0.5f32);
}
#[test]
fn linear_channel_uniform_f64_accumulator_primitives() {
assert_eq!(<u32 as LinearChannel>::uniform(0.5), 0.5f64);
assert_eq!(<u64 as LinearChannel>::uniform(0.5), 0.5f64);
assert_eq!(<i32 as LinearChannel>::uniform(0.25), 0.25f64);
assert_eq!(<i64 as LinearChannel>::uniform(0.25), 0.25f64);
assert_eq!(<f64 as LinearChannel>::uniform(42.0), 42.0f64);
assert_eq!(<Saturating<u32> as LinearChannel>::uniform(0.5), 0.5f64);
assert_eq!(<Saturating<u64> as LinearChannel>::uniform(0.5), 0.5f64);
}
#[test]
fn linear_channel_uniform_zero_and_negative() {
assert_eq!(<f32 as LinearChannel>::uniform(0.0), 0.0f32);
assert_eq!(<f32 as LinearChannel>::uniform(-1.5), -1.5f32);
assert_eq!(<f64 as LinearChannel>::uniform(-1.5), -1.5f64);
assert_eq!(<u8 as LinearChannel>::uniform(0.0), 0.0f32);
}
#[test]
fn linear_channel_f64_scalar_u32_u64() {
let a: u32 = 1_000_000;
assert_eq!(
<u32 as LinearChannel<f64>>::to_accumulator(&a),
1_000_000.0f64
);
let s = <u32 as LinearChannel<f64>>::scale(&a, 0.5);
assert_eq!(s, 500_000.0f64);
let sa = <u32 as LinearChannel<f64>>::scale_add(&a, 0.5, 10.0);
assert_eq!(sa, 500_010.0f64);
assert_eq!(<u32 as LinearChannel<f64>>::uniform(42.0), 42.0f64);
let b: u64 = 2_000_000;
assert_eq!(
<u64 as LinearChannel<f64>>::to_accumulator(&b),
2_000_000.0f64
);
assert_eq!(<u64 as LinearChannel<f64>>::scale(&b, 0.25), 500_000.0f64);
assert_eq!(
<u64 as LinearChannel<f64>>::scale_add(&b, 0.25, -5.0),
499_995.0f64
);
assert_eq!(<u64 as LinearChannel<f64>>::uniform(-7.5), -7.5f64);
}
#[test]
fn linear_channel_f64_scalar_i32_i64() {
let a: i32 = -1000;
assert_eq!(<i32 as LinearChannel<f64>>::to_accumulator(&a), -1000.0f64);
assert_eq!(<i32 as LinearChannel<f64>>::scale(&a, 2.0), -2000.0f64);
assert_eq!(
<i32 as LinearChannel<f64>>::scale_add(&a, 2.0, 100.0),
-1900.0f64
);
assert_eq!(<i32 as LinearChannel<f64>>::uniform(0.125), 0.125f64);
let b: i64 = -2000;
assert_eq!(<i64 as LinearChannel<f64>>::to_accumulator(&b), -2000.0f64);
assert_eq!(<i64 as LinearChannel<f64>>::scale(&b, 0.5), -1000.0f64);
assert_eq!(
<i64 as LinearChannel<f64>>::scale_add(&b, 0.5, 1.0),
-999.0f64
);
assert_eq!(<i64 as LinearChannel<f64>>::uniform(9.0), 9.0f64);
}
#[test]
fn linear_channel_f64_scalar_f64() {
let a: f64 = 3.5;
assert_eq!(<f64 as LinearChannel<f64>>::to_accumulator(&a), 3.5);
assert_eq!(<f64 as LinearChannel<f64>>::scale(&a, 2.0), 7.0);
assert_eq!(<f64 as LinearChannel<f64>>::scale_add(&a, 2.0, 1.0), 8.0);
assert_eq!(<f64 as LinearChannel<f64>>::uniform(0.5), 0.5f64);
}
#[test]
fn linear_channel_f64_scalar_saturating_u32_u64() {
let a = Saturating(50_000u32);
assert_eq!(
<Saturating<u32> as LinearChannel<f64>>::to_accumulator(&a),
50_000.0f64
);
assert_eq!(
<Saturating<u32> as LinearChannel<f64>>::scale(&a, 0.5),
25_000.0f64
);
assert_eq!(
<Saturating<u32> as LinearChannel<f64>>::scale_add(&a, 0.5, 7.0),
25_007.0f64
);
assert_eq!(
<Saturating<u32> as LinearChannel<f64>>::uniform(1.25),
1.25f64
);
let b = Saturating(2_000_000u64);
assert_eq!(
<Saturating<u64> as LinearChannel<f64>>::to_accumulator(&b),
2_000_000.0f64
);
assert_eq!(
<Saturating<u64> as LinearChannel<f64>>::scale(&b, 0.1),
200_000.0f64
);
assert_eq!(
<Saturating<u64> as LinearChannel<f64>>::uniform(-2.5),
-2.5f64
);
}
#[test]
fn linear_channel_f64_scalar_matches_f32_scalar_on_same_input() {
let a: u32 = 1000;
let via_f32 = <u32 as LinearChannel<f32>>::scale(&a, 0.5);
let via_f64 = <u32 as LinearChannel<f64>>::scale(&a, 0.5);
assert_eq!(via_f32, 500.0f64);
assert_eq!(via_f64, 500.0f64);
assert_eq!(via_f32, via_f64);
}
#[test]
fn linear_channel_inventory() {
fn assert_channel_f32<T: LinearChannel<f32>>() {}
fn assert_channel_f64<T: LinearChannel<f64>>() {}
assert_channel_f32::<u8>();
assert_channel_f32::<u16>();
assert_channel_f32::<u32>();
assert_channel_f32::<u64>();
assert_channel_f32::<i8>();
assert_channel_f32::<i16>();
assert_channel_f32::<i32>();
assert_channel_f32::<i64>();
assert_channel_f32::<f32>();
assert_channel_f32::<f64>();
assert_channel_f32::<Saturating<u8>>();
assert_channel_f32::<Saturating<u16>>();
assert_channel_f32::<Saturating<u32>>();
assert_channel_f32::<Saturating<u64>>();
assert_channel_f64::<u32>();
assert_channel_f64::<u64>();
assert_channel_f64::<i32>();
assert_channel_f64::<i64>();
assert_channel_f64::<f64>();
assert_channel_f64::<Saturating<u32>>();
assert_channel_f64::<Saturating<u64>>();
}
#[test]
fn linear_pixel_inventory_excludes_raw_floats() {
fn assert_linear_pixel<T: crate::pixel::LinearPixel>() {}
assert_linear_pixel::<crate::pixel::MonoF32>();
assert_linear_pixel::<crate::pixel::MonoF64>();
}
#[test]
fn plain_pixel_inventory_excludes_raw_floats() {
fn assert_plain_pixel<T: PlainPixel>() {}
assert_plain_pixel::<u8>();
assert_plain_pixel::<u16>();
assert_plain_pixel::<crate::pixel::MonoF32>();
assert_plain_pixel::<crate::pixel::MonoF64>();
}
#[test]
fn plain_channel_inventory() {
fn assert_plain_channel<T: PlainChannel>() {}
assert_plain_channel::<u8>();
assert_plain_channel::<u16>();
assert_plain_channel::<u32>();
assert_plain_channel::<u64>();
assert_plain_channel::<i8>();
assert_plain_channel::<i16>();
assert_plain_channel::<i32>();
assert_plain_channel::<i64>();
assert_plain_channel::<f32>();
assert_plain_channel::<f64>();
assert_plain_channel::<Saturating<u8>>();
assert_plain_channel::<Saturating<u16>>();
assert_plain_channel::<Saturating<u32>>();
assert_plain_channel::<Saturating<u64>>();
assert_plain_channel::<Saturating<i8>>();
assert_plain_channel::<Saturating<i16>>();
assert_plain_channel::<Saturating<i32>>();
assert_plain_channel::<Saturating<i64>>();
assert_plain_channel::<crate::pixel::Mono8>();
assert_plain_channel::<crate::pixel::MonoF32>();
assert_plain_channel::<crate::pixel::Rgb8>();
assert_plain_channel::<crate::pixel::RgbF32>();
}
#[test]
fn plain_pixel_inventory() {
fn assert_plain_pixel<T: PlainPixel>() {}
assert_plain_pixel::<u8>();
assert_plain_pixel::<u16>();
assert_plain_pixel::<u32>();
assert_plain_pixel::<u64>();
assert_plain_pixel::<Saturating<u8>>();
assert_plain_pixel::<Saturating<u16>>();
assert_plain_pixel::<Saturating<u32>>();
assert_plain_pixel::<Saturating<u64>>();
assert_plain_pixel::<crate::pixel::Mono8>();
assert_plain_pixel::<crate::pixel::Mono16>();
assert_plain_pixel::<crate::pixel::Mono32>();
assert_plain_pixel::<crate::pixel::Mono64>();
assert_plain_pixel::<crate::pixel::Mono<10>>();
assert_plain_pixel::<crate::pixel::Mono<12>>();
assert_plain_pixel::<crate::pixel::Mono<14>>();
assert_plain_pixel::<crate::pixel::MonoF32>();
assert_plain_pixel::<crate::pixel::MonoF64>();
assert_plain_pixel::<crate::pixel::MonoA8>();
assert_plain_pixel::<crate::pixel::MonoA16>();
assert_plain_pixel::<crate::pixel::MonoA32>();
assert_plain_pixel::<crate::pixel::MonoA64>();
assert_plain_pixel::<crate::pixel::MonoAF32>();
assert_plain_pixel::<crate::pixel::MonoAF64>();
assert_plain_pixel::<crate::pixel::Rgb8>();
assert_plain_pixel::<crate::pixel::Rgb16>();
assert_plain_pixel::<crate::pixel::Rgb32>();
assert_plain_pixel::<crate::pixel::Rgb64>();
assert_plain_pixel::<crate::pixel::Rgb<10>>();
assert_plain_pixel::<crate::pixel::Rgb<12>>();
assert_plain_pixel::<crate::pixel::Rgb<14>>();
assert_plain_pixel::<crate::pixel::RgbF32>();
assert_plain_pixel::<crate::pixel::RgbF64>();
assert_plain_pixel::<crate::pixel::Rgba8>();
assert_plain_pixel::<crate::pixel::Rgba16>();
assert_plain_pixel::<crate::pixel::Rgba32>();
assert_plain_pixel::<crate::pixel::Rgba64>();
assert_plain_pixel::<crate::pixel::Rgba<10>>();
assert_plain_pixel::<crate::pixel::Rgba<12>>();
assert_plain_pixel::<crate::pixel::Rgba<14>>();
assert_plain_pixel::<crate::pixel::RgbaF32>();
assert_plain_pixel::<crate::pixel::RgbaF64>();
assert_plain_pixel::<crate::pixel::Bgr8>();
assert_plain_pixel::<crate::pixel::Bgr16>();
assert_plain_pixel::<crate::pixel::Bgr32>();
assert_plain_pixel::<crate::pixel::Bgr64>();
assert_plain_pixel::<crate::pixel::Bgr<10>>();
assert_plain_pixel::<crate::pixel::Bgr<12>>();
assert_plain_pixel::<crate::pixel::Bgr<14>>();
assert_plain_pixel::<crate::pixel::BgrF32>();
assert_plain_pixel::<crate::pixel::BgrF64>();
assert_plain_pixel::<crate::pixel::Bgra8>();
assert_plain_pixel::<crate::pixel::Bgra16>();
assert_plain_pixel::<crate::pixel::Bgra32>();
assert_plain_pixel::<crate::pixel::Bgra64>();
assert_plain_pixel::<crate::pixel::Bgra<10>>();
assert_plain_pixel::<crate::pixel::Bgra<12>>();
assert_plain_pixel::<crate::pixel::Bgra<14>>();
assert_plain_pixel::<crate::pixel::BgraF32>();
assert_plain_pixel::<crate::pixel::BgraF64>();
assert_plain_pixel::<crate::pixel::Srgb8>();
assert_plain_pixel::<crate::pixel::Srgb16>();
assert_plain_pixel::<crate::pixel::Srgba8>();
assert_plain_pixel::<crate::pixel::Srgba16>();
assert_plain_pixel::<crate::pixel::SrgbMono8>();
assert_plain_pixel::<crate::pixel::SrgbMono16>();
assert_plain_pixel::<crate::pixel::SrgbMonoA8>();
assert_plain_pixel::<crate::pixel::SrgbMonoA16>();
assert_plain_pixel::<crate::pixel::Indexed8>();
}
#[test]
fn linear_pixel_inventory() {
fn assert_linear_pixel<T: crate::pixel::LinearPixel>() {}
assert_linear_pixel::<crate::pixel::Mono8>();
assert_linear_pixel::<crate::pixel::Mono16>();
assert_linear_pixel::<crate::pixel::Mono32>();
assert_linear_pixel::<crate::pixel::Mono64>();
assert_linear_pixel::<crate::pixel::Mono<10>>();
assert_linear_pixel::<crate::pixel::Mono<12>>();
assert_linear_pixel::<crate::pixel::Mono<14>>();
assert_linear_pixel::<crate::pixel::MonoF32>();
assert_linear_pixel::<crate::pixel::MonoF64>();
assert_linear_pixel::<crate::pixel::MonoA8>();
assert_linear_pixel::<crate::pixel::MonoA16>();
assert_linear_pixel::<crate::pixel::MonoA32>();
assert_linear_pixel::<crate::pixel::MonoA64>();
assert_linear_pixel::<crate::pixel::MonoAF32>();
assert_linear_pixel::<crate::pixel::MonoAF64>();
assert_linear_pixel::<crate::pixel::Rgb8>();
assert_linear_pixel::<crate::pixel::Rgb16>();
assert_linear_pixel::<crate::pixel::Rgb32>();
assert_linear_pixel::<crate::pixel::Rgb64>();
assert_linear_pixel::<crate::pixel::Rgb<10>>();
assert_linear_pixel::<crate::pixel::Rgb<12>>();
assert_linear_pixel::<crate::pixel::Rgb<14>>();
assert_linear_pixel::<crate::pixel::RgbF32>();
assert_linear_pixel::<crate::pixel::RgbF64>();
assert_linear_pixel::<crate::pixel::Rgba8>();
assert_linear_pixel::<crate::pixel::Rgba16>();
assert_linear_pixel::<crate::pixel::Rgba32>();
assert_linear_pixel::<crate::pixel::Rgba64>();
assert_linear_pixel::<crate::pixel::Rgba<10>>();
assert_linear_pixel::<crate::pixel::Rgba<12>>();
assert_linear_pixel::<crate::pixel::Rgba<14>>();
assert_linear_pixel::<crate::pixel::RgbaF32>();
assert_linear_pixel::<crate::pixel::RgbaF64>();
assert_linear_pixel::<crate::pixel::Bgr8>();
assert_linear_pixel::<crate::pixel::Bgr16>();
assert_linear_pixel::<crate::pixel::Bgr32>();
assert_linear_pixel::<crate::pixel::Bgr64>();
assert_linear_pixel::<crate::pixel::Bgr<10>>();
assert_linear_pixel::<crate::pixel::Bgr<12>>();
assert_linear_pixel::<crate::pixel::Bgr<14>>();
assert_linear_pixel::<crate::pixel::BgrF32>();
assert_linear_pixel::<crate::pixel::BgrF64>();
assert_linear_pixel::<crate::pixel::Bgra8>();
assert_linear_pixel::<crate::pixel::Bgra16>();
assert_linear_pixel::<crate::pixel::Bgra32>();
assert_linear_pixel::<crate::pixel::Bgra64>();
assert_linear_pixel::<crate::pixel::Bgra<10>>();
assert_linear_pixel::<crate::pixel::Bgra<12>>();
assert_linear_pixel::<crate::pixel::Bgra<14>>();
assert_linear_pixel::<crate::pixel::BgraF32>();
assert_linear_pixel::<crate::pixel::BgraF64>();
}
#[test]
fn linear_space_inventory() {
fn assert_linear_space<T: crate::pixel::LinearSpace>() {}
assert_linear_space::<crate::pixel::Mono8>();
assert_linear_space::<crate::pixel::Mono16>();
assert_linear_space::<crate::pixel::Mono32>();
assert_linear_space::<crate::pixel::Mono64>();
assert_linear_space::<crate::pixel::Mono<10>>();
assert_linear_space::<crate::pixel::Mono<12>>();
assert_linear_space::<crate::pixel::Mono<14>>();
assert_linear_space::<crate::pixel::MonoF32>();
assert_linear_space::<crate::pixel::MonoF64>();
assert_linear_space::<crate::pixel::MonoA8>();
assert_linear_space::<crate::pixel::MonoA16>();
assert_linear_space::<crate::pixel::MonoA32>();
assert_linear_space::<crate::pixel::MonoA64>();
assert_linear_space::<crate::pixel::MonoAF32>();
assert_linear_space::<crate::pixel::MonoAF64>();
assert_linear_space::<crate::pixel::Rgb8>();
assert_linear_space::<crate::pixel::Rgb16>();
assert_linear_space::<crate::pixel::Rgb32>();
assert_linear_space::<crate::pixel::Rgb64>();
assert_linear_space::<crate::pixel::Rgb<10>>();
assert_linear_space::<crate::pixel::Rgb<12>>();
assert_linear_space::<crate::pixel::Rgb<14>>();
assert_linear_space::<crate::pixel::RgbF32>();
assert_linear_space::<crate::pixel::RgbF64>();
assert_linear_space::<crate::pixel::Rgba8>();
assert_linear_space::<crate::pixel::Rgba16>();
assert_linear_space::<crate::pixel::Rgba32>();
assert_linear_space::<crate::pixel::Rgba64>();
assert_linear_space::<crate::pixel::Rgba<10>>();
assert_linear_space::<crate::pixel::Rgba<12>>();
assert_linear_space::<crate::pixel::Rgba<14>>();
assert_linear_space::<crate::pixel::RgbaF32>();
assert_linear_space::<crate::pixel::RgbaF64>();
assert_linear_space::<crate::pixel::Bgr8>();
assert_linear_space::<crate::pixel::Bgr16>();
assert_linear_space::<crate::pixel::Bgr32>();
assert_linear_space::<crate::pixel::Bgr64>();
assert_linear_space::<crate::pixel::Bgr<10>>();
assert_linear_space::<crate::pixel::Bgr<12>>();
assert_linear_space::<crate::pixel::Bgr<14>>();
assert_linear_space::<crate::pixel::BgrF32>();
assert_linear_space::<crate::pixel::BgrF64>();
assert_linear_space::<crate::pixel::Bgra8>();
assert_linear_space::<crate::pixel::Bgra16>();
assert_linear_space::<crate::pixel::Bgra32>();
assert_linear_space::<crate::pixel::Bgra64>();
assert_linear_space::<crate::pixel::Bgra<10>>();
assert_linear_space::<crate::pixel::Bgra<12>>();
assert_linear_space::<crate::pixel::Bgra<14>>();
assert_linear_space::<crate::pixel::BgraF32>();
assert_linear_space::<crate::pixel::BgraF64>();
}
}