fovea 0.2.0

A high-precision, type-safe computer vision library guaranteeing absolute image correctness at compile time
Documentation
//! Grayscale-with-alpha (MonoA) pixel types.
//!
//! Two-channel pixels: value (v) + alpha (a).

use fovea_derive::{HomogeneousPixel, LinearPixel, PlainPixel, WhiteChannel, ZeroablePixel};

use std::{
    hash::{Hash, Hasher},
    num::Saturating,
};

use super::{canonicalize_f32, canonicalize_f64};
use crate::pixel::impl_origin_invariant_pixel;

// ═══════════════════════════════════════════════════════════════════════════════
// MonoA (Grayscale-with-Alpha) pixel types
//
// Two-channel pixels: value (v) + alpha (a).  Same derive pattern as Rgba.
// ════════════════════════════════════════════════════════════════════════════════

/// Grayscale-with-alpha pixel, 8-bit depth per channel.
#[repr(C)]
#[derive(
    Clone,
    Copy,
    Debug,
    PartialEq,
    Eq,
    Hash,
    PlainPixel,
    HomogeneousPixel,
    ZeroablePixel,
    LinearPixel,
    WhiteChannel,
)]
#[linear(accumulator = MonoAF32)]
pub struct MonoA8 {
    /// Value (luminance) channel.
    pub v: Saturating<u8>,
    /// Alpha channel.
    pub a: Saturating<u8>,
}
impl MonoA8 {
    /// Creates a `MonoA8` pixel with the given 8-bit luminance `v` and alpha `a`.
    pub fn new(v: u8, a: u8) -> Self {
        MonoA8 {
            v: Saturating(v),
            a: Saturating(a),
        }
    }
}

/// Grayscale-with-alpha pixel, 16-bit depth per channel.
#[repr(C)]
#[derive(
    Clone,
    Copy,
    Debug,
    PartialEq,
    Eq,
    Hash,
    PlainPixel,
    HomogeneousPixel,
    ZeroablePixel,
    LinearPixel,
    WhiteChannel,
)]
#[linear(accumulator = MonoAF32)]
pub struct MonoA16 {
    /// Value (luminance) channel.
    pub v: Saturating<u16>,
    /// Alpha channel.
    pub a: Saturating<u16>,
}
impl MonoA16 {
    /// Creates a `MonoA16` pixel with the given 16-bit luminance `v` and alpha `a`.
    pub fn new(v: u16, a: u16) -> Self {
        MonoA16 {
            v: Saturating(v),
            a: Saturating(a),
        }
    }
}

/// Grayscale-with-alpha pixel, 32-bit depth per channel.
#[repr(C)]
#[derive(
    Clone,
    Copy,
    Debug,
    PartialEq,
    Eq,
    Hash,
    PlainPixel,
    HomogeneousPixel,
    ZeroablePixel,
    LinearPixel,
    WhiteChannel,
)]
#[linear(accumulator = MonoAF64)]
pub struct MonoA32 {
    /// Value (luminance) channel.
    pub v: Saturating<u32>,
    /// Alpha channel.
    pub a: Saturating<u32>,
}
impl MonoA32 {
    /// Creates a `MonoA32` pixel with the given 32-bit luminance `v` and alpha `a`.
    pub fn new(v: u32, a: u32) -> Self {
        MonoA32 {
            v: Saturating(v),
            a: Saturating(a),
        }
    }
}

/// Grayscale-with-alpha pixel, 64-bit depth per channel.
#[repr(C)]
#[derive(
    Clone,
    Copy,
    Debug,
    PartialEq,
    Eq,
    Hash,
    PlainPixel,
    HomogeneousPixel,
    ZeroablePixel,
    LinearPixel,
    WhiteChannel,
)]
#[linear(accumulator = MonoAF64)]
pub struct MonoA64 {
    /// Value (luminance) channel.
    pub v: Saturating<u64>,
    /// Alpha channel.
    pub a: Saturating<u64>,
}
impl MonoA64 {
    /// Creates a `MonoA64` pixel with the given 64-bit luminance `v` and alpha `a`.
    pub fn new(v: u64, a: u64) -> Self {
        MonoA64 {
            v: Saturating(v),
            a: Saturating(a),
        }
    }
}

/// Grayscale-with-alpha pixel, 32-bit floating point depth per channel.
#[repr(C)]
#[derive(
    Clone, Copy, Debug, PartialEq, PlainPixel, HomogeneousPixel, ZeroablePixel, LinearPixel,
)]
#[linear(accumulator = Self)]
pub struct MonoAF32 {
    // Inner `f32` is a channel, not a pixel.
    /// Value (luminance) channel.
    #[zero(default)]
    pub v: f32,
    /// Alpha channel.
    #[zero(default)]
    pub a: f32,
}
impl MonoAF32 {
    /// Creates a `MonoAF32` pixel with the given 32-bit floating-point luminance `v` and alpha `a`.
    pub fn new(v: f32, a: f32) -> Self {
        MonoAF32 { v, a }
    }
}

impl Hash for MonoAF32 {
    fn hash<H: Hasher>(&self, state: &mut H) {
        canonicalize_f32(self.v).hash(state);
        canonicalize_f32(self.a).hash(state);
    }
}

/// Grayscale-with-alpha pixel, 64-bit floating point depth per channel.
#[repr(C)]
#[derive(
    Clone, Copy, Debug, PartialEq, PlainPixel, HomogeneousPixel, ZeroablePixel, LinearPixel,
)]
#[linear(accumulator = Self)]
pub struct MonoAF64 {
    // Inner `f64` is a channel, not a pixel.
    /// Value (luminance) channel.
    #[zero(default)]
    pub v: f64,
    /// Alpha channel.
    #[zero(default)]
    pub a: f64,
}
impl MonoAF64 {
    /// Creates a `MonoAF64` pixel with the given 64-bit floating-point luminance `v` and alpha `a`.
    pub fn new(v: f64, a: f64) -> Self {
        MonoAF64 { v, a }
    }
}

impl Hash for MonoAF64 {
    fn hash<H: Hasher>(&self, state: &mut H) {
        canonicalize_f64(self.v).hash(state);
        canonicalize_f64(self.a).hash(state);
    }
}

// ---------------------------------------------------------------------------
// OriginInvariantPixel impls
// ---------------------------------------------------------------------------
//
// Grayscale-with-alpha values mean the same thing regardless of where the
// pixel sits, so an origin-translated crop preserves their meaning.
impl_origin_invariant_pixel!(MonoA8, MonoA16, MonoA32, MonoA64, MonoAF32, MonoAF64);