gb_cart 0.5.1

GB/CGB file header library and utilities.
Documentation
// SPDX-License-Identifier: LGPL-2.1-or-later OR GPL-2.0-or-later OR MPL-2.0
// SPDX-FileCopyrightText: 2026 Gabriel Marcano <gabemarcano@yahoo.com>

/// Macro that helps generate supporting logic for the large Licensee and related tables
macro_rules! licensee_table {
    // Entry point
    ($enum_name:ident : $type:ty  : $(#[$meta:meta])* -- $($rest:tt)*) => {
        licensee_table! {
            @munch
            ($enum_name, data, fmt, $type, $(#[$meta])*) // metadata/docs
            () // Variants
            () // From<$type> arms
            () // From<$enum_name> arms
            () // Display arms
            $($rest)* // everything else
        }
    };

    // Case 1: multiple values inside []
    (
        @munch
        ($enum_name:ident, $data:ident, $fmt:ident, $type:ty, $(#[$meta:meta])*)
        ($($variants:tt)*)
        ($($from_arms:tt)*)
        ($($from_enum_arms:tt)*)
        ($($display_arms:tt)*)
        $variant:ident => [ $($v:expr),+ ] => $name:expr, $($rest:tt)*
    ) => {
        licensee_table! {
            @munch ($enum_name, $data, $fmt, $type, $(#[$meta])*)
            ($($variants)* $variant($type),)
            ($($from_arms)* $($v)|* => Self::$variant($data),)
            ($($from_enum_arms)* $enum_name::$variant(value) => value,)
            ($($display_arms)* Self::$variant(_) => $fmt.write_str($name),)
            $($rest)*
        }
    };

    // Case 2: single value without []
    (
        @munch
        ($enum_name:ident, $data:ident, $fmt:ident, $type:ty, $(#[$meta:meta])*)
        ($($variants:tt)*)
        ($($from_arms:tt)*)
        ($($from_enum_arms:tt)*)
        ($($display_arms:tt)*)
        $variant:ident => $v:expr => $name:expr, $($rest:tt)*
    ) => {
        licensee_table! {
            @munch ($enum_name, $data, $fmt, $type, $(#[$meta])*)
            ($($variants)* $variant,)
            ($($from_arms)* $v => Self::$variant,)
            ($($from_enum_arms)* $enum_name::$variant => $v,)
            ($($display_arms)* Self::$variant => $fmt.write_str($name),)
            $($rest)*
        }
    };

    // Putting everything together...
    (
        @munch
        ($enum_name:ident, $data:ident, $fmt:ident, $type:ty, $(#[$meta:meta])*)
        ($($variants:tt)*)
        ($($from_arms:tt)*)
        ($($from_enum_arms:tt)*)
        ($($display_arms:tt)*)
    ) => {
        $(#[$meta])*
        #[non_exhaustive]
        #[derive(Debug, Copy, Clone)]
        pub enum $enum_name {
            $($variants)*
            Unknown($type),
        }

        impl From<$type> for $enum_name {
            fn from($data: $type) -> Self {
                match $data {
                    $($from_arms)*
                    _ => Self::Unknown($data),
                }
            }
        }

        impl From<$enum_name> for $type {
            fn from(data: $enum_name) -> Self {
                match data {
                    $($from_enum_arms)*
                    $enum_name::Unknown(v) => v,
                }
            }
        }

        impl std::fmt::Display for $enum_name {
            fn fmt(&self, $fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
                match self {
                    $($display_arms)*
                    Self::Unknown(value) => write!($fmt, "Unknown ({value})"),
                }
            }
        }
    };
}

licensee_table! { Licensee: u8:
/// Represents companies that were/are licensed to develop for the GB/CGB.
///
/// There is a place-holder value, [`Licensee::NewLicenseeField`], indicating that the real
/// licensee is in a different field in the header.
--
    None                   => 0x00               => "None",
    Nintendo               => [0x01, 0x31]       => "Nintendo",
    Capcom                 => [0x08, 0x38]       => "Capcom",
    HotB                   => 0x09               => "HOT-B",
    Jaleco                 => [0x0A, 0xE0]       => "Jaleco",
    Coconuts               => 0x0B               => "Coconuts Japan",
    EliteSystems           => [0x0C, 0x6E]       => "Elite Systems",
    ElectronicArts         => [0x13, 0x69]       => "EA (Electronic Arts)",
    Hudsonsoft             => [0x14, 0x20]       => "Hudson Soft",
    ItcEntertainment       => 0x18               => "ITC Entertainment",
    Yanoman                => 0x19               => "Yanoman",
    Clary                  => 0x1A               => "Japan Clary",
    Virgin                 => 0x1D               => "Virgin Games Ltd.",
    Kss                    => [0x1F, 0x4A, 0x61] => "KSS",
    PcmComplete            => 0x24               => "PCM Complete",
    SanX                   => 0x25               => "San-X",
    KotobukiSystems        => 0x28               => "Kemco",
    Seta                   => 0x29               => "SETA Corporation",
    Infogrames             => [0x30, 0x70]       => "Infogrames",
    Bandai                 => [0x32, 0xA2, 0xB2] => "Bandai",
    NewLicenseeField       => 0x33               => "Check New Licensee Field",
    Konami                 => [0x34, 0xA4]       => "Konami",
    Hector                 => 0x35               => "HectorSoft",
    Banpresto              => [0x39, 0x9D, 0xD9] => "Banpresto",
    EntertainmentI         => 0x3C               => ".Entertainment i",
    Gremlin                => 0x3E               => "Gremlin",
    Ubisoft                => 0x41               => "Ubi Soft",
    Atlus                  => [0x42, 0xEB]       => "Atlus",
    Malibu                 => [0x44, 0x4D]       => "Malibu Interactive",
    Angel                  => [0x46, 0xCF]       => "Angel",
    SpectrumHoloby         => 0x47               => "Spectrum Holoby",
    Irem                   => 0x49               => "Irem",
    USGold                 => 0x4F               => "U.S. Gold",
    Absolute               => 0x50               => "Absolute",
    Acclaim                => [0x51, 0xB0]       => "Acclaim Entertainment",
    Activision             => 0x52               => "Activision",
    AmericanSammy          => 0x53               => "Sammy USA Corporation",
    Gametek                => 0x54               => "GameTek",
    ParkPlace              => 0x55               => "Park Place",
    Ljn                    => [0x56, 0xDB, 0xFF] => "LJN",
    Matchbox               => 0x57               => "Matchbox",
    MiltonBradley          => 0x59               => "Milton Bradley Company",
    Mindscape              => 0x5A               => "Mindscape",
    Romstar                => 0x5B               => "Romstar",
    NaxatSoft              => [0x5C, 0xD6]       => "Naxat Soft",
    Tradewest              => 0x5D               => "Tradewest",
    Titus                  => 0x60               => "Titus Interactive",
    Ocean                  => 0x67               => "Ocean Software",
    ElectroBrain           => 0x6F               => "Electro Brain",
    Interplay              => 0x71               => "Interplay Entertainment",
    Broderbund             => [0x72, 0xAA]       => "Broderbund",
    SculpteredSoft         => 0x73               => "Sculptured Software",
    TheSalesCurve          => 0x75               => "The Sales Curve Limited",
    THq                    => 0x78               => "THQ",
    Accolade               => 0x79               => "Accolade",
    TriffixEntertainment   => 0x7A               => "Triffix Entertainment",
    Microprose             => 0x7C               => "Microprose",
    Kemco                  => [0x7F, 0xC2]       => "Kemco",
    MisawaEntertainment    => 0x80               => "Misawa Entertainment",
    Lozc                   => 0x83               => "Lozc",
    TokumaShotenIntermedia => [0x86, 0xC4]       => "Tokuma Shoten",
    BulletProofSoftware    => 0x8B               => "Bullet-Proof Software",
    VicTokai               => 0x8C               => "Vic Tokai",
    Ape                    => 0x8E               => "Ape",
    IMax                   => 0x8F               => "I’Max",
    ChunSoft               => 0x91               => "Chunsoft Co.",
    VideoSystem            => 0x92               => "Video System",
    Tsuburava              => 0x93               => "Tsubaraya Productions",
    Varie                  => [0x95, 0xE3]       => "Varie",
    YonezawaSPal           => 0x96               => "Yonezawa/S’Pal",
    Kaneko                 => 0x97               => "Kaneco",
    Arc                    => 0x99               => "Arc",
    NihonBussan            => 0x9A               => "Nihon Bussan",
    Tecmo                  => 0x9B               => "Tecmo",
    Imagineer              => 0x9C               => "Imagineer",
    Nova                   => 0x9F               => "Nova",
    HoriElectric           => 0xA1               => "Hori Electric",
    Kawada                 => 0xA6               => "Kawada",
    Takara                 => 0xA7               => "Takara",
    TechnosJapan           => 0xA9               => "Technos Japan",
    ToeiAnimation          => 0xAC               => "Toei Animation",
    Toho                   => 0xAD               => "Toho",
    Namco                  => 0xAF               => "Namco",
    AsciiOrNexoft          => 0xB1               => "ASCII Corporation or Nexsoft",
    Enix                   => 0xB4               => "Square Enix",
    Hal                    => 0xB6               => "HAL Laboratory",
    Snk                    => 0xB7               => "SNK",
    PonyCanyon             => 0xB9               => "Pony Canyon",
    CultureBrainO          => 0xBA               => "Culture Brain",
    Sunsoft                => 0xBB               => "Sunsoft",
    SonyImagesoft          => 0xBD               => "Sony Imagesoft",
    Sammy                  => 0xBF               => "Sammy Corporation",
    Taito                  => [0xC0, 0xD0]       => "Taito",
    Squaresoft             => 0xC3               => "Square",
    DataEast               => 0xC5               => "Data East",
    TonkinHouse            => 0xC6               => "Tonkinhouse",
    Koei                   => 0xC8               => "Koei",
    Ufl                    => 0xC9               => "UFL",
    Ultra                  => 0xCA               => "Ultra",
    Vap                    => 0xCB               => "Vap",
    Use                    => 0xCC               => "Use Corporation",
    Meldac                 => 0xCD               => "Meldac",
    PonyCanyonOr           => 0xCE               => "Pony Canyon",
    Sofel                  => 0xD1               => "Sofel",
    Quest                  => 0xD2               => "Quest",
    SigmaEnterprises       => 0xD3               => "Sigma Enterprises",
    AskKodansha            => 0xD4               => "ASK Kodansha Co.",
    CopyaSystems           => 0xD7               => "Copya System",
    Tomy                   => 0xDA               => "Tomy",
    Ncs                    => 0xDD               => "NCS",
    Human                  => 0xDE               => "Human",
    Altron                 => 0xDF               => "Altron",
    Towachiki              => 0xE1               => "Towa Chiki",
    Uutaka                 => 0xE2               => "Yutaka",
    Epoch                  => 0xE5               => "Epcoh",
    Athena                 => 0xE7               => "Athena",
    Asmik                  => 0xE8               => "Asmik Ace Entertainment",
    Natsume                => 0xE9               => "Natsume",
    KingRecords            => 0xEA               => "King Records",
    EpicSonyRecords        => 0xEC               => "Epic/Sony Records",
    Igs                    => 0xEE               => "IGS",
    AWave                  => 0xF0               => "A Wave",
    ExtremeEntertainment   => 0xF3               => "Extreme Entertainment",
}

//Nintendo =>             [1 | 49] =>              //"Nintendo Research & Development 1")?,
licensee_table! { NewLicensee: u16:
/// Represents companies that were/are licensed to develop for the GB/CGB.
///
/// These values are present in the header if and only if the
/// [`Metadata::licensee`](crate::metadata::Metadata::licensee) field is [`Licensee::NewLicenseeField`].
--
    None                => 0x3030           => "None",
    Nintendo            => [0x3130, 0x3133] => "Nintendo",
    Capcom              => 0x3830           => "Capcom",
    ElectronicArts      => [0x3331, 0x3936] => "EA (Electronic Arts)",
    Hudsonsoft          => 0x3831           => "Hudson Soft",
    BAi                 => 0x3931           => "B-AI",
    Kss                 => 0x3032           => "KSS",
    Pow                 => 0x3232           => "Planning Office WADA",
    PcmComplete         => 0x3432           => "PCM Complete",
    SanX                => 0x3532           => "San-X",
    KemcoJapan          => 0x3832           => "Kemco",
    Seta                => 0x3932           => "SETA Corporation",
    Viacom              => 0x3033           => "Viacom",
    Bandia              => 0x3233           => "Bandai",
    OceanAcclaim        => [0x3333, 0x3339] => "Ocean Software/Acclaim Entertainment",
    Konami              => [0x3433, 0x3435] => "Konami",
    Hector              => 0x3533           => "HectorSoft",
    Taito               => 0x3733           => "Taito",
    Hudson              => 0x3833           => "Hudson Soft",
    Banpresto           => 0x3933           => "Banpresto",
    UbiSoft             => 0x3134           => "Ubi Soft",
    Atlus               => 0x3234           => "Atlus",
    Malibu              => 0x3434           => "Malibu Interactive",
    Angel               => 0x3634           => "Angel",
    PulletProof         => 0x3734           => "Bullet-Proof Software",
    Irem                => 0x3934           => "Irem",
    Absolute            => 0x3035           => "Absolute",
    Acclaim             => 0x3135           => "Acclaim Entertainment",
    Activision          => 0x3235           => "Activision",
    AmericanSammy       => 0x3335           => "Sammy USA Corporation",
    HiTechEntertainment => 0x3535           => "Hi Tech Expressions",
    Ljn                 => 0x3635           => "LJN",
    Matchbox            => 0x3735           => "Matchbox",
    Mattel              => 0x3835           => "Mattel",
    MiltonBradley       => 0x3935           => "Milton Bradley Company",
    Titus               => 0x3036           => "Titus Interactive",
    Virgin              => 0x3136           => "Virgin Games Ltd.",
    Lucasarts           => 0x3436           => "Lucasfilm Games",
    Ocean               => 0x3736           => "Ocean Software",
    Infogrames          => 0x3037           => "Infogrames",
    Interplay           => 0x3137           => "Interplay Entertainment",
    Broderbund          => 0x3237           => "Broderbund",
    Sculptured          => 0x3337           => "Sculptured Software",
    Sci                 => 0x3537           => "The Sales Curve Limited",
    THq                 => 0x3837           => "THQ",
    Accolade            => 0x3937           => "Accolade",
    Misawa              => 0x3038           => "Misawa Entertainment",
    Lozc                => 0x3338           => "lozc",
    TokumaShotenI       => 0x3638           => "Tokuma Shoten",
    TsukudaOri          => 0x3738           => "Tsukuda Original",
    ChunSoft            => 0x3139           => "Chunsoft Co.",
    VideoSystem         => 0x3239           => "Video System",
    Varie               => 0x3539           => "Varie",
    YonezawaSPal        => 0x3639           => "Yonezawa/s’pal",
    Kaneko              => 0x3739           => "Kaneko",
    PackInSoft          => 0x3939           => "Pack-In-Video",
    BottomUp            => 0x4839           => "Bottom Up",
    KonamiYuGiOh        => 0x3441           => "Konami (Yu-Gi-Oh!)",
    Mto                 => 0x4C42           => "MTO",
    Kodansha            => 0x4B44           => "Kodansha",
}

impl From<[u8; 2]> for NewLicensee {
    fn from(field: [u8; 2]) -> Self {
        u16::from_le_bytes(field).into()
    }
}

impl From<NewLicensee> for [u8; 2] {
    fn from(field: NewLicensee) -> Self {
        let result: u16 = field.into();
        u16::to_le_bytes(result)
    }
}