cgats 0.2.0

Parse, transform, and write CGATS color files
Documentation
//! Parse and print CGATS DATA_FORMAT fields

use crate::*;
use std::{fmt, str::FromStr};

pub use Field::*;
/// The types contained within the `DATA_FORMAT` section of a CGATS file
#[allow(non_camel_case_types, missing_docs)]
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
pub enum Field {
    SAMPLE_ID, SAMPLE_NAME, BLANK,
    RGB_R, RGB_G, RGB_B,
    CMYK_C, CMYK_M, CMYK_Y, CMYK_K,
    FIVECLR_1, FIVECLR_2, FIVECLR_3, FIVECLR_4, FIVECLR_5,
    SIXCLR_1, SIXCLR_2, SIXCLR_3, SIXCLR_4, SIXCLR_5, SIXCLR_6,
    SEVENCLR_1, SEVENCLR_2, SEVENCLR_3, SEVENCLR_4, SEVENCLR_5, SEVENCLR_6, SEVENCLR_7,
    EIGHTCLR_1, EIGHTCLR_2, EIGHTCLR_3, EIGHTCLR_4, EIGHTCLR_5, EIGHTCLR_6, EIGHTCLR_7, EIGHTCLR_8,
    NCLR(u8),
    D_RED, D_GREEN, D_BLUE, D_VIS,
    LAB_L, LAB_A, LAB_B,
    LCH_L, LCH_C, LCH_H,
    DE_1976, DE_1994, DE_1994T, DE_CMC, DE_CMC2, DE_2000,
    XYZ_X, XYZ_Y, XYZ_Z,
    XYY_X, XYY_Y, XYY_CAPY,
    SPECTRAL_340, SPECTRAL_350, SPECTRAL_360, SPECTRAL_370, SPECTRAL_380,
    SPECTRAL_390, SPECTRAL_400, SPECTRAL_410, SPECTRAL_420, SPECTRAL_430,
    SPECTRAL_440, SPECTRAL_450, SPECTRAL_460, SPECTRAL_470, SPECTRAL_480,
    SPECTRAL_490, SPECTRAL_500, SPECTRAL_510, SPECTRAL_520, SPECTRAL_530,
    SPECTRAL_540, SPECTRAL_550, SPECTRAL_560, SPECTRAL_570, SPECTRAL_580,
    SPECTRAL_590, SPECTRAL_600, SPECTRAL_610, SPECTRAL_620, SPECTRAL_630,
    SPECTRAL_640, SPECTRAL_650, SPECTRAL_660, SPECTRAL_670, SPECTRAL_680,
    SPECTRAL_690, SPECTRAL_700, SPECTRAL_710, SPECTRAL_720, SPECTRAL_730,
    SPECTRAL_740, SPECTRAL_750, SPECTRAL_760, SPECTRAL_770, SPECTRAL_780,
    SPECTRAL_790, SPECTRAL_800, SPECTRAL_810, SPECTRAL_820, SPECTRAL_830,
    Other(String),
}

