feim 0.25.1

Modular crate for working with images in Rust
Documentation
use std::marker::PhantomData;

use super::convert::ConvertFrom;

use super::{BigEndian, Color, Endianness, LittleEndian, NativeEndian, Zero};
#[cfg(feature = "col-nrgba64")]
use super::{Nrgba64Be, Nrgba64Channels};
use crate::specialized;

pub trait Gray16Channels: Sized {
    fn y(self) -> u16;

    fn set_y(self, r: u16) -> Self;
}

#[derive(Copy, Clone, Eq, PartialEq, Debug)]
#[repr(C)]
pub struct Gray16<E> {
    y: u16,
    _endianness: PhantomData<E>,
}

impl<E1: Endianness> Gray16<E1> {
    pub const fn cast<E2: Endianness>(self) -> Gray16<E2> {
        let Gray16 { y, .. } = self;
        Gray16 {
            y,
            _endianness: PhantomData,
        }
    }
}

pub type Gray16Ne = Gray16<NativeEndian>;

pub type Gray16Be = Gray16<BigEndian>;

pub type Gray16Le = Gray16<LittleEndian>;

// -------------------------------------------------------------------------- //

impl Gray16<NativeEndian> {
    pub const fn ne(y: u16) -> Self {
        Self {
            y,
            _endianness: PhantomData,
        }
    }
}

impl Gray16Channels for Gray16<NativeEndian> {
    #[inline(always)]
    fn y(self) -> u16 {
        self.y
    }

    #[inline(always)]
    fn set_y(mut self, y: u16) -> Self {
        self.y = y;
        self
    }
}

impl Gray16<LittleEndian> {
    pub const fn le(y: u16) -> Self {
        Self {
            y: y.to_le(),
            _endianness: PhantomData,
        }
    }
}

impl Gray16Channels for Gray16<LittleEndian> {
    #[inline(always)]
    fn y(self) -> u16 {
        #[cfg(target_endian = "little")]
        {
            self.y
        }

        #[cfg(target_endian = "big")]
        {
            self.y.swap_bytes()
        }
    }

    #[inline(always)]
    fn set_y(mut self, y: u16) -> Self {
        #[cfg(target_endian = "little")]
        {
            self.y = y
        }

        #[cfg(target_endian = "big")]
        {
            self.y = y.swap_bytes()
        }

        self
    }
}

impl Gray16<BigEndian> {
    pub const fn be(y: u16) -> Self {
        Self {
            y: y.to_be(),
            _endianness: PhantomData,
        }
    }
}

impl Gray16Channels for Gray16<BigEndian> {
    #[inline(always)]
    fn y(self) -> u16 {
        #[cfg(target_endian = "little")]
        {
            self.y.swap_bytes()
        }

        #[cfg(target_endian = "big")]
        {
            self.y
        }
    }

    #[inline(always)]
    fn set_y(mut self, y: u16) -> Self {
        #[cfg(target_endian = "little")]
        {
            self.y = y.swap_bytes()
        }

        #[cfg(target_endian = "big")]
        {
            self.y = y
        }

        self
    }
}

// -------------------------------------------------------------------------- //

impl<E> Zero for Gray16<E>
where
    Gray16<E>: Color + Copy,
{
    const ZERO: Self = Gray16 {
        y: 0,
        _endianness: PhantomData,
    };
}

impl<E> Color for Gray16<E>
where
    E: Endianness,
    Self: Copy + Gray16Channels,
{
    fn as_rgba(&self) -> (u32, u32, u32, u32) {
        let y = self.y() as u32;
        (y, y, y, 0xffff)
    }
}

// -------------------------------------------------------------------------- //

impl<E1, E2> ConvertFrom<Gray16<E1>, specialized::Aye> for Gray16<E2>
where
    E1: Endianness,
    E2: Endianness,
    Gray16<E1>: Color,
    Gray16<E2>: Color + From<u16>,
    u16: From<Gray16<E1>>,
{
    fn convert_from(c: Gray16<E1>) -> Gray16<E2> {
        let c: u16 = c.into();
        c.into()
    }
}

// TODO: use these bounds instead
/*
impl<E1, E2> ConvertFrom<Gray16<E1>, specialized::Aye> for Gray16<E2>
where
    E1: Endianness,
    E2: Endianness,
    Gray16<E1>: Copy + Color + Gray16Channels,
    Gray16<E2>: Copy + Color + Gray16Channels,
{
    #[inline(always)]
    fn convert_from(c: Gray16<E1>) -> Gray16<E2> {
        Self::ZERO.set_y(c.y())
    }
}
*/

impl<C, E> ConvertFrom<C> for Gray16<E>
where
    C: Color,
    E: Endianness,
    Self: Zero + Gray16Channels,
{
    fn convert_from(c: C) -> Self {
        let (r, g, b, _) = c.as_rgba();
        Self::ZERO.set_y(((19595 * r + 38470 * g + 7471 * b + 0x8000) >> 16) as u16)
    }
}

#[cfg(feature = "col-nrgba64")]
impl ConvertFrom<Nrgba64Be, specialized::For<Gray16Be>> for Gray16Be {
    fn convert_from(c: Nrgba64Be) -> Self {
        let (r, g, b) = (c.r(), c.g(), c.b());
        let y = (((19595 * r as u64 + 38470 * g as u64 + 7471 * b as u64 + 0x8000) >> 16) as u16)
            .to_be();
        Gray16 {
            y,
            _endianness: PhantomData,
        }
    }
}

// -------------------------------------------------------------------------- //

impl<E> From<Gray16<E>> for u16
where
    E: Endianness,
    Gray16<E>: Gray16Channels,
{
    #[inline(always)]
    fn from(c: Gray16<E>) -> u16 {
        c.y()
    }
}

// -------------------------------------------------------------------------- //

impl<E> From<u16> for Gray16<E>
where
    E: Endianness,
    Self: Copy + Color + Gray16Channels,
{
    #[inline(always)]
    fn from(y: u16) -> Self {
        Self::ZERO.set_y(y)
    }
}