impl Field {
    /// Returns a guess at a [`Field`] based on the total number of channels and the index of the
    /// channel. Returns an error if there are less than 3 channels or if the index is greater than
    /// or equal to the number of channels.
    pub fn from_channel_index(n_channels: usize, index: usize) -> Result<Self> {
        if index >= n_channels {
            return err!(format!("the index is {index}, but the number of channels is {n_channels}"));
        }
        Ok(match (n_channels, index) {
            (0..=2, _) => return err!("less than 3 channels is not supported"),
            (3, i) => match i {
                0 => Field::RGB_R,
                1 => Field::RGB_G,
                2 => Field::RGB_B,
                _ => unreachable!(),
            }
            (4, i) => match i {
                0 => Field::CMYK_C,
                1 => Field::CMYK_M,
                2 => Field::CMYK_Y,
                3 => Field::CMYK_K,
                _ => unreachable!(),
            }
            (5, i) => match i {
                0 => Field::FIVECLR_1,
                1 => Field::FIVECLR_2,
                2 => Field::FIVECLR_3,
                3 => Field::FIVECLR_4,
                4 => Field::FIVECLR_5,
                _ => unreachable!(),
            }
            (6, i) => match i {
                0 => Field::SIXCLR_1,
                1 => Field::SIXCLR_2,
                2 => Field::SIXCLR_3,
                3 => Field::SIXCLR_4,
                4 => Field::SIXCLR_5,
                5 => Field::SIXCLR_6,
                _ => unreachable!(),
            }
            (7, i) => match i {
                0 => Field::SEVENCLR_1,
                1 => Field::SEVENCLR_2,
                2 => Field::SEVENCLR_3,
                3 => Field::SEVENCLR_4,
                4 => Field::SEVENCLR_5,
                5 => Field::SEVENCLR_6,
                6 => Field::SEVENCLR_7,
                _ => unreachable!(),
            }
            (8, i) => match i {
                0 => Field::EIGHTCLR_1,
                1 => Field::EIGHTCLR_2,
                2 => Field::EIGHTCLR_3,
                3 => Field::EIGHTCLR_4,
                4 => Field::EIGHTCLR_5,
                5 => Field::EIGHTCLR_6,
                6 => Field::EIGHTCLR_7,
                7 => Field::EIGHTCLR_8,
                _ => unreachable!(),
            }
            (_n, i) => Field::NCLR(i as u8 + 1),
        })
    }
}

impl AsRef<Self> for Field {
    fn as_ref(&self) -> &Self {
        self
    }
}

impl CgatsFmt for Field {
    fn cgats_fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let result = match self {
            BLANK => String::new(),
            NCLR(n) => format!("NCLR_{}", n),
            Other(other) => other.to_string(),
            field => format!("{:?}", field)
                .replace("FIVE", "5")
                .replace("SIX", "6")
                .replace("SEVEN", "7")
                .replace("EIGHT", "8"),
        };

        write!(f, "{}", result)
    }
}

impl fmt::Display for Field {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.cgats_fmt(f)
    }
}

impl FromStr for Field {
    type Err = BoxErr;
    fn from_str(s: &str) -> Result<Self> {
        use Field::*;
        match s.trim().to_uppercase().as_ref() {
            "SAMPLE_ID" | "SAMPLEID" | "SAMPLE" => Ok(SAMPLE_ID),
            "SAMPLE_NAME" | "SAMPLENAME" => Ok(SAMPLE_NAME),
            "" | "BLANK" => Ok(BLANK),

            "RGB_R" => Ok(RGB_R),
            "RGB_G" => Ok(RGB_G),
            "RGB_B" => Ok(RGB_B),

            "CMYK_C" => Ok(CMYK_C),
            "CMYK_M" => Ok(CMYK_M),
            "CMYK_Y" => Ok(CMYK_Y),
            "CMYK_K" => Ok(CMYK_K),

            "5CLR_1" => Ok(FIVECLR_1),
            "5CLR_2" => Ok(FIVECLR_2),
            "5CLR_3" => Ok(FIVECLR_3),
            "5CLR_4" => Ok(FIVECLR_4),
            "5CLR_5" => Ok(FIVECLR_5),

            "6CLR_1" => Ok(SIXCLR_1),
            "6CLR_2" => Ok(SIXCLR_2),
            "6CLR_3" => Ok(SIXCLR_3),
            "6CLR_4" => Ok(SIXCLR_4),
            "6CLR_5" => Ok(SIXCLR_5),
            "6CLR_6" => Ok(SIXCLR_6),

            "7CLR_1" => Ok(SEVENCLR_1),
            "7CLR_2" => Ok(SEVENCLR_2),
            "7CLR_3" => Ok(SEVENCLR_3),
            "7CLR_4" => Ok(SEVENCLR_4),
            "7CLR_5" => Ok(SEVENCLR_5),
            "7CLR_6" => Ok(SEVENCLR_6),
            "7CLR_7" => Ok(SEVENCLR_7),

            "8CLR_1" => Ok(EIGHTCLR_1),
            "8CLR_2" => Ok(EIGHTCLR_2),
            "8CLR_3" => Ok(EIGHTCLR_3),
            "8CLR_4" => Ok(EIGHTCLR_4),
            "8CLR_5" => Ok(EIGHTCLR_5),
            "8CLR_6" => Ok(EIGHTCLR_6),
            "8CLR_7" => Ok(EIGHTCLR_7),
            "8CLR_8" => Ok(EIGHTCLR_8),

            "NCLR_1" => Ok(NCLR(1)),
            "NCLR_2" => Ok(NCLR(2)),
            "NCLR_3" => Ok(NCLR(3)),
            "NCLR_4" => Ok(NCLR(4)),
            "NCLR_5" => Ok(NCLR(5)),
            "NCLR_6" => Ok(NCLR(6)),
            "NCLR_7" => Ok(NCLR(7)),
            "NCLR_8" => Ok(NCLR(8)),
            "NCLR_9" => Ok(NCLR(9)),
            "NCLR_10" => Ok(NCLR(10)),
            "NCLR_11" => Ok(NCLR(11)),
            "NCLR_12" => Ok(NCLR(12)),

            "LAB_L" => Ok(LAB_L),
            "LAB_A" => Ok(LAB_A),
            "LAB_B" => Ok(LAB_B),
            "LCH_L" => Ok(LCH_L),
            "LCH_C" => Ok(LCH_C),
            "LCH_H" => Ok(LCH_H),
            "XYZ_X" => Ok(XYZ_X),
            "XYZ_Y" => Ok(XYZ_Y),
            "XYZ_Z" => Ok(XYZ_Z),
            "XYY_X" => Ok(XYY_X),
            "XYY_Y" => Ok(XYY_Y),
            "XYY_CAPY" => Ok(XYY_CAPY),

            "D_RED" => Ok(D_RED),
            "D_GREEN" => Ok(D_GREEN),
            "D_BLUE" => Ok(D_BLUE),
            "D_VISUAL" | "D_VIS" => Ok(D_VIS),

            "LAB_DE" | "DE1976" | "DE76" | "DE" | "DE_76" | "DE_1976" => Ok(DE_1976),

            "LAB_DE_1994" | "DE1994" | "DE94" | "DE1994G" | "DE94G" | "DE94_G" | "DE_1994"
            | "DE_94" | "DE_1994G" | "DE_1994_G" | "DE_94G" | "DE_94_G" => Ok(DE_1994),

            "LAB_DE_1994T" | "DE1994T" | "DE94T" | "DE_1994_T" | "DE_94T" | "DE_1994T"
            | "DE_94_T" | "DE94_T" => Ok(DE_1994T),

            "LAB_DE_CMC" | "DECMC" | "DECMC1" | "CMC" | "CMC 1:1" | "DE_CMC1" | "DE_CMC_1"
            | "DE_CMC" => Ok(DE_CMC),

            "LAB_DE_CMC2" | "DECMC2" | "CMC2" | "CMC 2:1" | "DE_CMC_2" | "DE_CMC2"
            | "DE_CMC 2:1" | "DECMC_2" => Ok(DE_CMC2),

            "LAB_DE_2001" | "DE2000" | "DE00" | "DE_2000" | "DE_00" => Ok(DE_2000),

            "SPECTRAL_340" | "SPECTRAL_NM340"  => Ok(SPECTRAL_340),
            "SPECTRAL_350" | "SPECTRAL_NM350"  => Ok(SPECTRAL_350),
            "SPECTRAL_360" | "SPECTRAL_NM360"  => Ok(SPECTRAL_360),
            "SPECTRAL_370" | "SPECTRAL_NM370"  => Ok(SPECTRAL_370),
            "SPECTRAL_380" | "SPECTRAL_NM380"  => Ok(SPECTRAL_380),
            "SPECTRAL_390" | "SPECTRAL_NM390"  => Ok(SPECTRAL_390),
            "SPECTRAL_400" | "SPECTRAL_NM400"  => Ok(SPECTRAL_400),
            "SPECTRAL_410" | "SPECTRAL_NM410"  => Ok(SPECTRAL_410),
            "SPECTRAL_420" | "SPECTRAL_NM420"  => Ok(SPECTRAL_420),
            "SPECTRAL_430" | "SPECTRAL_NM430"  => Ok(SPECTRAL_430),
            "SPECTRAL_440" | "SPECTRAL_NM440"  => Ok(SPECTRAL_440),
            "SPECTRAL_450" | "SPECTRAL_NM450"  => Ok(SPECTRAL_450),
            "SPECTRAL_460" | "SPECTRAL_NM460"  => Ok(SPECTRAL_460),
            "SPECTRAL_470" | "SPECTRAL_NM470"  => Ok(SPECTRAL_470),
            "SPECTRAL_480" | "SPECTRAL_NM480"  => Ok(SPECTRAL_480),
            "SPECTRAL_490" | "SPECTRAL_NM490"  => Ok(SPECTRAL_490),
            "SPECTRAL_500" | "SPECTRAL_NM500"  => Ok(SPECTRAL_500),
            "SPECTRAL_510" | "SPECTRAL_NM510"  => Ok(SPECTRAL_510),
            "SPECTRAL_520" | "SPECTRAL_NM520"  => Ok(SPECTRAL_520),
            "SPECTRAL_530" | "SPECTRAL_NM530"  => Ok(SPECTRAL_530),
            "SPECTRAL_540" | "SPECTRAL_NM540"  => Ok(SPECTRAL_540),
            "SPECTRAL_550" | "SPECTRAL_NM550"  => Ok(SPECTRAL_550),
            "SPECTRAL_560" | "SPECTRAL_NM560"  => Ok(SPECTRAL_560),
            "SPECTRAL_570" | "SPECTRAL_NM570"  => Ok(SPECTRAL_570),
            "SPECTRAL_580" | "SPECTRAL_NM580"  => Ok(SPECTRAL_580),
            "SPECTRAL_590" | "SPECTRAL_NM590"  => Ok(SPECTRAL_590),
            "SPECTRAL_600" | "SPECTRAL_NM600"  => Ok(SPECTRAL_600),
            "SPECTRAL_610" | "SPECTRAL_NM610"  => Ok(SPECTRAL_610),
            "SPECTRAL_620" | "SPECTRAL_NM620"  => Ok(SPECTRAL_620),
            "SPECTRAL_630" | "SPECTRAL_NM630"  => Ok(SPECTRAL_630),
            "SPECTRAL_640" | "SPECTRAL_NM640"  => Ok(SPECTRAL_640),
            "SPECTRAL_650" | "SPECTRAL_NM650"  => Ok(SPECTRAL_650),
            "SPECTRAL_660" | "SPECTRAL_NM660"  => Ok(SPECTRAL_660),
            "SPECTRAL_670" | "SPECTRAL_NM670"  => Ok(SPECTRAL_670),
            "SPECTRAL_680" | "SPECTRAL_NM680"  => Ok(SPECTRAL_680),
            "SPECTRAL_690" | "SPECTRAL_NM690"  => Ok(SPECTRAL_690),
            "SPECTRAL_700" | "SPECTRAL_NM700"  => Ok(SPECTRAL_700),
            "SPECTRAL_710" | "SPECTRAL_NM710"  => Ok(SPECTRAL_710),
            "SPECTRAL_720" | "SPECTRAL_NM720"  => Ok(SPECTRAL_720),
            "SPECTRAL_730" | "SPECTRAL_NM730"  => Ok(SPECTRAL_730),
            "SPECTRAL_740" | "SPECTRAL_NM740"  => Ok(SPECTRAL_740),
            "SPECTRAL_750" | "SPECTRAL_NM750"  => Ok(SPECTRAL_750),
            "SPECTRAL_760" | "SPECTRAL_NM760"  => Ok(SPECTRAL_760),
            "SPECTRAL_770" | "SPECTRAL_NM770"  => Ok(SPECTRAL_770),
            "SPECTRAL_780" | "SPECTRAL_NM780"  => Ok(SPECTRAL_780),
            "SPECTRAL_790" | "SPECTRAL_NM790"  => Ok(SPECTRAL_790),
            "SPECTRAL_800" | "SPECTRAL_NM800"  => Ok(SPECTRAL_800),
            "SPECTRAL_810" | "SPECTRAL_NM810"  => Ok(SPECTRAL_810),
            "SPECTRAL_820" | "SPECTRAL_NM820"  => Ok(SPECTRAL_820),
            "SPECTRAL_830" | "SPECTRAL_NM830"  => Ok(SPECTRAL_830),
            other => Ok(Other(other.into())),
        }
    }
}