// @generated by fit-codegen. DO NOT EDIT.
// Source: guide/garmin_fit_guide/Profile.xlsx

//! Auto-generated FIT enum types. Each enum corresponds to a row in the
//! Types sheet of Profile.xlsx that has a non-empty list of named values.
//! `mesg_num` is split into its own module (see `super::mesg_num`).

#![allow(non_camel_case_types, dead_code, clippy::should_implement_trait)]

use super::mesg_num::MesgNum;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum File {
    Device = 1,
    Settings = 2,
    Sport = 3,
    Activity = 4,
    Workout = 5,
    Course = 6,
    Schedules = 7,
    Weight = 9,
    Totals = 10,
    Goals = 11,
    BloodPressure = 14,
    MonitoringA = 15,
    ActivitySummary = 20,
    MonitoringDaily = 28,
    MonitoringB = 32,
    Segment = 34,
    SegmentList = 35,
    ExdConfiguration = 40,
    MfgRangeMin = 247,
    MfgRangeMax = 254,
}

impl File {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            File::Device => "device",
            File::Settings => "settings",
            File::Sport => "sport",
            File::Activity => "activity",
            File::Workout => "workout",
            File::Course => "course",
            File::Schedules => "schedules",
            File::Weight => "weight",
            File::Totals => "totals",
            File::Goals => "goals",
            File::BloodPressure => "blood_pressure",
            File::MonitoringA => "monitoring_a",
            File::ActivitySummary => "activity_summary",
            File::MonitoringDaily => "monitoring_daily",
            File::MonitoringB => "monitoring_b",
            File::Segment => "segment",
            File::SegmentList => "segment_list",
            File::ExdConfiguration => "exd_configuration",
            File::MfgRangeMin => "mfg_range_min",
            File::MfgRangeMax => "mfg_range_max",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            1 => Some(File::Device),
            2 => Some(File::Settings),
            3 => Some(File::Sport),
            4 => Some(File::Activity),
            5 => Some(File::Workout),
            6 => Some(File::Course),
            7 => Some(File::Schedules),
            9 => Some(File::Weight),
            10 => Some(File::Totals),
            11 => Some(File::Goals),
            14 => Some(File::BloodPressure),
            15 => Some(File::MonitoringA),
            20 => Some(File::ActivitySummary),
            28 => Some(File::MonitoringDaily),
            32 => Some(File::MonitoringB),
            34 => Some(File::Segment),
            35 => Some(File::SegmentList),
            40 => Some(File::ExdConfiguration),
            247 => Some(File::MfgRangeMin),
            254 => Some(File::MfgRangeMax),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "device" => Some(File::Device),
            "settings" => Some(File::Settings),
            "sport" => Some(File::Sport),
            "activity" => Some(File::Activity),
            "workout" => Some(File::Workout),
            "course" => Some(File::Course),
            "schedules" => Some(File::Schedules),
            "weight" => Some(File::Weight),
            "totals" => Some(File::Totals),
            "goals" => Some(File::Goals),
            "blood_pressure" => Some(File::BloodPressure),
            "monitoring_a" => Some(File::MonitoringA),
            "activity_summary" => Some(File::ActivitySummary),
            "monitoring_daily" => Some(File::MonitoringDaily),
            "monitoring_b" => Some(File::MonitoringB),
            "segment" => Some(File::Segment),
            "segment_list" => Some(File::SegmentList),
            "exd_configuration" => Some(File::ExdConfiguration),
            "mfg_range_min" => Some(File::MfgRangeMin),
            "mfg_range_max" => Some(File::MfgRangeMax),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum Checksum {
    Clear = 0,
    Ok = 1,
}

impl Checksum {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            Checksum::Clear => "clear",
            Checksum::Ok => "ok",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(Checksum::Clear),
            1 => Some(Checksum::Ok),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "clear" => Some(Checksum::Clear),
            "ok" => Some(Checksum::Ok),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum FileFlags {
    Read = 2,
    Write = 4,
    Erase = 8,
}

impl FileFlags {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            FileFlags::Read => "read",
            FileFlags::Write => "write",
            FileFlags::Erase => "erase",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            2 => Some(FileFlags::Read),
            4 => Some(FileFlags::Write),
            8 => Some(FileFlags::Erase),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "read" => Some(FileFlags::Read),
            "write" => Some(FileFlags::Write),
            "erase" => Some(FileFlags::Erase),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum MesgCount {
    NumPerFile = 0,
    MaxPerFile = 1,
    MaxPerFileType = 2,
}

impl MesgCount {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            MesgCount::NumPerFile => "num_per_file",
            MesgCount::MaxPerFile => "max_per_file",
            MesgCount::MaxPerFileType => "max_per_file_type",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(MesgCount::NumPerFile),
            1 => Some(MesgCount::MaxPerFile),
            2 => Some(MesgCount::MaxPerFileType),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "num_per_file" => Some(MesgCount::NumPerFile),
            "max_per_file" => Some(MesgCount::MaxPerFile),
            "max_per_file_type" => Some(MesgCount::MaxPerFileType),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u32)]
#[non_exhaustive]
pub enum DateTime {
    Min = 268435456,
}

impl DateTime {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            DateTime::Min => "min",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u32) -> Option<Self> {
        match value {
            268435456 => Some(DateTime::Min),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "min" => Some(DateTime::Min),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u32)]
#[non_exhaustive]
pub enum LocalDateTime {
    Min = 268435456,
}

impl LocalDateTime {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            LocalDateTime::Min => "min",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u32) -> Option<Self> {
        match value {
            268435456 => Some(LocalDateTime::Min),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "min" => Some(LocalDateTime::Min),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum MessageIndex {
    Selected = 32768,
    Reserved = 28672,
    Mask = 4095,
}

impl MessageIndex {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            MessageIndex::Selected => "selected",
            MessageIndex::Reserved => "reserved",
            MessageIndex::Mask => "mask",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            32768 => Some(MessageIndex::Selected),
            28672 => Some(MessageIndex::Reserved),
            4095 => Some(MessageIndex::Mask),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "selected" => Some(MessageIndex::Selected),
            "reserved" => Some(MessageIndex::Reserved),
            "mask" => Some(MessageIndex::Mask),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum DeviceIndex {
    Creator = 0,
}

impl DeviceIndex {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            DeviceIndex::Creator => "creator",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(DeviceIndex::Creator),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "creator" => Some(DeviceIndex::Creator),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum Gender {
    Female = 0,
    Male = 1,
}

impl Gender {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            Gender::Female => "female",
            Gender::Male => "male",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(Gender::Female),
            1 => Some(Gender::Male),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "female" => Some(Gender::Female),
            "male" => Some(Gender::Male),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum Language {
    English = 0,
    French = 1,
    Italian = 2,
    German = 3,
    Spanish = 4,
    Croatian = 5,
    Czech = 6,
    Danish = 7,
    Dutch = 8,
    Finnish = 9,
    Greek = 10,
    Hungarian = 11,
    Norwegian = 12,
    Polish = 13,
    Portuguese = 14,
    Slovakian = 15,
    Slovenian = 16,
    Swedish = 17,
    Russian = 18,
    Turkish = 19,
    Latvian = 20,
    Ukrainian = 21,
    Arabic = 22,
    Farsi = 23,
    Bulgarian = 24,
    Romanian = 25,
    Chinese = 26,
    Japanese = 27,
    Korean = 28,
    Taiwanese = 29,
    Thai = 30,
    Hebrew = 31,
    BrazilianPortuguese = 32,
    Indonesian = 33,
    Malaysian = 34,
    Vietnamese = 35,
    Burmese = 36,
    Mongolian = 37,
    Custom = 254,
}

impl Language {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            Language::English => "english",
            Language::French => "french",
            Language::Italian => "italian",
            Language::German => "german",
            Language::Spanish => "spanish",
            Language::Croatian => "croatian",
            Language::Czech => "czech",
            Language::Danish => "danish",
            Language::Dutch => "dutch",
            Language::Finnish => "finnish",
            Language::Greek => "greek",
            Language::Hungarian => "hungarian",
            Language::Norwegian => "norwegian",
            Language::Polish => "polish",
            Language::Portuguese => "portuguese",
            Language::Slovakian => "slovakian",
            Language::Slovenian => "slovenian",
            Language::Swedish => "swedish",
            Language::Russian => "russian",
            Language::Turkish => "turkish",
            Language::Latvian => "latvian",
            Language::Ukrainian => "ukrainian",
            Language::Arabic => "arabic",
            Language::Farsi => "farsi",
            Language::Bulgarian => "bulgarian",
            Language::Romanian => "romanian",
            Language::Chinese => "chinese",
            Language::Japanese => "japanese",
            Language::Korean => "korean",
            Language::Taiwanese => "taiwanese",
            Language::Thai => "thai",
            Language::Hebrew => "hebrew",
            Language::BrazilianPortuguese => "brazilian_portuguese",
            Language::Indonesian => "indonesian",
            Language::Malaysian => "malaysian",
            Language::Vietnamese => "vietnamese",
            Language::Burmese => "burmese",
            Language::Mongolian => "mongolian",
            Language::Custom => "custom",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(Language::English),
            1 => Some(Language::French),
            2 => Some(Language::Italian),
            3 => Some(Language::German),
            4 => Some(Language::Spanish),
            5 => Some(Language::Croatian),
            6 => Some(Language::Czech),
            7 => Some(Language::Danish),
            8 => Some(Language::Dutch),
            9 => Some(Language::Finnish),
            10 => Some(Language::Greek),
            11 => Some(Language::Hungarian),
            12 => Some(Language::Norwegian),
            13 => Some(Language::Polish),
            14 => Some(Language::Portuguese),
            15 => Some(Language::Slovakian),
            16 => Some(Language::Slovenian),
            17 => Some(Language::Swedish),
            18 => Some(Language::Russian),
            19 => Some(Language::Turkish),
            20 => Some(Language::Latvian),
            21 => Some(Language::Ukrainian),
            22 => Some(Language::Arabic),
            23 => Some(Language::Farsi),
            24 => Some(Language::Bulgarian),
            25 => Some(Language::Romanian),
            26 => Some(Language::Chinese),
            27 => Some(Language::Japanese),
            28 => Some(Language::Korean),
            29 => Some(Language::Taiwanese),
            30 => Some(Language::Thai),
            31 => Some(Language::Hebrew),
            32 => Some(Language::BrazilianPortuguese),
            33 => Some(Language::Indonesian),
            34 => Some(Language::Malaysian),
            35 => Some(Language::Vietnamese),
            36 => Some(Language::Burmese),
            37 => Some(Language::Mongolian),
            254 => Some(Language::Custom),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "english" => Some(Language::English),
            "french" => Some(Language::French),
            "italian" => Some(Language::Italian),
            "german" => Some(Language::German),
            "spanish" => Some(Language::Spanish),
            "croatian" => Some(Language::Croatian),
            "czech" => Some(Language::Czech),
            "danish" => Some(Language::Danish),
            "dutch" => Some(Language::Dutch),
            "finnish" => Some(Language::Finnish),
            "greek" => Some(Language::Greek),
            "hungarian" => Some(Language::Hungarian),
            "norwegian" => Some(Language::Norwegian),
            "polish" => Some(Language::Polish),
            "portuguese" => Some(Language::Portuguese),
            "slovakian" => Some(Language::Slovakian),
            "slovenian" => Some(Language::Slovenian),
            "swedish" => Some(Language::Swedish),
            "russian" => Some(Language::Russian),
            "turkish" => Some(Language::Turkish),
            "latvian" => Some(Language::Latvian),
            "ukrainian" => Some(Language::Ukrainian),
            "arabic" => Some(Language::Arabic),
            "farsi" => Some(Language::Farsi),
            "bulgarian" => Some(Language::Bulgarian),
            "romanian" => Some(Language::Romanian),
            "chinese" => Some(Language::Chinese),
            "japanese" => Some(Language::Japanese),
            "korean" => Some(Language::Korean),
            "taiwanese" => Some(Language::Taiwanese),
            "thai" => Some(Language::Thai),
            "hebrew" => Some(Language::Hebrew),
            "brazilian_portuguese" => Some(Language::BrazilianPortuguese),
            "indonesian" => Some(Language::Indonesian),
            "malaysian" => Some(Language::Malaysian),
            "vietnamese" => Some(Language::Vietnamese),
            "burmese" => Some(Language::Burmese),
            "mongolian" => Some(Language::Mongolian),
            "custom" => Some(Language::Custom),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum LanguageBits0 {
    English = 1,
    French = 2,
    Italian = 4,
    German = 8,
    Spanish = 16,
    Croatian = 32,
    Czech = 64,
    Danish = 128,
}

impl LanguageBits0 {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            LanguageBits0::English => "english",
            LanguageBits0::French => "french",
            LanguageBits0::Italian => "italian",
            LanguageBits0::German => "german",
            LanguageBits0::Spanish => "spanish",
            LanguageBits0::Croatian => "croatian",
            LanguageBits0::Czech => "czech",
            LanguageBits0::Danish => "danish",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            1 => Some(LanguageBits0::English),
            2 => Some(LanguageBits0::French),
            4 => Some(LanguageBits0::Italian),
            8 => Some(LanguageBits0::German),
            16 => Some(LanguageBits0::Spanish),
            32 => Some(LanguageBits0::Croatian),
            64 => Some(LanguageBits0::Czech),
            128 => Some(LanguageBits0::Danish),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "english" => Some(LanguageBits0::English),
            "french" => Some(LanguageBits0::French),
            "italian" => Some(LanguageBits0::Italian),
            "german" => Some(LanguageBits0::German),
            "spanish" => Some(LanguageBits0::Spanish),
            "croatian" => Some(LanguageBits0::Croatian),
            "czech" => Some(LanguageBits0::Czech),
            "danish" => Some(LanguageBits0::Danish),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum LanguageBits1 {
    Dutch = 1,
    Finnish = 2,
    Greek = 4,
    Hungarian = 8,
    Norwegian = 16,
    Polish = 32,
    Portuguese = 64,
    Slovakian = 128,
}

impl LanguageBits1 {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            LanguageBits1::Dutch => "dutch",
            LanguageBits1::Finnish => "finnish",
            LanguageBits1::Greek => "greek",
            LanguageBits1::Hungarian => "hungarian",
            LanguageBits1::Norwegian => "norwegian",
            LanguageBits1::Polish => "polish",
            LanguageBits1::Portuguese => "portuguese",
            LanguageBits1::Slovakian => "slovakian",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            1 => Some(LanguageBits1::Dutch),
            2 => Some(LanguageBits1::Finnish),
            4 => Some(LanguageBits1::Greek),
            8 => Some(LanguageBits1::Hungarian),
            16 => Some(LanguageBits1::Norwegian),
            32 => Some(LanguageBits1::Polish),
            64 => Some(LanguageBits1::Portuguese),
            128 => Some(LanguageBits1::Slovakian),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "dutch" => Some(LanguageBits1::Dutch),
            "finnish" => Some(LanguageBits1::Finnish),
            "greek" => Some(LanguageBits1::Greek),
            "hungarian" => Some(LanguageBits1::Hungarian),
            "norwegian" => Some(LanguageBits1::Norwegian),
            "polish" => Some(LanguageBits1::Polish),
            "portuguese" => Some(LanguageBits1::Portuguese),
            "slovakian" => Some(LanguageBits1::Slovakian),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum LanguageBits2 {
    Slovenian = 1,
    Swedish = 2,
    Russian = 4,
    Turkish = 8,
    Latvian = 16,
    Ukrainian = 32,
    Arabic = 64,
    Farsi = 128,
}

impl LanguageBits2 {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            LanguageBits2::Slovenian => "slovenian",
            LanguageBits2::Swedish => "swedish",
            LanguageBits2::Russian => "russian",
            LanguageBits2::Turkish => "turkish",
            LanguageBits2::Latvian => "latvian",
            LanguageBits2::Ukrainian => "ukrainian",
            LanguageBits2::Arabic => "arabic",
            LanguageBits2::Farsi => "farsi",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            1 => Some(LanguageBits2::Slovenian),
            2 => Some(LanguageBits2::Swedish),
            4 => Some(LanguageBits2::Russian),
            8 => Some(LanguageBits2::Turkish),
            16 => Some(LanguageBits2::Latvian),
            32 => Some(LanguageBits2::Ukrainian),
            64 => Some(LanguageBits2::Arabic),
            128 => Some(LanguageBits2::Farsi),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "slovenian" => Some(LanguageBits2::Slovenian),
            "swedish" => Some(LanguageBits2::Swedish),
            "russian" => Some(LanguageBits2::Russian),
            "turkish" => Some(LanguageBits2::Turkish),
            "latvian" => Some(LanguageBits2::Latvian),
            "ukrainian" => Some(LanguageBits2::Ukrainian),
            "arabic" => Some(LanguageBits2::Arabic),
            "farsi" => Some(LanguageBits2::Farsi),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum LanguageBits3 {
    Bulgarian = 1,
    Romanian = 2,
    Chinese = 4,
    Japanese = 8,
    Korean = 16,
    Taiwanese = 32,
    Thai = 64,
    Hebrew = 128,
}

impl LanguageBits3 {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            LanguageBits3::Bulgarian => "bulgarian",
            LanguageBits3::Romanian => "romanian",
            LanguageBits3::Chinese => "chinese",
            LanguageBits3::Japanese => "japanese",
            LanguageBits3::Korean => "korean",
            LanguageBits3::Taiwanese => "taiwanese",
            LanguageBits3::Thai => "thai",
            LanguageBits3::Hebrew => "hebrew",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            1 => Some(LanguageBits3::Bulgarian),
            2 => Some(LanguageBits3::Romanian),
            4 => Some(LanguageBits3::Chinese),
            8 => Some(LanguageBits3::Japanese),
            16 => Some(LanguageBits3::Korean),
            32 => Some(LanguageBits3::Taiwanese),
            64 => Some(LanguageBits3::Thai),
            128 => Some(LanguageBits3::Hebrew),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "bulgarian" => Some(LanguageBits3::Bulgarian),
            "romanian" => Some(LanguageBits3::Romanian),
            "chinese" => Some(LanguageBits3::Chinese),
            "japanese" => Some(LanguageBits3::Japanese),
            "korean" => Some(LanguageBits3::Korean),
            "taiwanese" => Some(LanguageBits3::Taiwanese),
            "thai" => Some(LanguageBits3::Thai),
            "hebrew" => Some(LanguageBits3::Hebrew),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum LanguageBits4 {
    BrazilianPortuguese = 1,
    Indonesian = 2,
    Malaysian = 4,
    Vietnamese = 8,
    Burmese = 16,
    Mongolian = 32,
}

impl LanguageBits4 {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            LanguageBits4::BrazilianPortuguese => "brazilian_portuguese",
            LanguageBits4::Indonesian => "indonesian",
            LanguageBits4::Malaysian => "malaysian",
            LanguageBits4::Vietnamese => "vietnamese",
            LanguageBits4::Burmese => "burmese",
            LanguageBits4::Mongolian => "mongolian",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            1 => Some(LanguageBits4::BrazilianPortuguese),
            2 => Some(LanguageBits4::Indonesian),
            4 => Some(LanguageBits4::Malaysian),
            8 => Some(LanguageBits4::Vietnamese),
            16 => Some(LanguageBits4::Burmese),
            32 => Some(LanguageBits4::Mongolian),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "brazilian_portuguese" => Some(LanguageBits4::BrazilianPortuguese),
            "indonesian" => Some(LanguageBits4::Indonesian),
            "malaysian" => Some(LanguageBits4::Malaysian),
            "vietnamese" => Some(LanguageBits4::Vietnamese),
            "burmese" => Some(LanguageBits4::Burmese),
            "mongolian" => Some(LanguageBits4::Mongolian),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum TimeZone {
    Almaty = 0,
    Bangkok = 1,
    Bombay = 2,
    Brasilia = 3,
    Cairo = 4,
    CapeVerdeIs = 5,
    Darwin = 6,
    Eniwetok = 7,
    Fiji = 8,
    HongKong = 9,
    Islamabad = 10,
    Kabul = 11,
    Magadan = 12,
    MidAtlantic = 13,
    Moscow = 14,
    Muscat = 15,
    Newfoundland = 16,
    Samoa = 17,
    Sydney = 18,
    Tehran = 19,
    Tokyo = 20,
    UsAlaska = 21,
    UsAtlantic = 22,
    UsCentral = 23,
    UsEastern = 24,
    UsHawaii = 25,
    UsMountain = 26,
    UsPacific = 27,
    Other = 28,
    Auckland = 29,
    Kathmandu = 30,
    EuropeWesternWet = 31,
    EuropeCentralCet = 32,
    EuropeEasternEet = 33,
    Jakarta = 34,
    Perth = 35,
    Adelaide = 36,
    Brisbane = 37,
    Tasmania = 38,
    Iceland = 39,
    Amsterdam = 40,
    Athens = 41,
    Barcelona = 42,
    Berlin = 43,
    Brussels = 44,
    Budapest = 45,
    Copenhagen = 46,
    Dublin = 47,
    Helsinki = 48,
    Lisbon = 49,
    London = 50,
    Madrid = 51,
    Munich = 52,
    Oslo = 53,
    Paris = 54,
    Prague = 55,
    Reykjavik = 56,
    Rome = 57,
    Stockholm = 58,
    Vienna = 59,
    Warsaw = 60,
    Zurich = 61,
    Quebec = 62,
    Ontario = 63,
    Manitoba = 64,
    Saskatchewan = 65,
    Alberta = 66,
    BritishColumbia = 67,
    Boise = 68,
    Boston = 69,
    Chicago = 70,
    Dallas = 71,
    Denver = 72,
    KansasCity = 73,
    LasVegas = 74,
    LosAngeles = 75,
    Miami = 76,
    Minneapolis = 77,
    NewYork = 78,
    NewOrleans = 79,
    Phoenix = 80,
    SantaFe = 81,
    Seattle = 82,
    WashingtonDc = 83,
    UsArizona = 84,
    Chita = 85,
    Ekaterinburg = 86,
    Irkutsk = 87,
    Kaliningrad = 88,
    Krasnoyarsk = 89,
    Novosibirsk = 90,
    PetropavlovskKamchatskiy = 91,
    Samara = 92,
    Vladivostok = 93,
    MexicoCentral = 94,
    MexicoMountain = 95,
    MexicoPacific = 96,
    CapeTown = 97,
    Winkhoek = 98,
    Lagos = 99,
    Riyahd = 100,
    Venezuela = 101,
    AustraliaLh = 102,
    Santiago = 103,
    Manual = 253,
    Automatic = 254,
}

impl TimeZone {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            TimeZone::Almaty => "almaty",
            TimeZone::Bangkok => "bangkok",
            TimeZone::Bombay => "bombay",
            TimeZone::Brasilia => "brasilia",
            TimeZone::Cairo => "cairo",
            TimeZone::CapeVerdeIs => "cape_verde_is",
            TimeZone::Darwin => "darwin",
            TimeZone::Eniwetok => "eniwetok",
            TimeZone::Fiji => "fiji",
            TimeZone::HongKong => "hong_kong",
            TimeZone::Islamabad => "islamabad",
            TimeZone::Kabul => "kabul",
            TimeZone::Magadan => "magadan",
            TimeZone::MidAtlantic => "mid_atlantic",
            TimeZone::Moscow => "moscow",
            TimeZone::Muscat => "muscat",
            TimeZone::Newfoundland => "newfoundland",
            TimeZone::Samoa => "samoa",
            TimeZone::Sydney => "sydney",
            TimeZone::Tehran => "tehran",
            TimeZone::Tokyo => "tokyo",
            TimeZone::UsAlaska => "us_alaska",
            TimeZone::UsAtlantic => "us_atlantic",
            TimeZone::UsCentral => "us_central",
            TimeZone::UsEastern => "us_eastern",
            TimeZone::UsHawaii => "us_hawaii",
            TimeZone::UsMountain => "us_mountain",
            TimeZone::UsPacific => "us_pacific",
            TimeZone::Other => "other",
            TimeZone::Auckland => "auckland",
            TimeZone::Kathmandu => "kathmandu",
            TimeZone::EuropeWesternWet => "europe_western_wet",
            TimeZone::EuropeCentralCet => "europe_central_cet",
            TimeZone::EuropeEasternEet => "europe_eastern_eet",
            TimeZone::Jakarta => "jakarta",
            TimeZone::Perth => "perth",
            TimeZone::Adelaide => "adelaide",
            TimeZone::Brisbane => "brisbane",
            TimeZone::Tasmania => "tasmania",
            TimeZone::Iceland => "iceland",
            TimeZone::Amsterdam => "amsterdam",
            TimeZone::Athens => "athens",
            TimeZone::Barcelona => "barcelona",
            TimeZone::Berlin => "berlin",
            TimeZone::Brussels => "brussels",
            TimeZone::Budapest => "budapest",
            TimeZone::Copenhagen => "copenhagen",
            TimeZone::Dublin => "dublin",
            TimeZone::Helsinki => "helsinki",
            TimeZone::Lisbon => "lisbon",
            TimeZone::London => "london",
            TimeZone::Madrid => "madrid",
            TimeZone::Munich => "munich",
            TimeZone::Oslo => "oslo",
            TimeZone::Paris => "paris",
            TimeZone::Prague => "prague",
            TimeZone::Reykjavik => "reykjavik",
            TimeZone::Rome => "rome",
            TimeZone::Stockholm => "stockholm",
            TimeZone::Vienna => "vienna",
            TimeZone::Warsaw => "warsaw",
            TimeZone::Zurich => "zurich",
            TimeZone::Quebec => "quebec",
            TimeZone::Ontario => "ontario",
            TimeZone::Manitoba => "manitoba",
            TimeZone::Saskatchewan => "saskatchewan",
            TimeZone::Alberta => "alberta",
            TimeZone::BritishColumbia => "british_columbia",
            TimeZone::Boise => "boise",
            TimeZone::Boston => "boston",
            TimeZone::Chicago => "chicago",
            TimeZone::Dallas => "dallas",
            TimeZone::Denver => "denver",
            TimeZone::KansasCity => "kansas_city",
            TimeZone::LasVegas => "las_vegas",
            TimeZone::LosAngeles => "los_angeles",
            TimeZone::Miami => "miami",
            TimeZone::Minneapolis => "minneapolis",
            TimeZone::NewYork => "new_york",
            TimeZone::NewOrleans => "new_orleans",
            TimeZone::Phoenix => "phoenix",
            TimeZone::SantaFe => "santa_fe",
            TimeZone::Seattle => "seattle",
            TimeZone::WashingtonDc => "washington_dc",
            TimeZone::UsArizona => "us_arizona",
            TimeZone::Chita => "chita",
            TimeZone::Ekaterinburg => "ekaterinburg",
            TimeZone::Irkutsk => "irkutsk",
            TimeZone::Kaliningrad => "kaliningrad",
            TimeZone::Krasnoyarsk => "krasnoyarsk",
            TimeZone::Novosibirsk => "novosibirsk",
            TimeZone::PetropavlovskKamchatskiy => "petropavlovsk_kamchatskiy",
            TimeZone::Samara => "samara",
            TimeZone::Vladivostok => "vladivostok",
            TimeZone::MexicoCentral => "mexico_central",
            TimeZone::MexicoMountain => "mexico_mountain",
            TimeZone::MexicoPacific => "mexico_pacific",
            TimeZone::CapeTown => "cape_town",
            TimeZone::Winkhoek => "winkhoek",
            TimeZone::Lagos => "lagos",
            TimeZone::Riyahd => "riyahd",
            TimeZone::Venezuela => "venezuela",
            TimeZone::AustraliaLh => "australia_lh",
            TimeZone::Santiago => "santiago",
            TimeZone::Manual => "manual",
            TimeZone::Automatic => "automatic",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(TimeZone::Almaty),
            1 => Some(TimeZone::Bangkok),
            2 => Some(TimeZone::Bombay),
            3 => Some(TimeZone::Brasilia),
            4 => Some(TimeZone::Cairo),
            5 => Some(TimeZone::CapeVerdeIs),
            6 => Some(TimeZone::Darwin),
            7 => Some(TimeZone::Eniwetok),
            8 => Some(TimeZone::Fiji),
            9 => Some(TimeZone::HongKong),
            10 => Some(TimeZone::Islamabad),
            11 => Some(TimeZone::Kabul),
            12 => Some(TimeZone::Magadan),
            13 => Some(TimeZone::MidAtlantic),
            14 => Some(TimeZone::Moscow),
            15 => Some(TimeZone::Muscat),
            16 => Some(TimeZone::Newfoundland),
            17 => Some(TimeZone::Samoa),
            18 => Some(TimeZone::Sydney),
            19 => Some(TimeZone::Tehran),
            20 => Some(TimeZone::Tokyo),
            21 => Some(TimeZone::UsAlaska),
            22 => Some(TimeZone::UsAtlantic),
            23 => Some(TimeZone::UsCentral),
            24 => Some(TimeZone::UsEastern),
            25 => Some(TimeZone::UsHawaii),
            26 => Some(TimeZone::UsMountain),
            27 => Some(TimeZone::UsPacific),
            28 => Some(TimeZone::Other),
            29 => Some(TimeZone::Auckland),
            30 => Some(TimeZone::Kathmandu),
            31 => Some(TimeZone::EuropeWesternWet),
            32 => Some(TimeZone::EuropeCentralCet),
            33 => Some(TimeZone::EuropeEasternEet),
            34 => Some(TimeZone::Jakarta),
            35 => Some(TimeZone::Perth),
            36 => Some(TimeZone::Adelaide),
            37 => Some(TimeZone::Brisbane),
            38 => Some(TimeZone::Tasmania),
            39 => Some(TimeZone::Iceland),
            40 => Some(TimeZone::Amsterdam),
            41 => Some(TimeZone::Athens),
            42 => Some(TimeZone::Barcelona),
            43 => Some(TimeZone::Berlin),
            44 => Some(TimeZone::Brussels),
            45 => Some(TimeZone::Budapest),
            46 => Some(TimeZone::Copenhagen),
            47 => Some(TimeZone::Dublin),
            48 => Some(TimeZone::Helsinki),
            49 => Some(TimeZone::Lisbon),
            50 => Some(TimeZone::London),
            51 => Some(TimeZone::Madrid),
            52 => Some(TimeZone::Munich),
            53 => Some(TimeZone::Oslo),
            54 => Some(TimeZone::Paris),
            55 => Some(TimeZone::Prague),
            56 => Some(TimeZone::Reykjavik),
            57 => Some(TimeZone::Rome),
            58 => Some(TimeZone::Stockholm),
            59 => Some(TimeZone::Vienna),
            60 => Some(TimeZone::Warsaw),
            61 => Some(TimeZone::Zurich),
            62 => Some(TimeZone::Quebec),
            63 => Some(TimeZone::Ontario),
            64 => Some(TimeZone::Manitoba),
            65 => Some(TimeZone::Saskatchewan),
            66 => Some(TimeZone::Alberta),
            67 => Some(TimeZone::BritishColumbia),
            68 => Some(TimeZone::Boise),
            69 => Some(TimeZone::Boston),
            70 => Some(TimeZone::Chicago),
            71 => Some(TimeZone::Dallas),
            72 => Some(TimeZone::Denver),
            73 => Some(TimeZone::KansasCity),
            74 => Some(TimeZone::LasVegas),
            75 => Some(TimeZone::LosAngeles),
            76 => Some(TimeZone::Miami),
            77 => Some(TimeZone::Minneapolis),
            78 => Some(TimeZone::NewYork),
            79 => Some(TimeZone::NewOrleans),
            80 => Some(TimeZone::Phoenix),
            81 => Some(TimeZone::SantaFe),
            82 => Some(TimeZone::Seattle),
            83 => Some(TimeZone::WashingtonDc),
            84 => Some(TimeZone::UsArizona),
            85 => Some(TimeZone::Chita),
            86 => Some(TimeZone::Ekaterinburg),
            87 => Some(TimeZone::Irkutsk),
            88 => Some(TimeZone::Kaliningrad),
            89 => Some(TimeZone::Krasnoyarsk),
            90 => Some(TimeZone::Novosibirsk),
            91 => Some(TimeZone::PetropavlovskKamchatskiy),
            92 => Some(TimeZone::Samara),
            93 => Some(TimeZone::Vladivostok),
            94 => Some(TimeZone::MexicoCentral),
            95 => Some(TimeZone::MexicoMountain),
            96 => Some(TimeZone::MexicoPacific),
            97 => Some(TimeZone::CapeTown),
            98 => Some(TimeZone::Winkhoek),
            99 => Some(TimeZone::Lagos),
            100 => Some(TimeZone::Riyahd),
            101 => Some(TimeZone::Venezuela),
            102 => Some(TimeZone::AustraliaLh),
            103 => Some(TimeZone::Santiago),
            253 => Some(TimeZone::Manual),
            254 => Some(TimeZone::Automatic),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "almaty" => Some(TimeZone::Almaty),
            "bangkok" => Some(TimeZone::Bangkok),
            "bombay" => Some(TimeZone::Bombay),
            "brasilia" => Some(TimeZone::Brasilia),
            "cairo" => Some(TimeZone::Cairo),
            "cape_verde_is" => Some(TimeZone::CapeVerdeIs),
            "darwin" => Some(TimeZone::Darwin),
            "eniwetok" => Some(TimeZone::Eniwetok),
            "fiji" => Some(TimeZone::Fiji),
            "hong_kong" => Some(TimeZone::HongKong),
            "islamabad" => Some(TimeZone::Islamabad),
            "kabul" => Some(TimeZone::Kabul),
            "magadan" => Some(TimeZone::Magadan),
            "mid_atlantic" => Some(TimeZone::MidAtlantic),
            "moscow" => Some(TimeZone::Moscow),
            "muscat" => Some(TimeZone::Muscat),
            "newfoundland" => Some(TimeZone::Newfoundland),
            "samoa" => Some(TimeZone::Samoa),
            "sydney" => Some(TimeZone::Sydney),
            "tehran" => Some(TimeZone::Tehran),
            "tokyo" => Some(TimeZone::Tokyo),
            "us_alaska" => Some(TimeZone::UsAlaska),
            "us_atlantic" => Some(TimeZone::UsAtlantic),
            "us_central" => Some(TimeZone::UsCentral),
            "us_eastern" => Some(TimeZone::UsEastern),
            "us_hawaii" => Some(TimeZone::UsHawaii),
            "us_mountain" => Some(TimeZone::UsMountain),
            "us_pacific" => Some(TimeZone::UsPacific),
            "other" => Some(TimeZone::Other),
            "auckland" => Some(TimeZone::Auckland),
            "kathmandu" => Some(TimeZone::Kathmandu),
            "europe_western_wet" => Some(TimeZone::EuropeWesternWet),
            "europe_central_cet" => Some(TimeZone::EuropeCentralCet),
            "europe_eastern_eet" => Some(TimeZone::EuropeEasternEet),
            "jakarta" => Some(TimeZone::Jakarta),
            "perth" => Some(TimeZone::Perth),
            "adelaide" => Some(TimeZone::Adelaide),
            "brisbane" => Some(TimeZone::Brisbane),
            "tasmania" => Some(TimeZone::Tasmania),
            "iceland" => Some(TimeZone::Iceland),
            "amsterdam" => Some(TimeZone::Amsterdam),
            "athens" => Some(TimeZone::Athens),
            "barcelona" => Some(TimeZone::Barcelona),
            "berlin" => Some(TimeZone::Berlin),
            "brussels" => Some(TimeZone::Brussels),
            "budapest" => Some(TimeZone::Budapest),
            "copenhagen" => Some(TimeZone::Copenhagen),
            "dublin" => Some(TimeZone::Dublin),
            "helsinki" => Some(TimeZone::Helsinki),
            "lisbon" => Some(TimeZone::Lisbon),
            "london" => Some(TimeZone::London),
            "madrid" => Some(TimeZone::Madrid),
            "munich" => Some(TimeZone::Munich),
            "oslo" => Some(TimeZone::Oslo),
            "paris" => Some(TimeZone::Paris),
            "prague" => Some(TimeZone::Prague),
            "reykjavik" => Some(TimeZone::Reykjavik),
            "rome" => Some(TimeZone::Rome),
            "stockholm" => Some(TimeZone::Stockholm),
            "vienna" => Some(TimeZone::Vienna),
            "warsaw" => Some(TimeZone::Warsaw),
            "zurich" => Some(TimeZone::Zurich),
            "quebec" => Some(TimeZone::Quebec),
            "ontario" => Some(TimeZone::Ontario),
            "manitoba" => Some(TimeZone::Manitoba),
            "saskatchewan" => Some(TimeZone::Saskatchewan),
            "alberta" => Some(TimeZone::Alberta),
            "british_columbia" => Some(TimeZone::BritishColumbia),
            "boise" => Some(TimeZone::Boise),
            "boston" => Some(TimeZone::Boston),
            "chicago" => Some(TimeZone::Chicago),
            "dallas" => Some(TimeZone::Dallas),
            "denver" => Some(TimeZone::Denver),
            "kansas_city" => Some(TimeZone::KansasCity),
            "las_vegas" => Some(TimeZone::LasVegas),
            "los_angeles" => Some(TimeZone::LosAngeles),
            "miami" => Some(TimeZone::Miami),
            "minneapolis" => Some(TimeZone::Minneapolis),
            "new_york" => Some(TimeZone::NewYork),
            "new_orleans" => Some(TimeZone::NewOrleans),
            "phoenix" => Some(TimeZone::Phoenix),
            "santa_fe" => Some(TimeZone::SantaFe),
            "seattle" => Some(TimeZone::Seattle),
            "washington_dc" => Some(TimeZone::WashingtonDc),
            "us_arizona" => Some(TimeZone::UsArizona),
            "chita" => Some(TimeZone::Chita),
            "ekaterinburg" => Some(TimeZone::Ekaterinburg),
            "irkutsk" => Some(TimeZone::Irkutsk),
            "kaliningrad" => Some(TimeZone::Kaliningrad),
            "krasnoyarsk" => Some(TimeZone::Krasnoyarsk),
            "novosibirsk" => Some(TimeZone::Novosibirsk),
            "petropavlovsk_kamchatskiy" => Some(TimeZone::PetropavlovskKamchatskiy),
            "samara" => Some(TimeZone::Samara),
            "vladivostok" => Some(TimeZone::Vladivostok),
            "mexico_central" => Some(TimeZone::MexicoCentral),
            "mexico_mountain" => Some(TimeZone::MexicoMountain),
            "mexico_pacific" => Some(TimeZone::MexicoPacific),
            "cape_town" => Some(TimeZone::CapeTown),
            "winkhoek" => Some(TimeZone::Winkhoek),
            "lagos" => Some(TimeZone::Lagos),
            "riyahd" => Some(TimeZone::Riyahd),
            "venezuela" => Some(TimeZone::Venezuela),
            "australia_lh" => Some(TimeZone::AustraliaLh),
            "santiago" => Some(TimeZone::Santiago),
            "manual" => Some(TimeZone::Manual),
            "automatic" => Some(TimeZone::Automatic),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum DisplayMeasure {
    Metric = 0,
    Statute = 1,
    Nautical = 2,
}

impl DisplayMeasure {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            DisplayMeasure::Metric => "metric",
            DisplayMeasure::Statute => "statute",
            DisplayMeasure::Nautical => "nautical",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(DisplayMeasure::Metric),
            1 => Some(DisplayMeasure::Statute),
            2 => Some(DisplayMeasure::Nautical),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "metric" => Some(DisplayMeasure::Metric),
            "statute" => Some(DisplayMeasure::Statute),
            "nautical" => Some(DisplayMeasure::Nautical),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum DisplayHeart {
    Bpm = 0,
    Max = 1,
    Reserve = 2,
}

impl DisplayHeart {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            DisplayHeart::Bpm => "bpm",
            DisplayHeart::Max => "max",
            DisplayHeart::Reserve => "reserve",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(DisplayHeart::Bpm),
            1 => Some(DisplayHeart::Max),
            2 => Some(DisplayHeart::Reserve),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "bpm" => Some(DisplayHeart::Bpm),
            "max" => Some(DisplayHeart::Max),
            "reserve" => Some(DisplayHeart::Reserve),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum DisplayPower {
    Watts = 0,
    PercentFtp = 1,
}

impl DisplayPower {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            DisplayPower::Watts => "watts",
            DisplayPower::PercentFtp => "percent_ftp",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(DisplayPower::Watts),
            1 => Some(DisplayPower::PercentFtp),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "watts" => Some(DisplayPower::Watts),
            "percent_ftp" => Some(DisplayPower::PercentFtp),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum DisplayPosition {
    Degree = 0,
    DegreeMinute = 1,
    DegreeMinuteSecond = 2,
    AustrianGrid = 3,
    BritishGrid = 4,
    DutchGrid = 5,
    HungarianGrid = 6,
    FinnishGrid = 7,
    GermanGrid = 8,
    IcelandicGrid = 9,
    IndonesianEquatorial = 10,
    IndonesianIrian = 11,
    IndonesianSouthern = 12,
    IndiaZone0 = 13,
    IndiaZoneIA = 14,
    IndiaZoneIB = 15,
    IndiaZoneIIA = 16,
    IndiaZoneIIB = 17,
    IndiaZoneIIIA = 18,
    IndiaZoneIIIB = 19,
    IndiaZoneIVA = 20,
    IndiaZoneIVB = 21,
    IrishTransverse = 22,
    IrishGrid = 23,
    Loran = 24,
    MaidenheadGrid = 25,
    MgrsGrid = 26,
    NewZealandGrid = 27,
    NewZealandTransverse = 28,
    QatarGrid = 29,
    ModifiedSwedishGrid = 30,
    SwedishGrid = 31,
    SouthAfricanGrid = 32,
    SwissGrid = 33,
    TaiwanGrid = 34,
    UnitedStatesGrid = 35,
    UtmUpsGrid = 36,
    WestMalayan = 37,
    BorneoRso = 38,
    EstonianGrid = 39,
    LatvianGrid = 40,
    SwedishRef99Grid = 41,
}

impl DisplayPosition {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            DisplayPosition::Degree => "degree",
            DisplayPosition::DegreeMinute => "degree_minute",
            DisplayPosition::DegreeMinuteSecond => "degree_minute_second",
            DisplayPosition::AustrianGrid => "austrian_grid",
            DisplayPosition::BritishGrid => "british_grid",
            DisplayPosition::DutchGrid => "dutch_grid",
            DisplayPosition::HungarianGrid => "hungarian_grid",
            DisplayPosition::FinnishGrid => "finnish_grid",
            DisplayPosition::GermanGrid => "german_grid",
            DisplayPosition::IcelandicGrid => "icelandic_grid",
            DisplayPosition::IndonesianEquatorial => "indonesian_equatorial",
            DisplayPosition::IndonesianIrian => "indonesian_irian",
            DisplayPosition::IndonesianSouthern => "indonesian_southern",
            DisplayPosition::IndiaZone0 => "india_zone_0",
            DisplayPosition::IndiaZoneIA => "india_zone_IA",
            DisplayPosition::IndiaZoneIB => "india_zone_IB",
            DisplayPosition::IndiaZoneIIA => "india_zone_IIA",
            DisplayPosition::IndiaZoneIIB => "india_zone_IIB",
            DisplayPosition::IndiaZoneIIIA => "india_zone_IIIA",
            DisplayPosition::IndiaZoneIIIB => "india_zone_IIIB",
            DisplayPosition::IndiaZoneIVA => "india_zone_IVA",
            DisplayPosition::IndiaZoneIVB => "india_zone_IVB",
            DisplayPosition::IrishTransverse => "irish_transverse",
            DisplayPosition::IrishGrid => "irish_grid",
            DisplayPosition::Loran => "loran",
            DisplayPosition::MaidenheadGrid => "maidenhead_grid",
            DisplayPosition::MgrsGrid => "mgrs_grid",
            DisplayPosition::NewZealandGrid => "new_zealand_grid",
            DisplayPosition::NewZealandTransverse => "new_zealand_transverse",
            DisplayPosition::QatarGrid => "qatar_grid",
            DisplayPosition::ModifiedSwedishGrid => "modified_swedish_grid",
            DisplayPosition::SwedishGrid => "swedish_grid",
            DisplayPosition::SouthAfricanGrid => "south_african_grid",
            DisplayPosition::SwissGrid => "swiss_grid",
            DisplayPosition::TaiwanGrid => "taiwan_grid",
            DisplayPosition::UnitedStatesGrid => "united_states_grid",
            DisplayPosition::UtmUpsGrid => "utm_ups_grid",
            DisplayPosition::WestMalayan => "west_malayan",
            DisplayPosition::BorneoRso => "borneo_rso",
            DisplayPosition::EstonianGrid => "estonian_grid",
            DisplayPosition::LatvianGrid => "latvian_grid",
            DisplayPosition::SwedishRef99Grid => "swedish_ref_99_grid",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(DisplayPosition::Degree),
            1 => Some(DisplayPosition::DegreeMinute),
            2 => Some(DisplayPosition::DegreeMinuteSecond),
            3 => Some(DisplayPosition::AustrianGrid),
            4 => Some(DisplayPosition::BritishGrid),
            5 => Some(DisplayPosition::DutchGrid),
            6 => Some(DisplayPosition::HungarianGrid),
            7 => Some(DisplayPosition::FinnishGrid),
            8 => Some(DisplayPosition::GermanGrid),
            9 => Some(DisplayPosition::IcelandicGrid),
            10 => Some(DisplayPosition::IndonesianEquatorial),
            11 => Some(DisplayPosition::IndonesianIrian),
            12 => Some(DisplayPosition::IndonesianSouthern),
            13 => Some(DisplayPosition::IndiaZone0),
            14 => Some(DisplayPosition::IndiaZoneIA),
            15 => Some(DisplayPosition::IndiaZoneIB),
            16 => Some(DisplayPosition::IndiaZoneIIA),
            17 => Some(DisplayPosition::IndiaZoneIIB),
            18 => Some(DisplayPosition::IndiaZoneIIIA),
            19 => Some(DisplayPosition::IndiaZoneIIIB),
            20 => Some(DisplayPosition::IndiaZoneIVA),
            21 => Some(DisplayPosition::IndiaZoneIVB),
            22 => Some(DisplayPosition::IrishTransverse),
            23 => Some(DisplayPosition::IrishGrid),
            24 => Some(DisplayPosition::Loran),
            25 => Some(DisplayPosition::MaidenheadGrid),
            26 => Some(DisplayPosition::MgrsGrid),
            27 => Some(DisplayPosition::NewZealandGrid),
            28 => Some(DisplayPosition::NewZealandTransverse),
            29 => Some(DisplayPosition::QatarGrid),
            30 => Some(DisplayPosition::ModifiedSwedishGrid),
            31 => Some(DisplayPosition::SwedishGrid),
            32 => Some(DisplayPosition::SouthAfricanGrid),
            33 => Some(DisplayPosition::SwissGrid),
            34 => Some(DisplayPosition::TaiwanGrid),
            35 => Some(DisplayPosition::UnitedStatesGrid),
            36 => Some(DisplayPosition::UtmUpsGrid),
            37 => Some(DisplayPosition::WestMalayan),
            38 => Some(DisplayPosition::BorneoRso),
            39 => Some(DisplayPosition::EstonianGrid),
            40 => Some(DisplayPosition::LatvianGrid),
            41 => Some(DisplayPosition::SwedishRef99Grid),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "degree" => Some(DisplayPosition::Degree),
            "degree_minute" => Some(DisplayPosition::DegreeMinute),
            "degree_minute_second" => Some(DisplayPosition::DegreeMinuteSecond),
            "austrian_grid" => Some(DisplayPosition::AustrianGrid),
            "british_grid" => Some(DisplayPosition::BritishGrid),
            "dutch_grid" => Some(DisplayPosition::DutchGrid),
            "hungarian_grid" => Some(DisplayPosition::HungarianGrid),
            "finnish_grid" => Some(DisplayPosition::FinnishGrid),
            "german_grid" => Some(DisplayPosition::GermanGrid),
            "icelandic_grid" => Some(DisplayPosition::IcelandicGrid),
            "indonesian_equatorial" => Some(DisplayPosition::IndonesianEquatorial),
            "indonesian_irian" => Some(DisplayPosition::IndonesianIrian),
            "indonesian_southern" => Some(DisplayPosition::IndonesianSouthern),
            "india_zone_0" => Some(DisplayPosition::IndiaZone0),
            "india_zone_IA" => Some(DisplayPosition::IndiaZoneIA),
            "india_zone_IB" => Some(DisplayPosition::IndiaZoneIB),
            "india_zone_IIA" => Some(DisplayPosition::IndiaZoneIIA),
            "india_zone_IIB" => Some(DisplayPosition::IndiaZoneIIB),
            "india_zone_IIIA" => Some(DisplayPosition::IndiaZoneIIIA),
            "india_zone_IIIB" => Some(DisplayPosition::IndiaZoneIIIB),
            "india_zone_IVA" => Some(DisplayPosition::IndiaZoneIVA),
            "india_zone_IVB" => Some(DisplayPosition::IndiaZoneIVB),
            "irish_transverse" => Some(DisplayPosition::IrishTransverse),
            "irish_grid" => Some(DisplayPosition::IrishGrid),
            "loran" => Some(DisplayPosition::Loran),
            "maidenhead_grid" => Some(DisplayPosition::MaidenheadGrid),
            "mgrs_grid" => Some(DisplayPosition::MgrsGrid),
            "new_zealand_grid" => Some(DisplayPosition::NewZealandGrid),
            "new_zealand_transverse" => Some(DisplayPosition::NewZealandTransverse),
            "qatar_grid" => Some(DisplayPosition::QatarGrid),
            "modified_swedish_grid" => Some(DisplayPosition::ModifiedSwedishGrid),
            "swedish_grid" => Some(DisplayPosition::SwedishGrid),
            "south_african_grid" => Some(DisplayPosition::SouthAfricanGrid),
            "swiss_grid" => Some(DisplayPosition::SwissGrid),
            "taiwan_grid" => Some(DisplayPosition::TaiwanGrid),
            "united_states_grid" => Some(DisplayPosition::UnitedStatesGrid),
            "utm_ups_grid" => Some(DisplayPosition::UtmUpsGrid),
            "west_malayan" => Some(DisplayPosition::WestMalayan),
            "borneo_rso" => Some(DisplayPosition::BorneoRso),
            "estonian_grid" => Some(DisplayPosition::EstonianGrid),
            "latvian_grid" => Some(DisplayPosition::LatvianGrid),
            "swedish_ref_99_grid" => Some(DisplayPosition::SwedishRef99Grid),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum Switch {
    Off = 0,
    On = 1,
    Auto = 2,
}

impl Switch {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            Switch::Off => "off",
            Switch::On => "on",
            Switch::Auto => "auto",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(Switch::Off),
            1 => Some(Switch::On),
            2 => Some(Switch::Auto),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "off" => Some(Switch::Off),
            "on" => Some(Switch::On),
            "auto" => Some(Switch::Auto),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum Sport {
    Generic = 0,
    Running = 1,
    Cycling = 2,
    Transition = 3,
    FitnessEquipment = 4,
    Swimming = 5,
    Basketball = 6,
    Soccer = 7,
    Tennis = 8,
    AmericanFootball = 9,
    Training = 10,
    Walking = 11,
    CrossCountrySkiing = 12,
    AlpineSkiing = 13,
    Snowboarding = 14,
    Rowing = 15,
    Mountaineering = 16,
    Hiking = 17,
    Multisport = 18,
    Paddling = 19,
    Flying = 20,
    EBiking = 21,
    Motorcycling = 22,
    Boating = 23,
    Driving = 24,
    Golf = 25,
    HangGliding = 26,
    HorsebackRiding = 27,
    Hunting = 28,
    Fishing = 29,
    InlineSkating = 30,
    RockClimbing = 31,
    Sailing = 32,
    IceSkating = 33,
    SkyDiving = 34,
    Snowshoeing = 35,
    Snowmobiling = 36,
    StandUpPaddleboarding = 37,
    Surfing = 38,
    Wakeboarding = 39,
    WaterSkiing = 40,
    Kayaking = 41,
    Rafting = 42,
    Windsurfing = 43,
    Kitesurfing = 44,
    Tactical = 45,
    Jumpmaster = 46,
    Boxing = 47,
    FloorClimbing = 48,
    Baseball = 49,
    Diving = 53,
    Shooting = 56,
    WinterSport = 58,
    Grinding = 59,
    Hiit = 62,
    VideoGaming = 63,
    Racket = 64,
    WheelchairPushWalk = 65,
    WheelchairPushRun = 66,
    Meditation = 67,
    ParaSport = 68,
    DiscGolf = 69,
    TeamSport = 70,
    Cricket = 71,
    Rugby = 72,
    Hockey = 73,
    Lacrosse = 74,
    Volleyball = 75,
    WaterTubing = 76,
    Wakesurfing = 77,
    WaterSport = 78,
    Archery = 79,
    MixedMartialArts = 80,
    MotorSports = 81,
    Snorkeling = 82,
    Dance = 83,
    JumpRope = 84,
    PoolApnea = 85,
    Mobility = 86,
    Geocaching = 87,
    Canoeing = 88,
    All = 254,
}

impl Sport {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            Sport::Generic => "generic",
            Sport::Running => "running",
            Sport::Cycling => "cycling",
            Sport::Transition => "transition",
            Sport::FitnessEquipment => "fitness_equipment",
            Sport::Swimming => "swimming",
            Sport::Basketball => "basketball",
            Sport::Soccer => "soccer",
            Sport::Tennis => "tennis",
            Sport::AmericanFootball => "american_football",
            Sport::Training => "training",
            Sport::Walking => "walking",
            Sport::CrossCountrySkiing => "cross_country_skiing",
            Sport::AlpineSkiing => "alpine_skiing",
            Sport::Snowboarding => "snowboarding",
            Sport::Rowing => "rowing",
            Sport::Mountaineering => "mountaineering",
            Sport::Hiking => "hiking",
            Sport::Multisport => "multisport",
            Sport::Paddling => "paddling",
            Sport::Flying => "flying",
            Sport::EBiking => "e_biking",
            Sport::Motorcycling => "motorcycling",
            Sport::Boating => "boating",
            Sport::Driving => "driving",
            Sport::Golf => "golf",
            Sport::HangGliding => "hang_gliding",
            Sport::HorsebackRiding => "horseback_riding",
            Sport::Hunting => "hunting",
            Sport::Fishing => "fishing",
            Sport::InlineSkating => "inline_skating",
            Sport::RockClimbing => "rock_climbing",
            Sport::Sailing => "sailing",
            Sport::IceSkating => "ice_skating",
            Sport::SkyDiving => "sky_diving",
            Sport::Snowshoeing => "snowshoeing",
            Sport::Snowmobiling => "snowmobiling",
            Sport::StandUpPaddleboarding => "stand_up_paddleboarding",
            Sport::Surfing => "surfing",
            Sport::Wakeboarding => "wakeboarding",
            Sport::WaterSkiing => "water_skiing",
            Sport::Kayaking => "kayaking",
            Sport::Rafting => "rafting",
            Sport::Windsurfing => "windsurfing",
            Sport::Kitesurfing => "kitesurfing",
            Sport::Tactical => "tactical",
            Sport::Jumpmaster => "jumpmaster",
            Sport::Boxing => "boxing",
            Sport::FloorClimbing => "floor_climbing",
            Sport::Baseball => "baseball",
            Sport::Diving => "diving",
            Sport::Shooting => "shooting",
            Sport::WinterSport => "winter_sport",
            Sport::Grinding => "grinding",
            Sport::Hiit => "hiit",
            Sport::VideoGaming => "video_gaming",
            Sport::Racket => "racket",
            Sport::WheelchairPushWalk => "wheelchair_push_walk",
            Sport::WheelchairPushRun => "wheelchair_push_run",
            Sport::Meditation => "meditation",
            Sport::ParaSport => "para_sport",
            Sport::DiscGolf => "disc_golf",
            Sport::TeamSport => "team_sport",
            Sport::Cricket => "cricket",
            Sport::Rugby => "rugby",
            Sport::Hockey => "hockey",
            Sport::Lacrosse => "lacrosse",
            Sport::Volleyball => "volleyball",
            Sport::WaterTubing => "water_tubing",
            Sport::Wakesurfing => "wakesurfing",
            Sport::WaterSport => "water_sport",
            Sport::Archery => "archery",
            Sport::MixedMartialArts => "mixed_martial_arts",
            Sport::MotorSports => "motor_sports",
            Sport::Snorkeling => "snorkeling",
            Sport::Dance => "dance",
            Sport::JumpRope => "jump_rope",
            Sport::PoolApnea => "pool_apnea",
            Sport::Mobility => "mobility",
            Sport::Geocaching => "geocaching",
            Sport::Canoeing => "canoeing",
            Sport::All => "all",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(Sport::Generic),
            1 => Some(Sport::Running),
            2 => Some(Sport::Cycling),
            3 => Some(Sport::Transition),
            4 => Some(Sport::FitnessEquipment),
            5 => Some(Sport::Swimming),
            6 => Some(Sport::Basketball),
            7 => Some(Sport::Soccer),
            8 => Some(Sport::Tennis),
            9 => Some(Sport::AmericanFootball),
            10 => Some(Sport::Training),
            11 => Some(Sport::Walking),
            12 => Some(Sport::CrossCountrySkiing),
            13 => Some(Sport::AlpineSkiing),
            14 => Some(Sport::Snowboarding),
            15 => Some(Sport::Rowing),
            16 => Some(Sport::Mountaineering),
            17 => Some(Sport::Hiking),
            18 => Some(Sport::Multisport),
            19 => Some(Sport::Paddling),
            20 => Some(Sport::Flying),
            21 => Some(Sport::EBiking),
            22 => Some(Sport::Motorcycling),
            23 => Some(Sport::Boating),
            24 => Some(Sport::Driving),
            25 => Some(Sport::Golf),
            26 => Some(Sport::HangGliding),
            27 => Some(Sport::HorsebackRiding),
            28 => Some(Sport::Hunting),
            29 => Some(Sport::Fishing),
            30 => Some(Sport::InlineSkating),
            31 => Some(Sport::RockClimbing),
            32 => Some(Sport::Sailing),
            33 => Some(Sport::IceSkating),
            34 => Some(Sport::SkyDiving),
            35 => Some(Sport::Snowshoeing),
            36 => Some(Sport::Snowmobiling),
            37 => Some(Sport::StandUpPaddleboarding),
            38 => Some(Sport::Surfing),
            39 => Some(Sport::Wakeboarding),
            40 => Some(Sport::WaterSkiing),
            41 => Some(Sport::Kayaking),
            42 => Some(Sport::Rafting),
            43 => Some(Sport::Windsurfing),
            44 => Some(Sport::Kitesurfing),
            45 => Some(Sport::Tactical),
            46 => Some(Sport::Jumpmaster),
            47 => Some(Sport::Boxing),
            48 => Some(Sport::FloorClimbing),
            49 => Some(Sport::Baseball),
            53 => Some(Sport::Diving),
            56 => Some(Sport::Shooting),
            58 => Some(Sport::WinterSport),
            59 => Some(Sport::Grinding),
            62 => Some(Sport::Hiit),
            63 => Some(Sport::VideoGaming),
            64 => Some(Sport::Racket),
            65 => Some(Sport::WheelchairPushWalk),
            66 => Some(Sport::WheelchairPushRun),
            67 => Some(Sport::Meditation),
            68 => Some(Sport::ParaSport),
            69 => Some(Sport::DiscGolf),
            70 => Some(Sport::TeamSport),
            71 => Some(Sport::Cricket),
            72 => Some(Sport::Rugby),
            73 => Some(Sport::Hockey),
            74 => Some(Sport::Lacrosse),
            75 => Some(Sport::Volleyball),
            76 => Some(Sport::WaterTubing),
            77 => Some(Sport::Wakesurfing),
            78 => Some(Sport::WaterSport),
            79 => Some(Sport::Archery),
            80 => Some(Sport::MixedMartialArts),
            81 => Some(Sport::MotorSports),
            82 => Some(Sport::Snorkeling),
            83 => Some(Sport::Dance),
            84 => Some(Sport::JumpRope),
            85 => Some(Sport::PoolApnea),
            86 => Some(Sport::Mobility),
            87 => Some(Sport::Geocaching),
            88 => Some(Sport::Canoeing),
            254 => Some(Sport::All),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "generic" => Some(Sport::Generic),
            "running" => Some(Sport::Running),
            "cycling" => Some(Sport::Cycling),
            "transition" => Some(Sport::Transition),
            "fitness_equipment" => Some(Sport::FitnessEquipment),
            "swimming" => Some(Sport::Swimming),
            "basketball" => Some(Sport::Basketball),
            "soccer" => Some(Sport::Soccer),
            "tennis" => Some(Sport::Tennis),
            "american_football" => Some(Sport::AmericanFootball),
            "training" => Some(Sport::Training),
            "walking" => Some(Sport::Walking),
            "cross_country_skiing" => Some(Sport::CrossCountrySkiing),
            "alpine_skiing" => Some(Sport::AlpineSkiing),
            "snowboarding" => Some(Sport::Snowboarding),
            "rowing" => Some(Sport::Rowing),
            "mountaineering" => Some(Sport::Mountaineering),
            "hiking" => Some(Sport::Hiking),
            "multisport" => Some(Sport::Multisport),
            "paddling" => Some(Sport::Paddling),
            "flying" => Some(Sport::Flying),
            "e_biking" => Some(Sport::EBiking),
            "motorcycling" => Some(Sport::Motorcycling),
            "boating" => Some(Sport::Boating),
            "driving" => Some(Sport::Driving),
            "golf" => Some(Sport::Golf),
            "hang_gliding" => Some(Sport::HangGliding),
            "horseback_riding" => Some(Sport::HorsebackRiding),
            "hunting" => Some(Sport::Hunting),
            "fishing" => Some(Sport::Fishing),
            "inline_skating" => Some(Sport::InlineSkating),
            "rock_climbing" => Some(Sport::RockClimbing),
            "sailing" => Some(Sport::Sailing),
            "ice_skating" => Some(Sport::IceSkating),
            "sky_diving" => Some(Sport::SkyDiving),
            "snowshoeing" => Some(Sport::Snowshoeing),
            "snowmobiling" => Some(Sport::Snowmobiling),
            "stand_up_paddleboarding" => Some(Sport::StandUpPaddleboarding),
            "surfing" => Some(Sport::Surfing),
            "wakeboarding" => Some(Sport::Wakeboarding),
            "water_skiing" => Some(Sport::WaterSkiing),
            "kayaking" => Some(Sport::Kayaking),
            "rafting" => Some(Sport::Rafting),
            "windsurfing" => Some(Sport::Windsurfing),
            "kitesurfing" => Some(Sport::Kitesurfing),
            "tactical" => Some(Sport::Tactical),
            "jumpmaster" => Some(Sport::Jumpmaster),
            "boxing" => Some(Sport::Boxing),
            "floor_climbing" => Some(Sport::FloorClimbing),
            "baseball" => Some(Sport::Baseball),
            "diving" => Some(Sport::Diving),
            "shooting" => Some(Sport::Shooting),
            "winter_sport" => Some(Sport::WinterSport),
            "grinding" => Some(Sport::Grinding),
            "hiit" => Some(Sport::Hiit),
            "video_gaming" => Some(Sport::VideoGaming),
            "racket" => Some(Sport::Racket),
            "wheelchair_push_walk" => Some(Sport::WheelchairPushWalk),
            "wheelchair_push_run" => Some(Sport::WheelchairPushRun),
            "meditation" => Some(Sport::Meditation),
            "para_sport" => Some(Sport::ParaSport),
            "disc_golf" => Some(Sport::DiscGolf),
            "team_sport" => Some(Sport::TeamSport),
            "cricket" => Some(Sport::Cricket),
            "rugby" => Some(Sport::Rugby),
            "hockey" => Some(Sport::Hockey),
            "lacrosse" => Some(Sport::Lacrosse),
            "volleyball" => Some(Sport::Volleyball),
            "water_tubing" => Some(Sport::WaterTubing),
            "wakesurfing" => Some(Sport::Wakesurfing),
            "water_sport" => Some(Sport::WaterSport),
            "archery" => Some(Sport::Archery),
            "mixed_martial_arts" => Some(Sport::MixedMartialArts),
            "motor_sports" => Some(Sport::MotorSports),
            "snorkeling" => Some(Sport::Snorkeling),
            "dance" => Some(Sport::Dance),
            "jump_rope" => Some(Sport::JumpRope),
            "pool_apnea" => Some(Sport::PoolApnea),
            "mobility" => Some(Sport::Mobility),
            "geocaching" => Some(Sport::Geocaching),
            "canoeing" => Some(Sport::Canoeing),
            "all" => Some(Sport::All),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum SportBits0 {
    Generic = 1,
    Running = 2,
    Cycling = 4,
    Transition = 8,
    FitnessEquipment = 16,
    Swimming = 32,
    Basketball = 64,
    Soccer = 128,
}

impl SportBits0 {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            SportBits0::Generic => "generic",
            SportBits0::Running => "running",
            SportBits0::Cycling => "cycling",
            SportBits0::Transition => "transition",
            SportBits0::FitnessEquipment => "fitness_equipment",
            SportBits0::Swimming => "swimming",
            SportBits0::Basketball => "basketball",
            SportBits0::Soccer => "soccer",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            1 => Some(SportBits0::Generic),
            2 => Some(SportBits0::Running),
            4 => Some(SportBits0::Cycling),
            8 => Some(SportBits0::Transition),
            16 => Some(SportBits0::FitnessEquipment),
            32 => Some(SportBits0::Swimming),
            64 => Some(SportBits0::Basketball),
            128 => Some(SportBits0::Soccer),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "generic" => Some(SportBits0::Generic),
            "running" => Some(SportBits0::Running),
            "cycling" => Some(SportBits0::Cycling),
            "transition" => Some(SportBits0::Transition),
            "fitness_equipment" => Some(SportBits0::FitnessEquipment),
            "swimming" => Some(SportBits0::Swimming),
            "basketball" => Some(SportBits0::Basketball),
            "soccer" => Some(SportBits0::Soccer),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum SportBits1 {
    Tennis = 1,
    AmericanFootball = 2,
    Training = 4,
    Walking = 8,
    CrossCountrySkiing = 16,
    AlpineSkiing = 32,
    Snowboarding = 64,
    Rowing = 128,
}

impl SportBits1 {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            SportBits1::Tennis => "tennis",
            SportBits1::AmericanFootball => "american_football",
            SportBits1::Training => "training",
            SportBits1::Walking => "walking",
            SportBits1::CrossCountrySkiing => "cross_country_skiing",
            SportBits1::AlpineSkiing => "alpine_skiing",
            SportBits1::Snowboarding => "snowboarding",
            SportBits1::Rowing => "rowing",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            1 => Some(SportBits1::Tennis),
            2 => Some(SportBits1::AmericanFootball),
            4 => Some(SportBits1::Training),
            8 => Some(SportBits1::Walking),
            16 => Some(SportBits1::CrossCountrySkiing),
            32 => Some(SportBits1::AlpineSkiing),
            64 => Some(SportBits1::Snowboarding),
            128 => Some(SportBits1::Rowing),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "tennis" => Some(SportBits1::Tennis),
            "american_football" => Some(SportBits1::AmericanFootball),
            "training" => Some(SportBits1::Training),
            "walking" => Some(SportBits1::Walking),
            "cross_country_skiing" => Some(SportBits1::CrossCountrySkiing),
            "alpine_skiing" => Some(SportBits1::AlpineSkiing),
            "snowboarding" => Some(SportBits1::Snowboarding),
            "rowing" => Some(SportBits1::Rowing),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum SportBits2 {
    Mountaineering = 1,
    Hiking = 2,
    Multisport = 4,
    Paddling = 8,
    Flying = 16,
    EBiking = 32,
    Motorcycling = 64,
    Boating = 128,
}

impl SportBits2 {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            SportBits2::Mountaineering => "mountaineering",
            SportBits2::Hiking => "hiking",
            SportBits2::Multisport => "multisport",
            SportBits2::Paddling => "paddling",
            SportBits2::Flying => "flying",
            SportBits2::EBiking => "e_biking",
            SportBits2::Motorcycling => "motorcycling",
            SportBits2::Boating => "boating",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            1 => Some(SportBits2::Mountaineering),
            2 => Some(SportBits2::Hiking),
            4 => Some(SportBits2::Multisport),
            8 => Some(SportBits2::Paddling),
            16 => Some(SportBits2::Flying),
            32 => Some(SportBits2::EBiking),
            64 => Some(SportBits2::Motorcycling),
            128 => Some(SportBits2::Boating),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "mountaineering" => Some(SportBits2::Mountaineering),
            "hiking" => Some(SportBits2::Hiking),
            "multisport" => Some(SportBits2::Multisport),
            "paddling" => Some(SportBits2::Paddling),
            "flying" => Some(SportBits2::Flying),
            "e_biking" => Some(SportBits2::EBiking),
            "motorcycling" => Some(SportBits2::Motorcycling),
            "boating" => Some(SportBits2::Boating),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum SportBits3 {
    Driving = 1,
    Golf = 2,
    HangGliding = 4,
    HorsebackRiding = 8,
    Hunting = 16,
    Fishing = 32,
    InlineSkating = 64,
    RockClimbing = 128,
}

impl SportBits3 {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            SportBits3::Driving => "driving",
            SportBits3::Golf => "golf",
            SportBits3::HangGliding => "hang_gliding",
            SportBits3::HorsebackRiding => "horseback_riding",
            SportBits3::Hunting => "hunting",
            SportBits3::Fishing => "fishing",
            SportBits3::InlineSkating => "inline_skating",
            SportBits3::RockClimbing => "rock_climbing",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            1 => Some(SportBits3::Driving),
            2 => Some(SportBits3::Golf),
            4 => Some(SportBits3::HangGliding),
            8 => Some(SportBits3::HorsebackRiding),
            16 => Some(SportBits3::Hunting),
            32 => Some(SportBits3::Fishing),
            64 => Some(SportBits3::InlineSkating),
            128 => Some(SportBits3::RockClimbing),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "driving" => Some(SportBits3::Driving),
            "golf" => Some(SportBits3::Golf),
            "hang_gliding" => Some(SportBits3::HangGliding),
            "horseback_riding" => Some(SportBits3::HorsebackRiding),
            "hunting" => Some(SportBits3::Hunting),
            "fishing" => Some(SportBits3::Fishing),
            "inline_skating" => Some(SportBits3::InlineSkating),
            "rock_climbing" => Some(SportBits3::RockClimbing),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum SportBits4 {
    Sailing = 1,
    IceSkating = 2,
    SkyDiving = 4,
    Snowshoeing = 8,
    Snowmobiling = 16,
    StandUpPaddleboarding = 32,
    Surfing = 64,
    Wakeboarding = 128,
}

impl SportBits4 {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            SportBits4::Sailing => "sailing",
            SportBits4::IceSkating => "ice_skating",
            SportBits4::SkyDiving => "sky_diving",
            SportBits4::Snowshoeing => "snowshoeing",
            SportBits4::Snowmobiling => "snowmobiling",
            SportBits4::StandUpPaddleboarding => "stand_up_paddleboarding",
            SportBits4::Surfing => "surfing",
            SportBits4::Wakeboarding => "wakeboarding",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            1 => Some(SportBits4::Sailing),
            2 => Some(SportBits4::IceSkating),
            4 => Some(SportBits4::SkyDiving),
            8 => Some(SportBits4::Snowshoeing),
            16 => Some(SportBits4::Snowmobiling),
            32 => Some(SportBits4::StandUpPaddleboarding),
            64 => Some(SportBits4::Surfing),
            128 => Some(SportBits4::Wakeboarding),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "sailing" => Some(SportBits4::Sailing),
            "ice_skating" => Some(SportBits4::IceSkating),
            "sky_diving" => Some(SportBits4::SkyDiving),
            "snowshoeing" => Some(SportBits4::Snowshoeing),
            "snowmobiling" => Some(SportBits4::Snowmobiling),
            "stand_up_paddleboarding" => Some(SportBits4::StandUpPaddleboarding),
            "surfing" => Some(SportBits4::Surfing),
            "wakeboarding" => Some(SportBits4::Wakeboarding),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum SportBits5 {
    WaterSkiing = 1,
    Kayaking = 2,
    Rafting = 4,
    Windsurfing = 8,
    Kitesurfing = 16,
    Tactical = 32,
    Jumpmaster = 64,
    Boxing = 128,
}

impl SportBits5 {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            SportBits5::WaterSkiing => "water_skiing",
            SportBits5::Kayaking => "kayaking",
            SportBits5::Rafting => "rafting",
            SportBits5::Windsurfing => "windsurfing",
            SportBits5::Kitesurfing => "kitesurfing",
            SportBits5::Tactical => "tactical",
            SportBits5::Jumpmaster => "jumpmaster",
            SportBits5::Boxing => "boxing",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            1 => Some(SportBits5::WaterSkiing),
            2 => Some(SportBits5::Kayaking),
            4 => Some(SportBits5::Rafting),
            8 => Some(SportBits5::Windsurfing),
            16 => Some(SportBits5::Kitesurfing),
            32 => Some(SportBits5::Tactical),
            64 => Some(SportBits5::Jumpmaster),
            128 => Some(SportBits5::Boxing),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "water_skiing" => Some(SportBits5::WaterSkiing),
            "kayaking" => Some(SportBits5::Kayaking),
            "rafting" => Some(SportBits5::Rafting),
            "windsurfing" => Some(SportBits5::Windsurfing),
            "kitesurfing" => Some(SportBits5::Kitesurfing),
            "tactical" => Some(SportBits5::Tactical),
            "jumpmaster" => Some(SportBits5::Jumpmaster),
            "boxing" => Some(SportBits5::Boxing),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum SportBits6 {
    FloorClimbing = 1,
}

impl SportBits6 {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            SportBits6::FloorClimbing => "floor_climbing",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            1 => Some(SportBits6::FloorClimbing),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "floor_climbing" => Some(SportBits6::FloorClimbing),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum SubSport {
    Generic = 0,
    Treadmill = 1,
    Street = 2,
    Trail = 3,
    Track = 4,
    Spin = 5,
    IndoorCycling = 6,
    Road = 7,
    Mountain = 8,
    Downhill = 9,
    Recumbent = 10,
    Cyclocross = 11,
    HandCycling = 12,
    TrackCycling = 13,
    IndoorRowing = 14,
    Elliptical = 15,
    StairClimbing = 16,
    LapSwimming = 17,
    OpenWater = 18,
    FlexibilityTraining = 19,
    StrengthTraining = 20,
    WarmUp = 21,
    Match = 22,
    Exercise = 23,
    Challenge = 24,
    IndoorSkiing = 25,
    CardioTraining = 26,
    IndoorWalking = 27,
    EBikeFitness = 28,
    Bmx = 29,
    CasualWalking = 30,
    SpeedWalking = 31,
    BikeToRunTransition = 32,
    RunToBikeTransition = 33,
    SwimToBikeTransition = 34,
    Atv = 35,
    Motocross = 36,
    Backcountry = 37,
    Resort = 38,
    RcDrone = 39,
    Wingsuit = 40,
    Whitewater = 41,
    SkateSkiing = 42,
    Yoga = 43,
    Pilates = 44,
    IndoorRunning = 45,
    GravelCycling = 46,
    EBikeMountain = 47,
    Commuting = 48,
    MixedSurface = 49,
    Navigate = 50,
    TrackMe = 51,
    Map = 52,
    SingleGasDiving = 53,
    MultiGasDiving = 54,
    GaugeDiving = 55,
    ApneaDiving = 56,
    ApneaHunting = 57,
    VirtualActivity = 58,
    Obstacle = 59,
    Breathing = 62,
    CcrDiving = 63,
    SailRace = 65,
    Expedition = 66,
    Ultra = 67,
    IndoorClimbing = 68,
    Bouldering = 69,
    Hiit = 70,
    IndoorGrinding = 71,
    HuntingWithDogs = 72,
    Amrap = 73,
    Emom = 74,
    Tabata = 75,
    Esport = 77,
    Triathlon = 78,
    Duathlon = 79,
    Brick = 80,
    SwimRun = 81,
    AdventureRace = 82,
    TruckerWorkout = 83,
    Pickleball = 84,
    Padel = 85,
    IndoorWheelchairWalk = 86,
    IndoorWheelchairRun = 87,
    IndoorHandCycling = 88,
    Field = 90,
    Ice = 91,
    Ultimate = 92,
    Platform = 93,
    Squash = 94,
    Badminton = 95,
    Racquetball = 96,
    TableTennis = 97,
    Overland = 98,
    TrollingMotor = 99,
    FlyCanopy = 110,
    FlyParaglide = 111,
    FlyParamotor = 112,
    FlyPressurized = 113,
    FlyNavigate = 114,
    FlyTimer = 115,
    FlyAltimeter = 116,
    FlyWx = 117,
    FlyVfr = 118,
    FlyIfr = 119,
    DynamicApnea = 121,
    Enduro = 123,
    Rucking = 124,
    Rally = 125,
    PoolTriathlon = 126,
    EBikeEnduro = 127,
    All = 254,
}

impl SubSport {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            SubSport::Generic => "generic",
            SubSport::Treadmill => "treadmill",
            SubSport::Street => "street",
            SubSport::Trail => "trail",
            SubSport::Track => "track",
            SubSport::Spin => "spin",
            SubSport::IndoorCycling => "indoor_cycling",
            SubSport::Road => "road",
            SubSport::Mountain => "mountain",
            SubSport::Downhill => "downhill",
            SubSport::Recumbent => "recumbent",
            SubSport::Cyclocross => "cyclocross",
            SubSport::HandCycling => "hand_cycling",
            SubSport::TrackCycling => "track_cycling",
            SubSport::IndoorRowing => "indoor_rowing",
            SubSport::Elliptical => "elliptical",
            SubSport::StairClimbing => "stair_climbing",
            SubSport::LapSwimming => "lap_swimming",
            SubSport::OpenWater => "open_water",
            SubSport::FlexibilityTraining => "flexibility_training",
            SubSport::StrengthTraining => "strength_training",
            SubSport::WarmUp => "warm_up",
            SubSport::Match => "match",
            SubSport::Exercise => "exercise",
            SubSport::Challenge => "challenge",
            SubSport::IndoorSkiing => "indoor_skiing",
            SubSport::CardioTraining => "cardio_training",
            SubSport::IndoorWalking => "indoor_walking",
            SubSport::EBikeFitness => "e_bike_fitness",
            SubSport::Bmx => "bmx",
            SubSport::CasualWalking => "casual_walking",
            SubSport::SpeedWalking => "speed_walking",
            SubSport::BikeToRunTransition => "bike_to_run_transition",
            SubSport::RunToBikeTransition => "run_to_bike_transition",
            SubSport::SwimToBikeTransition => "swim_to_bike_transition",
            SubSport::Atv => "atv",
            SubSport::Motocross => "motocross",
            SubSport::Backcountry => "backcountry",
            SubSport::Resort => "resort",
            SubSport::RcDrone => "rc_drone",
            SubSport::Wingsuit => "wingsuit",
            SubSport::Whitewater => "whitewater",
            SubSport::SkateSkiing => "skate_skiing",
            SubSport::Yoga => "yoga",
            SubSport::Pilates => "pilates",
            SubSport::IndoorRunning => "indoor_running",
            SubSport::GravelCycling => "gravel_cycling",
            SubSport::EBikeMountain => "e_bike_mountain",
            SubSport::Commuting => "commuting",
            SubSport::MixedSurface => "mixed_surface",
            SubSport::Navigate => "navigate",
            SubSport::TrackMe => "track_me",
            SubSport::Map => "map",
            SubSport::SingleGasDiving => "single_gas_diving",
            SubSport::MultiGasDiving => "multi_gas_diving",
            SubSport::GaugeDiving => "gauge_diving",
            SubSport::ApneaDiving => "apnea_diving",
            SubSport::ApneaHunting => "apnea_hunting",
            SubSport::VirtualActivity => "virtual_activity",
            SubSport::Obstacle => "obstacle",
            SubSport::Breathing => "breathing",
            SubSport::CcrDiving => "ccr_diving",
            SubSport::SailRace => "sail_race",
            SubSport::Expedition => "expedition",
            SubSport::Ultra => "ultra",
            SubSport::IndoorClimbing => "indoor_climbing",
            SubSport::Bouldering => "bouldering",
            SubSport::Hiit => "hiit",
            SubSport::IndoorGrinding => "indoor_grinding",
            SubSport::HuntingWithDogs => "hunting_with_dogs",
            SubSport::Amrap => "amrap",
            SubSport::Emom => "emom",
            SubSport::Tabata => "tabata",
            SubSport::Esport => "esport",
            SubSport::Triathlon => "triathlon",
            SubSport::Duathlon => "duathlon",
            SubSport::Brick => "brick",
            SubSport::SwimRun => "swim_run",
            SubSport::AdventureRace => "adventure_race",
            SubSport::TruckerWorkout => "trucker_workout",
            SubSport::Pickleball => "pickleball",
            SubSport::Padel => "padel",
            SubSport::IndoorWheelchairWalk => "indoor_wheelchair_walk",
            SubSport::IndoorWheelchairRun => "indoor_wheelchair_run",
            SubSport::IndoorHandCycling => "indoor_hand_cycling",
            SubSport::Field => "field",
            SubSport::Ice => "ice",
            SubSport::Ultimate => "ultimate",
            SubSport::Platform => "platform",
            SubSport::Squash => "squash",
            SubSport::Badminton => "badminton",
            SubSport::Racquetball => "racquetball",
            SubSport::TableTennis => "table_tennis",
            SubSport::Overland => "overland",
            SubSport::TrollingMotor => "trolling_motor",
            SubSport::FlyCanopy => "fly_canopy",
            SubSport::FlyParaglide => "fly_paraglide",
            SubSport::FlyParamotor => "fly_paramotor",
            SubSport::FlyPressurized => "fly_pressurized",
            SubSport::FlyNavigate => "fly_navigate",
            SubSport::FlyTimer => "fly_timer",
            SubSport::FlyAltimeter => "fly_altimeter",
            SubSport::FlyWx => "fly_wx",
            SubSport::FlyVfr => "fly_vfr",
            SubSport::FlyIfr => "fly_ifr",
            SubSport::DynamicApnea => "dynamic_apnea",
            SubSport::Enduro => "enduro",
            SubSport::Rucking => "rucking",
            SubSport::Rally => "rally",
            SubSport::PoolTriathlon => "pool_triathlon",
            SubSport::EBikeEnduro => "e_bike_enduro",
            SubSport::All => "all",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(SubSport::Generic),
            1 => Some(SubSport::Treadmill),
            2 => Some(SubSport::Street),
            3 => Some(SubSport::Trail),
            4 => Some(SubSport::Track),
            5 => Some(SubSport::Spin),
            6 => Some(SubSport::IndoorCycling),
            7 => Some(SubSport::Road),
            8 => Some(SubSport::Mountain),
            9 => Some(SubSport::Downhill),
            10 => Some(SubSport::Recumbent),
            11 => Some(SubSport::Cyclocross),
            12 => Some(SubSport::HandCycling),
            13 => Some(SubSport::TrackCycling),
            14 => Some(SubSport::IndoorRowing),
            15 => Some(SubSport::Elliptical),
            16 => Some(SubSport::StairClimbing),
            17 => Some(SubSport::LapSwimming),
            18 => Some(SubSport::OpenWater),
            19 => Some(SubSport::FlexibilityTraining),
            20 => Some(SubSport::StrengthTraining),
            21 => Some(SubSport::WarmUp),
            22 => Some(SubSport::Match),
            23 => Some(SubSport::Exercise),
            24 => Some(SubSport::Challenge),
            25 => Some(SubSport::IndoorSkiing),
            26 => Some(SubSport::CardioTraining),
            27 => Some(SubSport::IndoorWalking),
            28 => Some(SubSport::EBikeFitness),
            29 => Some(SubSport::Bmx),
            30 => Some(SubSport::CasualWalking),
            31 => Some(SubSport::SpeedWalking),
            32 => Some(SubSport::BikeToRunTransition),
            33 => Some(SubSport::RunToBikeTransition),
            34 => Some(SubSport::SwimToBikeTransition),
            35 => Some(SubSport::Atv),
            36 => Some(SubSport::Motocross),
            37 => Some(SubSport::Backcountry),
            38 => Some(SubSport::Resort),
            39 => Some(SubSport::RcDrone),
            40 => Some(SubSport::Wingsuit),
            41 => Some(SubSport::Whitewater),
            42 => Some(SubSport::SkateSkiing),
            43 => Some(SubSport::Yoga),
            44 => Some(SubSport::Pilates),
            45 => Some(SubSport::IndoorRunning),
            46 => Some(SubSport::GravelCycling),
            47 => Some(SubSport::EBikeMountain),
            48 => Some(SubSport::Commuting),
            49 => Some(SubSport::MixedSurface),
            50 => Some(SubSport::Navigate),
            51 => Some(SubSport::TrackMe),
            52 => Some(SubSport::Map),
            53 => Some(SubSport::SingleGasDiving),
            54 => Some(SubSport::MultiGasDiving),
            55 => Some(SubSport::GaugeDiving),
            56 => Some(SubSport::ApneaDiving),
            57 => Some(SubSport::ApneaHunting),
            58 => Some(SubSport::VirtualActivity),
            59 => Some(SubSport::Obstacle),
            62 => Some(SubSport::Breathing),
            63 => Some(SubSport::CcrDiving),
            65 => Some(SubSport::SailRace),
            66 => Some(SubSport::Expedition),
            67 => Some(SubSport::Ultra),
            68 => Some(SubSport::IndoorClimbing),
            69 => Some(SubSport::Bouldering),
            70 => Some(SubSport::Hiit),
            71 => Some(SubSport::IndoorGrinding),
            72 => Some(SubSport::HuntingWithDogs),
            73 => Some(SubSport::Amrap),
            74 => Some(SubSport::Emom),
            75 => Some(SubSport::Tabata),
            77 => Some(SubSport::Esport),
            78 => Some(SubSport::Triathlon),
            79 => Some(SubSport::Duathlon),
            80 => Some(SubSport::Brick),
            81 => Some(SubSport::SwimRun),
            82 => Some(SubSport::AdventureRace),
            83 => Some(SubSport::TruckerWorkout),
            84 => Some(SubSport::Pickleball),
            85 => Some(SubSport::Padel),
            86 => Some(SubSport::IndoorWheelchairWalk),
            87 => Some(SubSport::IndoorWheelchairRun),
            88 => Some(SubSport::IndoorHandCycling),
            90 => Some(SubSport::Field),
            91 => Some(SubSport::Ice),
            92 => Some(SubSport::Ultimate),
            93 => Some(SubSport::Platform),
            94 => Some(SubSport::Squash),
            95 => Some(SubSport::Badminton),
            96 => Some(SubSport::Racquetball),
            97 => Some(SubSport::TableTennis),
            98 => Some(SubSport::Overland),
            99 => Some(SubSport::TrollingMotor),
            110 => Some(SubSport::FlyCanopy),
            111 => Some(SubSport::FlyParaglide),
            112 => Some(SubSport::FlyParamotor),
            113 => Some(SubSport::FlyPressurized),
            114 => Some(SubSport::FlyNavigate),
            115 => Some(SubSport::FlyTimer),
            116 => Some(SubSport::FlyAltimeter),
            117 => Some(SubSport::FlyWx),
            118 => Some(SubSport::FlyVfr),
            119 => Some(SubSport::FlyIfr),
            121 => Some(SubSport::DynamicApnea),
            123 => Some(SubSport::Enduro),
            124 => Some(SubSport::Rucking),
            125 => Some(SubSport::Rally),
            126 => Some(SubSport::PoolTriathlon),
            127 => Some(SubSport::EBikeEnduro),
            254 => Some(SubSport::All),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "generic" => Some(SubSport::Generic),
            "treadmill" => Some(SubSport::Treadmill),
            "street" => Some(SubSport::Street),
            "trail" => Some(SubSport::Trail),
            "track" => Some(SubSport::Track),
            "spin" => Some(SubSport::Spin),
            "indoor_cycling" => Some(SubSport::IndoorCycling),
            "road" => Some(SubSport::Road),
            "mountain" => Some(SubSport::Mountain),
            "downhill" => Some(SubSport::Downhill),
            "recumbent" => Some(SubSport::Recumbent),
            "cyclocross" => Some(SubSport::Cyclocross),
            "hand_cycling" => Some(SubSport::HandCycling),
            "track_cycling" => Some(SubSport::TrackCycling),
            "indoor_rowing" => Some(SubSport::IndoorRowing),
            "elliptical" => Some(SubSport::Elliptical),
            "stair_climbing" => Some(SubSport::StairClimbing),
            "lap_swimming" => Some(SubSport::LapSwimming),
            "open_water" => Some(SubSport::OpenWater),
            "flexibility_training" => Some(SubSport::FlexibilityTraining),
            "strength_training" => Some(SubSport::StrengthTraining),
            "warm_up" => Some(SubSport::WarmUp),
            "match" => Some(SubSport::Match),
            "exercise" => Some(SubSport::Exercise),
            "challenge" => Some(SubSport::Challenge),
            "indoor_skiing" => Some(SubSport::IndoorSkiing),
            "cardio_training" => Some(SubSport::CardioTraining),
            "indoor_walking" => Some(SubSport::IndoorWalking),
            "e_bike_fitness" => Some(SubSport::EBikeFitness),
            "bmx" => Some(SubSport::Bmx),
            "casual_walking" => Some(SubSport::CasualWalking),
            "speed_walking" => Some(SubSport::SpeedWalking),
            "bike_to_run_transition" => Some(SubSport::BikeToRunTransition),
            "run_to_bike_transition" => Some(SubSport::RunToBikeTransition),
            "swim_to_bike_transition" => Some(SubSport::SwimToBikeTransition),
            "atv" => Some(SubSport::Atv),
            "motocross" => Some(SubSport::Motocross),
            "backcountry" => Some(SubSport::Backcountry),
            "resort" => Some(SubSport::Resort),
            "rc_drone" => Some(SubSport::RcDrone),
            "wingsuit" => Some(SubSport::Wingsuit),
            "whitewater" => Some(SubSport::Whitewater),
            "skate_skiing" => Some(SubSport::SkateSkiing),
            "yoga" => Some(SubSport::Yoga),
            "pilates" => Some(SubSport::Pilates),
            "indoor_running" => Some(SubSport::IndoorRunning),
            "gravel_cycling" => Some(SubSport::GravelCycling),
            "e_bike_mountain" => Some(SubSport::EBikeMountain),
            "commuting" => Some(SubSport::Commuting),
            "mixed_surface" => Some(SubSport::MixedSurface),
            "navigate" => Some(SubSport::Navigate),
            "track_me" => Some(SubSport::TrackMe),
            "map" => Some(SubSport::Map),
            "single_gas_diving" => Some(SubSport::SingleGasDiving),
            "multi_gas_diving" => Some(SubSport::MultiGasDiving),
            "gauge_diving" => Some(SubSport::GaugeDiving),
            "apnea_diving" => Some(SubSport::ApneaDiving),
            "apnea_hunting" => Some(SubSport::ApneaHunting),
            "virtual_activity" => Some(SubSport::VirtualActivity),
            "obstacle" => Some(SubSport::Obstacle),
            "breathing" => Some(SubSport::Breathing),
            "ccr_diving" => Some(SubSport::CcrDiving),
            "sail_race" => Some(SubSport::SailRace),
            "expedition" => Some(SubSport::Expedition),
            "ultra" => Some(SubSport::Ultra),
            "indoor_climbing" => Some(SubSport::IndoorClimbing),
            "bouldering" => Some(SubSport::Bouldering),
            "hiit" => Some(SubSport::Hiit),
            "indoor_grinding" => Some(SubSport::IndoorGrinding),
            "hunting_with_dogs" => Some(SubSport::HuntingWithDogs),
            "amrap" => Some(SubSport::Amrap),
            "emom" => Some(SubSport::Emom),
            "tabata" => Some(SubSport::Tabata),
            "esport" => Some(SubSport::Esport),
            "triathlon" => Some(SubSport::Triathlon),
            "duathlon" => Some(SubSport::Duathlon),
            "brick" => Some(SubSport::Brick),
            "swim_run" => Some(SubSport::SwimRun),
            "adventure_race" => Some(SubSport::AdventureRace),
            "trucker_workout" => Some(SubSport::TruckerWorkout),
            "pickleball" => Some(SubSport::Pickleball),
            "padel" => Some(SubSport::Padel),
            "indoor_wheelchair_walk" => Some(SubSport::IndoorWheelchairWalk),
            "indoor_wheelchair_run" => Some(SubSport::IndoorWheelchairRun),
            "indoor_hand_cycling" => Some(SubSport::IndoorHandCycling),
            "field" => Some(SubSport::Field),
            "ice" => Some(SubSport::Ice),
            "ultimate" => Some(SubSport::Ultimate),
            "platform" => Some(SubSport::Platform),
            "squash" => Some(SubSport::Squash),
            "badminton" => Some(SubSport::Badminton),
            "racquetball" => Some(SubSport::Racquetball),
            "table_tennis" => Some(SubSport::TableTennis),
            "overland" => Some(SubSport::Overland),
            "trolling_motor" => Some(SubSport::TrollingMotor),
            "fly_canopy" => Some(SubSport::FlyCanopy),
            "fly_paraglide" => Some(SubSport::FlyParaglide),
            "fly_paramotor" => Some(SubSport::FlyParamotor),
            "fly_pressurized" => Some(SubSport::FlyPressurized),
            "fly_navigate" => Some(SubSport::FlyNavigate),
            "fly_timer" => Some(SubSport::FlyTimer),
            "fly_altimeter" => Some(SubSport::FlyAltimeter),
            "fly_wx" => Some(SubSport::FlyWx),
            "fly_vfr" => Some(SubSport::FlyVfr),
            "fly_ifr" => Some(SubSport::FlyIfr),
            "dynamic_apnea" => Some(SubSport::DynamicApnea),
            "enduro" => Some(SubSport::Enduro),
            "rucking" => Some(SubSport::Rucking),
            "rally" => Some(SubSport::Rally),
            "pool_triathlon" => Some(SubSport::PoolTriathlon),
            "e_bike_enduro" => Some(SubSport::EBikeEnduro),
            "all" => Some(SubSport::All),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum SportEvent {
    Uncategorized = 0,
    Geocaching = 1,
    Fitness = 2,
    Recreation = 3,
    Race = 4,
    SpecialEvent = 5,
    Training = 6,
    Transportation = 7,
    Touring = 8,
}

impl SportEvent {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            SportEvent::Uncategorized => "uncategorized",
            SportEvent::Geocaching => "geocaching",
            SportEvent::Fitness => "fitness",
            SportEvent::Recreation => "recreation",
            SportEvent::Race => "race",
            SportEvent::SpecialEvent => "special_event",
            SportEvent::Training => "training",
            SportEvent::Transportation => "transportation",
            SportEvent::Touring => "touring",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(SportEvent::Uncategorized),
            1 => Some(SportEvent::Geocaching),
            2 => Some(SportEvent::Fitness),
            3 => Some(SportEvent::Recreation),
            4 => Some(SportEvent::Race),
            5 => Some(SportEvent::SpecialEvent),
            6 => Some(SportEvent::Training),
            7 => Some(SportEvent::Transportation),
            8 => Some(SportEvent::Touring),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "uncategorized" => Some(SportEvent::Uncategorized),
            "geocaching" => Some(SportEvent::Geocaching),
            "fitness" => Some(SportEvent::Fitness),
            "recreation" => Some(SportEvent::Recreation),
            "race" => Some(SportEvent::Race),
            "special_event" => Some(SportEvent::SpecialEvent),
            "training" => Some(SportEvent::Training),
            "transportation" => Some(SportEvent::Transportation),
            "touring" => Some(SportEvent::Touring),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum Activity {
    Manual = 0,
    AutoMultiSport = 1,
}

impl Activity {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            Activity::Manual => "manual",
            Activity::AutoMultiSport => "auto_multi_sport",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(Activity::Manual),
            1 => Some(Activity::AutoMultiSport),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "manual" => Some(Activity::Manual),
            "auto_multi_sport" => Some(Activity::AutoMultiSport),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum Intensity {
    Active = 0,
    Rest = 1,
    Warmup = 2,
    Cooldown = 3,
    Recovery = 4,
    Interval = 5,
    Other = 6,
}

impl Intensity {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            Intensity::Active => "active",
            Intensity::Rest => "rest",
            Intensity::Warmup => "warmup",
            Intensity::Cooldown => "cooldown",
            Intensity::Recovery => "recovery",
            Intensity::Interval => "interval",
            Intensity::Other => "other",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(Intensity::Active),
            1 => Some(Intensity::Rest),
            2 => Some(Intensity::Warmup),
            3 => Some(Intensity::Cooldown),
            4 => Some(Intensity::Recovery),
            5 => Some(Intensity::Interval),
            6 => Some(Intensity::Other),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "active" => Some(Intensity::Active),
            "rest" => Some(Intensity::Rest),
            "warmup" => Some(Intensity::Warmup),
            "cooldown" => Some(Intensity::Cooldown),
            "recovery" => Some(Intensity::Recovery),
            "interval" => Some(Intensity::Interval),
            "other" => Some(Intensity::Other),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum SessionTrigger {
    ActivityEnd = 0,
    Manual = 1,
    AutoMultiSport = 2,
    FitnessEquipment = 3,
}

impl SessionTrigger {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            SessionTrigger::ActivityEnd => "activity_end",
            SessionTrigger::Manual => "manual",
            SessionTrigger::AutoMultiSport => "auto_multi_sport",
            SessionTrigger::FitnessEquipment => "fitness_equipment",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(SessionTrigger::ActivityEnd),
            1 => Some(SessionTrigger::Manual),
            2 => Some(SessionTrigger::AutoMultiSport),
            3 => Some(SessionTrigger::FitnessEquipment),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "activity_end" => Some(SessionTrigger::ActivityEnd),
            "manual" => Some(SessionTrigger::Manual),
            "auto_multi_sport" => Some(SessionTrigger::AutoMultiSport),
            "fitness_equipment" => Some(SessionTrigger::FitnessEquipment),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum AutolapTrigger {
    Time = 0,
    Distance = 1,
    PositionStart = 2,
    PositionLap = 3,
    PositionWaypoint = 4,
    PositionMarked = 5,
    Off = 6,
    AutoSelect = 13,
}

impl AutolapTrigger {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            AutolapTrigger::Time => "time",
            AutolapTrigger::Distance => "distance",
            AutolapTrigger::PositionStart => "position_start",
            AutolapTrigger::PositionLap => "position_lap",
            AutolapTrigger::PositionWaypoint => "position_waypoint",
            AutolapTrigger::PositionMarked => "position_marked",
            AutolapTrigger::Off => "off",
            AutolapTrigger::AutoSelect => "auto_select",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(AutolapTrigger::Time),
            1 => Some(AutolapTrigger::Distance),
            2 => Some(AutolapTrigger::PositionStart),
            3 => Some(AutolapTrigger::PositionLap),
            4 => Some(AutolapTrigger::PositionWaypoint),
            5 => Some(AutolapTrigger::PositionMarked),
            6 => Some(AutolapTrigger::Off),
            13 => Some(AutolapTrigger::AutoSelect),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "time" => Some(AutolapTrigger::Time),
            "distance" => Some(AutolapTrigger::Distance),
            "position_start" => Some(AutolapTrigger::PositionStart),
            "position_lap" => Some(AutolapTrigger::PositionLap),
            "position_waypoint" => Some(AutolapTrigger::PositionWaypoint),
            "position_marked" => Some(AutolapTrigger::PositionMarked),
            "off" => Some(AutolapTrigger::Off),
            "auto_select" => Some(AutolapTrigger::AutoSelect),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum LapTrigger {
    Manual = 0,
    Time = 1,
    Distance = 2,
    PositionStart = 3,
    PositionLap = 4,
    PositionWaypoint = 5,
    PositionMarked = 6,
    SessionEnd = 7,
    FitnessEquipment = 8,
}

impl LapTrigger {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            LapTrigger::Manual => "manual",
            LapTrigger::Time => "time",
            LapTrigger::Distance => "distance",
            LapTrigger::PositionStart => "position_start",
            LapTrigger::PositionLap => "position_lap",
            LapTrigger::PositionWaypoint => "position_waypoint",
            LapTrigger::PositionMarked => "position_marked",
            LapTrigger::SessionEnd => "session_end",
            LapTrigger::FitnessEquipment => "fitness_equipment",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(LapTrigger::Manual),
            1 => Some(LapTrigger::Time),
            2 => Some(LapTrigger::Distance),
            3 => Some(LapTrigger::PositionStart),
            4 => Some(LapTrigger::PositionLap),
            5 => Some(LapTrigger::PositionWaypoint),
            6 => Some(LapTrigger::PositionMarked),
            7 => Some(LapTrigger::SessionEnd),
            8 => Some(LapTrigger::FitnessEquipment),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "manual" => Some(LapTrigger::Manual),
            "time" => Some(LapTrigger::Time),
            "distance" => Some(LapTrigger::Distance),
            "position_start" => Some(LapTrigger::PositionStart),
            "position_lap" => Some(LapTrigger::PositionLap),
            "position_waypoint" => Some(LapTrigger::PositionWaypoint),
            "position_marked" => Some(LapTrigger::PositionMarked),
            "session_end" => Some(LapTrigger::SessionEnd),
            "fitness_equipment" => Some(LapTrigger::FitnessEquipment),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum TimeMode {
    Hour12 = 0,
    Hour24 = 1,
    Military = 2,
    Hour12WithSeconds = 3,
    Hour24WithSeconds = 4,
    Utc = 5,
}

impl TimeMode {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            TimeMode::Hour12 => "hour12",
            TimeMode::Hour24 => "hour24",
            TimeMode::Military => "military",
            TimeMode::Hour12WithSeconds => "hour_12_with_seconds",
            TimeMode::Hour24WithSeconds => "hour_24_with_seconds",
            TimeMode::Utc => "utc",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(TimeMode::Hour12),
            1 => Some(TimeMode::Hour24),
            2 => Some(TimeMode::Military),
            3 => Some(TimeMode::Hour12WithSeconds),
            4 => Some(TimeMode::Hour24WithSeconds),
            5 => Some(TimeMode::Utc),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "hour12" => Some(TimeMode::Hour12),
            "hour24" => Some(TimeMode::Hour24),
            "military" => Some(TimeMode::Military),
            "hour_12_with_seconds" => Some(TimeMode::Hour12WithSeconds),
            "hour_24_with_seconds" => Some(TimeMode::Hour24WithSeconds),
            "utc" => Some(TimeMode::Utc),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum BacklightMode {
    Off = 0,
    Manual = 1,
    KeyAndMessages = 2,
    AutoBrightness = 3,
    SmartNotifications = 4,
    KeyAndMessagesNight = 5,
    KeyAndMessagesAndSmartNotifications = 6,
}

impl BacklightMode {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            BacklightMode::Off => "off",
            BacklightMode::Manual => "manual",
            BacklightMode::KeyAndMessages => "key_and_messages",
            BacklightMode::AutoBrightness => "auto_brightness",
            BacklightMode::SmartNotifications => "smart_notifications",
            BacklightMode::KeyAndMessagesNight => "key_and_messages_night",
            BacklightMode::KeyAndMessagesAndSmartNotifications => {
                "key_and_messages_and_smart_notifications"
            }
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(BacklightMode::Off),
            1 => Some(BacklightMode::Manual),
            2 => Some(BacklightMode::KeyAndMessages),
            3 => Some(BacklightMode::AutoBrightness),
            4 => Some(BacklightMode::SmartNotifications),
            5 => Some(BacklightMode::KeyAndMessagesNight),
            6 => Some(BacklightMode::KeyAndMessagesAndSmartNotifications),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "off" => Some(BacklightMode::Off),
            "manual" => Some(BacklightMode::Manual),
            "key_and_messages" => Some(BacklightMode::KeyAndMessages),
            "auto_brightness" => Some(BacklightMode::AutoBrightness),
            "smart_notifications" => Some(BacklightMode::SmartNotifications),
            "key_and_messages_night" => Some(BacklightMode::KeyAndMessagesNight),
            "key_and_messages_and_smart_notifications" => {
                Some(BacklightMode::KeyAndMessagesAndSmartNotifications)
            }
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum DateMode {
    DayMonth = 0,
    MonthDay = 1,
}

impl DateMode {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            DateMode::DayMonth => "day_month",
            DateMode::MonthDay => "month_day",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(DateMode::DayMonth),
            1 => Some(DateMode::MonthDay),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "day_month" => Some(DateMode::DayMonth),
            "month_day" => Some(DateMode::MonthDay),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum BacklightTimeout {
    Infinite = 0,
}

impl BacklightTimeout {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            BacklightTimeout::Infinite => "infinite",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(BacklightTimeout::Infinite),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "infinite" => Some(BacklightTimeout::Infinite),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum Event {
    Timer = 0,
    Workout = 3,
    WorkoutStep = 4,
    PowerDown = 5,
    PowerUp = 6,
    OffCourse = 7,
    Session = 8,
    Lap = 9,
    CoursePoint = 10,
    Battery = 11,
    VirtualPartnerPace = 12,
    HrHighAlert = 13,
    HrLowAlert = 14,
    SpeedHighAlert = 15,
    SpeedLowAlert = 16,
    CadHighAlert = 17,
    CadLowAlert = 18,
    PowerHighAlert = 19,
    PowerLowAlert = 20,
    RecoveryHr = 21,
    BatteryLow = 22,
    TimeDurationAlert = 23,
    DistanceDurationAlert = 24,
    CalorieDurationAlert = 25,
    Activity = 26,
    FitnessEquipment = 27,
    Length = 28,
    UserMarker = 32,
    SportPoint = 33,
    Calibration = 36,
    FrontGearChange = 42,
    RearGearChange = 43,
    RiderPositionChange = 44,
    ElevHighAlert = 45,
    ElevLowAlert = 46,
    CommTimeout = 47,
    AutoActivityDetect = 54,
    DiveAlert = 56,
    DiveGasSwitched = 57,
    TankPressureReserve = 71,
    TankPressureCritical = 72,
    TankLost = 73,
    RadarThreatAlert = 75,
    TankBatteryLow = 76,
    TankPodConnected = 81,
    TankPodDisconnected = 82,
}

impl Event {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            Event::Timer => "timer",
            Event::Workout => "workout",
            Event::WorkoutStep => "workout_step",
            Event::PowerDown => "power_down",
            Event::PowerUp => "power_up",
            Event::OffCourse => "off_course",
            Event::Session => "session",
            Event::Lap => "lap",
            Event::CoursePoint => "course_point",
            Event::Battery => "battery",
            Event::VirtualPartnerPace => "virtual_partner_pace",
            Event::HrHighAlert => "hr_high_alert",
            Event::HrLowAlert => "hr_low_alert",
            Event::SpeedHighAlert => "speed_high_alert",
            Event::SpeedLowAlert => "speed_low_alert",
            Event::CadHighAlert => "cad_high_alert",
            Event::CadLowAlert => "cad_low_alert",
            Event::PowerHighAlert => "power_high_alert",
            Event::PowerLowAlert => "power_low_alert",
            Event::RecoveryHr => "recovery_hr",
            Event::BatteryLow => "battery_low",
            Event::TimeDurationAlert => "time_duration_alert",
            Event::DistanceDurationAlert => "distance_duration_alert",
            Event::CalorieDurationAlert => "calorie_duration_alert",
            Event::Activity => "activity",
            Event::FitnessEquipment => "fitness_equipment",
            Event::Length => "length",
            Event::UserMarker => "user_marker",
            Event::SportPoint => "sport_point",
            Event::Calibration => "calibration",
            Event::FrontGearChange => "front_gear_change",
            Event::RearGearChange => "rear_gear_change",
            Event::RiderPositionChange => "rider_position_change",
            Event::ElevHighAlert => "elev_high_alert",
            Event::ElevLowAlert => "elev_low_alert",
            Event::CommTimeout => "comm_timeout",
            Event::AutoActivityDetect => "auto_activity_detect",
            Event::DiveAlert => "dive_alert",
            Event::DiveGasSwitched => "dive_gas_switched",
            Event::TankPressureReserve => "tank_pressure_reserve",
            Event::TankPressureCritical => "tank_pressure_critical",
            Event::TankLost => "tank_lost",
            Event::RadarThreatAlert => "radar_threat_alert",
            Event::TankBatteryLow => "tank_battery_low",
            Event::TankPodConnected => "tank_pod_connected",
            Event::TankPodDisconnected => "tank_pod_disconnected",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(Event::Timer),
            3 => Some(Event::Workout),
            4 => Some(Event::WorkoutStep),
            5 => Some(Event::PowerDown),
            6 => Some(Event::PowerUp),
            7 => Some(Event::OffCourse),
            8 => Some(Event::Session),
            9 => Some(Event::Lap),
            10 => Some(Event::CoursePoint),
            11 => Some(Event::Battery),
            12 => Some(Event::VirtualPartnerPace),
            13 => Some(Event::HrHighAlert),
            14 => Some(Event::HrLowAlert),
            15 => Some(Event::SpeedHighAlert),
            16 => Some(Event::SpeedLowAlert),
            17 => Some(Event::CadHighAlert),
            18 => Some(Event::CadLowAlert),
            19 => Some(Event::PowerHighAlert),
            20 => Some(Event::PowerLowAlert),
            21 => Some(Event::RecoveryHr),
            22 => Some(Event::BatteryLow),
            23 => Some(Event::TimeDurationAlert),
            24 => Some(Event::DistanceDurationAlert),
            25 => Some(Event::CalorieDurationAlert),
            26 => Some(Event::Activity),
            27 => Some(Event::FitnessEquipment),
            28 => Some(Event::Length),
            32 => Some(Event::UserMarker),
            33 => Some(Event::SportPoint),
            36 => Some(Event::Calibration),
            42 => Some(Event::FrontGearChange),
            43 => Some(Event::RearGearChange),
            44 => Some(Event::RiderPositionChange),
            45 => Some(Event::ElevHighAlert),
            46 => Some(Event::ElevLowAlert),
            47 => Some(Event::CommTimeout),
            54 => Some(Event::AutoActivityDetect),
            56 => Some(Event::DiveAlert),
            57 => Some(Event::DiveGasSwitched),
            71 => Some(Event::TankPressureReserve),
            72 => Some(Event::TankPressureCritical),
            73 => Some(Event::TankLost),
            75 => Some(Event::RadarThreatAlert),
            76 => Some(Event::TankBatteryLow),
            81 => Some(Event::TankPodConnected),
            82 => Some(Event::TankPodDisconnected),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "timer" => Some(Event::Timer),
            "workout" => Some(Event::Workout),
            "workout_step" => Some(Event::WorkoutStep),
            "power_down" => Some(Event::PowerDown),
            "power_up" => Some(Event::PowerUp),
            "off_course" => Some(Event::OffCourse),
            "session" => Some(Event::Session),
            "lap" => Some(Event::Lap),
            "course_point" => Some(Event::CoursePoint),
            "battery" => Some(Event::Battery),
            "virtual_partner_pace" => Some(Event::VirtualPartnerPace),
            "hr_high_alert" => Some(Event::HrHighAlert),
            "hr_low_alert" => Some(Event::HrLowAlert),
            "speed_high_alert" => Some(Event::SpeedHighAlert),
            "speed_low_alert" => Some(Event::SpeedLowAlert),
            "cad_high_alert" => Some(Event::CadHighAlert),
            "cad_low_alert" => Some(Event::CadLowAlert),
            "power_high_alert" => Some(Event::PowerHighAlert),
            "power_low_alert" => Some(Event::PowerLowAlert),
            "recovery_hr" => Some(Event::RecoveryHr),
            "battery_low" => Some(Event::BatteryLow),
            "time_duration_alert" => Some(Event::TimeDurationAlert),
            "distance_duration_alert" => Some(Event::DistanceDurationAlert),
            "calorie_duration_alert" => Some(Event::CalorieDurationAlert),
            "activity" => Some(Event::Activity),
            "fitness_equipment" => Some(Event::FitnessEquipment),
            "length" => Some(Event::Length),
            "user_marker" => Some(Event::UserMarker),
            "sport_point" => Some(Event::SportPoint),
            "calibration" => Some(Event::Calibration),
            "front_gear_change" => Some(Event::FrontGearChange),
            "rear_gear_change" => Some(Event::RearGearChange),
            "rider_position_change" => Some(Event::RiderPositionChange),
            "elev_high_alert" => Some(Event::ElevHighAlert),
            "elev_low_alert" => Some(Event::ElevLowAlert),
            "comm_timeout" => Some(Event::CommTimeout),
            "auto_activity_detect" => Some(Event::AutoActivityDetect),
            "dive_alert" => Some(Event::DiveAlert),
            "dive_gas_switched" => Some(Event::DiveGasSwitched),
            "tank_pressure_reserve" => Some(Event::TankPressureReserve),
            "tank_pressure_critical" => Some(Event::TankPressureCritical),
            "tank_lost" => Some(Event::TankLost),
            "radar_threat_alert" => Some(Event::RadarThreatAlert),
            "tank_battery_low" => Some(Event::TankBatteryLow),
            "tank_pod_connected" => Some(Event::TankPodConnected),
            "tank_pod_disconnected" => Some(Event::TankPodDisconnected),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum EventType {
    Start = 0,
    Stop = 1,
    ConsecutiveDepreciated = 2,
    Marker = 3,
    StopAll = 4,
    BeginDepreciated = 5,
    EndDepreciated = 6,
    EndAllDepreciated = 7,
    StopDisable = 8,
    StopDisableAll = 9,
}

impl EventType {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            EventType::Start => "start",
            EventType::Stop => "stop",
            EventType::ConsecutiveDepreciated => "consecutive_depreciated",
            EventType::Marker => "marker",
            EventType::StopAll => "stop_all",
            EventType::BeginDepreciated => "begin_depreciated",
            EventType::EndDepreciated => "end_depreciated",
            EventType::EndAllDepreciated => "end_all_depreciated",
            EventType::StopDisable => "stop_disable",
            EventType::StopDisableAll => "stop_disable_all",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(EventType::Start),
            1 => Some(EventType::Stop),
            2 => Some(EventType::ConsecutiveDepreciated),
            3 => Some(EventType::Marker),
            4 => Some(EventType::StopAll),
            5 => Some(EventType::BeginDepreciated),
            6 => Some(EventType::EndDepreciated),
            7 => Some(EventType::EndAllDepreciated),
            8 => Some(EventType::StopDisable),
            9 => Some(EventType::StopDisableAll),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "start" => Some(EventType::Start),
            "stop" => Some(EventType::Stop),
            "consecutive_depreciated" => Some(EventType::ConsecutiveDepreciated),
            "marker" => Some(EventType::Marker),
            "stop_all" => Some(EventType::StopAll),
            "begin_depreciated" => Some(EventType::BeginDepreciated),
            "end_depreciated" => Some(EventType::EndDepreciated),
            "end_all_depreciated" => Some(EventType::EndAllDepreciated),
            "stop_disable" => Some(EventType::StopDisable),
            "stop_disable_all" => Some(EventType::StopDisableAll),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum TimerTrigger {
    Manual = 0,
    Auto = 1,
    FitnessEquipment = 2,
}

impl TimerTrigger {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            TimerTrigger::Manual => "manual",
            TimerTrigger::Auto => "auto",
            TimerTrigger::FitnessEquipment => "fitness_equipment",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(TimerTrigger::Manual),
            1 => Some(TimerTrigger::Auto),
            2 => Some(TimerTrigger::FitnessEquipment),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "manual" => Some(TimerTrigger::Manual),
            "auto" => Some(TimerTrigger::Auto),
            "fitness_equipment" => Some(TimerTrigger::FitnessEquipment),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum FitnessEquipmentState {
    Ready = 0,
    InUse = 1,
    Paused = 2,
    Unknown = 3,
}

impl FitnessEquipmentState {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            FitnessEquipmentState::Ready => "ready",
            FitnessEquipmentState::InUse => "in_use",
            FitnessEquipmentState::Paused => "paused",
            FitnessEquipmentState::Unknown => "unknown",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(FitnessEquipmentState::Ready),
            1 => Some(FitnessEquipmentState::InUse),
            2 => Some(FitnessEquipmentState::Paused),
            3 => Some(FitnessEquipmentState::Unknown),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "ready" => Some(FitnessEquipmentState::Ready),
            "in_use" => Some(FitnessEquipmentState::InUse),
            "paused" => Some(FitnessEquipmentState::Paused),
            "unknown" => Some(FitnessEquipmentState::Unknown),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum Tone {
    Off = 0,
    Tone = 1,
    Vibrate = 2,
    ToneAndVibrate = 3,
}

impl Tone {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            Tone::Off => "off",
            Tone::Tone => "tone",
            Tone::Vibrate => "vibrate",
            Tone::ToneAndVibrate => "tone_and_vibrate",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(Tone::Off),
            1 => Some(Tone::Tone),
            2 => Some(Tone::Vibrate),
            3 => Some(Tone::ToneAndVibrate),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "off" => Some(Tone::Off),
            "tone" => Some(Tone::Tone),
            "vibrate" => Some(Tone::Vibrate),
            "tone_and_vibrate" => Some(Tone::ToneAndVibrate),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum Autoscroll {
    None = 0,
    Slow = 1,
    Medium = 2,
    Fast = 3,
}

impl Autoscroll {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            Autoscroll::None => "none",
            Autoscroll::Slow => "slow",
            Autoscroll::Medium => "medium",
            Autoscroll::Fast => "fast",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(Autoscroll::None),
            1 => Some(Autoscroll::Slow),
            2 => Some(Autoscroll::Medium),
            3 => Some(Autoscroll::Fast),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "none" => Some(Autoscroll::None),
            "slow" => Some(Autoscroll::Slow),
            "medium" => Some(Autoscroll::Medium),
            "fast" => Some(Autoscroll::Fast),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum ActivityClass {
    Level = 127,
    LevelMax = 100,
    Athlete = 128,
}

impl ActivityClass {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            ActivityClass::Level => "level",
            ActivityClass::LevelMax => "level_max",
            ActivityClass::Athlete => "athlete",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            127 => Some(ActivityClass::Level),
            100 => Some(ActivityClass::LevelMax),
            128 => Some(ActivityClass::Athlete),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "level" => Some(ActivityClass::Level),
            "level_max" => Some(ActivityClass::LevelMax),
            "athlete" => Some(ActivityClass::Athlete),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum HrZoneCalc {
    Custom = 0,
    PercentMaxHr = 1,
    PercentHrr = 2,
    PercentLthr = 3,
}

impl HrZoneCalc {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            HrZoneCalc::Custom => "custom",
            HrZoneCalc::PercentMaxHr => "percent_max_hr",
            HrZoneCalc::PercentHrr => "percent_hrr",
            HrZoneCalc::PercentLthr => "percent_lthr",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(HrZoneCalc::Custom),
            1 => Some(HrZoneCalc::PercentMaxHr),
            2 => Some(HrZoneCalc::PercentHrr),
            3 => Some(HrZoneCalc::PercentLthr),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "custom" => Some(HrZoneCalc::Custom),
            "percent_max_hr" => Some(HrZoneCalc::PercentMaxHr),
            "percent_hrr" => Some(HrZoneCalc::PercentHrr),
            "percent_lthr" => Some(HrZoneCalc::PercentLthr),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum PwrZoneCalc {
    Custom = 0,
    PercentFtp = 1,
}

impl PwrZoneCalc {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            PwrZoneCalc::Custom => "custom",
            PwrZoneCalc::PercentFtp => "percent_ftp",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(PwrZoneCalc::Custom),
            1 => Some(PwrZoneCalc::PercentFtp),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "custom" => Some(PwrZoneCalc::Custom),
            "percent_ftp" => Some(PwrZoneCalc::PercentFtp),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum WktStepDuration {
    Time = 0,
    Distance = 1,
    HrLessThan = 2,
    HrGreaterThan = 3,
    Calories = 4,
    Open = 5,
    RepeatUntilStepsCmplt = 6,
    RepeatUntilTime = 7,
    RepeatUntilDistance = 8,
    RepeatUntilCalories = 9,
    RepeatUntilHrLessThan = 10,
    RepeatUntilHrGreaterThan = 11,
    RepeatUntilPowerLessThan = 12,
    RepeatUntilPowerGreaterThan = 13,
    PowerLessThan = 14,
    PowerGreaterThan = 15,
    TrainingPeaksTss = 16,
    RepeatUntilPowerLastLapLessThan = 17,
    RepeatUntilMaxPowerLastLapLessThan = 18,
    Power3sLessThan = 19,
    Power10sLessThan = 20,
    Power30sLessThan = 21,
    Power3sGreaterThan = 22,
    Power10sGreaterThan = 23,
    Power30sGreaterThan = 24,
    PowerLapLessThan = 25,
    PowerLapGreaterThan = 26,
    RepeatUntilTrainingPeaksTss = 27,
    RepetitionTime = 28,
    Reps = 29,
    TimeOnly = 31,
}

impl WktStepDuration {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            WktStepDuration::Time => "time",
            WktStepDuration::Distance => "distance",
            WktStepDuration::HrLessThan => "hr_less_than",
            WktStepDuration::HrGreaterThan => "hr_greater_than",
            WktStepDuration::Calories => "calories",
            WktStepDuration::Open => "open",
            WktStepDuration::RepeatUntilStepsCmplt => "repeat_until_steps_cmplt",
            WktStepDuration::RepeatUntilTime => "repeat_until_time",
            WktStepDuration::RepeatUntilDistance => "repeat_until_distance",
            WktStepDuration::RepeatUntilCalories => "repeat_until_calories",
            WktStepDuration::RepeatUntilHrLessThan => "repeat_until_hr_less_than",
            WktStepDuration::RepeatUntilHrGreaterThan => "repeat_until_hr_greater_than",
            WktStepDuration::RepeatUntilPowerLessThan => "repeat_until_power_less_than",
            WktStepDuration::RepeatUntilPowerGreaterThan => "repeat_until_power_greater_than",
            WktStepDuration::PowerLessThan => "power_less_than",
            WktStepDuration::PowerGreaterThan => "power_greater_than",
            WktStepDuration::TrainingPeaksTss => "training_peaks_tss",
            WktStepDuration::RepeatUntilPowerLastLapLessThan => {
                "repeat_until_power_last_lap_less_than"
            }
            WktStepDuration::RepeatUntilMaxPowerLastLapLessThan => {
                "repeat_until_max_power_last_lap_less_than"
            }
            WktStepDuration::Power3sLessThan => "power_3s_less_than",
            WktStepDuration::Power10sLessThan => "power_10s_less_than",
            WktStepDuration::Power30sLessThan => "power_30s_less_than",
            WktStepDuration::Power3sGreaterThan => "power_3s_greater_than",
            WktStepDuration::Power10sGreaterThan => "power_10s_greater_than",
            WktStepDuration::Power30sGreaterThan => "power_30s_greater_than",
            WktStepDuration::PowerLapLessThan => "power_lap_less_than",
            WktStepDuration::PowerLapGreaterThan => "power_lap_greater_than",
            WktStepDuration::RepeatUntilTrainingPeaksTss => "repeat_until_training_peaks_tss",
            WktStepDuration::RepetitionTime => "repetition_time",
            WktStepDuration::Reps => "reps",
            WktStepDuration::TimeOnly => "time_only",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(WktStepDuration::Time),
            1 => Some(WktStepDuration::Distance),
            2 => Some(WktStepDuration::HrLessThan),
            3 => Some(WktStepDuration::HrGreaterThan),
            4 => Some(WktStepDuration::Calories),
            5 => Some(WktStepDuration::Open),
            6 => Some(WktStepDuration::RepeatUntilStepsCmplt),
            7 => Some(WktStepDuration::RepeatUntilTime),
            8 => Some(WktStepDuration::RepeatUntilDistance),
            9 => Some(WktStepDuration::RepeatUntilCalories),
            10 => Some(WktStepDuration::RepeatUntilHrLessThan),
            11 => Some(WktStepDuration::RepeatUntilHrGreaterThan),
            12 => Some(WktStepDuration::RepeatUntilPowerLessThan),
            13 => Some(WktStepDuration::RepeatUntilPowerGreaterThan),
            14 => Some(WktStepDuration::PowerLessThan),
            15 => Some(WktStepDuration::PowerGreaterThan),
            16 => Some(WktStepDuration::TrainingPeaksTss),
            17 => Some(WktStepDuration::RepeatUntilPowerLastLapLessThan),
            18 => Some(WktStepDuration::RepeatUntilMaxPowerLastLapLessThan),
            19 => Some(WktStepDuration::Power3sLessThan),
            20 => Some(WktStepDuration::Power10sLessThan),
            21 => Some(WktStepDuration::Power30sLessThan),
            22 => Some(WktStepDuration::Power3sGreaterThan),
            23 => Some(WktStepDuration::Power10sGreaterThan),
            24 => Some(WktStepDuration::Power30sGreaterThan),
            25 => Some(WktStepDuration::PowerLapLessThan),
            26 => Some(WktStepDuration::PowerLapGreaterThan),
            27 => Some(WktStepDuration::RepeatUntilTrainingPeaksTss),
            28 => Some(WktStepDuration::RepetitionTime),
            29 => Some(WktStepDuration::Reps),
            31 => Some(WktStepDuration::TimeOnly),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "time" => Some(WktStepDuration::Time),
            "distance" => Some(WktStepDuration::Distance),
            "hr_less_than" => Some(WktStepDuration::HrLessThan),
            "hr_greater_than" => Some(WktStepDuration::HrGreaterThan),
            "calories" => Some(WktStepDuration::Calories),
            "open" => Some(WktStepDuration::Open),
            "repeat_until_steps_cmplt" => Some(WktStepDuration::RepeatUntilStepsCmplt),
            "repeat_until_time" => Some(WktStepDuration::RepeatUntilTime),
            "repeat_until_distance" => Some(WktStepDuration::RepeatUntilDistance),
            "repeat_until_calories" => Some(WktStepDuration::RepeatUntilCalories),
            "repeat_until_hr_less_than" => Some(WktStepDuration::RepeatUntilHrLessThan),
            "repeat_until_hr_greater_than" => Some(WktStepDuration::RepeatUntilHrGreaterThan),
            "repeat_until_power_less_than" => Some(WktStepDuration::RepeatUntilPowerLessThan),
            "repeat_until_power_greater_than" => Some(WktStepDuration::RepeatUntilPowerGreaterThan),
            "power_less_than" => Some(WktStepDuration::PowerLessThan),
            "power_greater_than" => Some(WktStepDuration::PowerGreaterThan),
            "training_peaks_tss" => Some(WktStepDuration::TrainingPeaksTss),
            "repeat_until_power_last_lap_less_than" => {
                Some(WktStepDuration::RepeatUntilPowerLastLapLessThan)
            }
            "repeat_until_max_power_last_lap_less_than" => {
                Some(WktStepDuration::RepeatUntilMaxPowerLastLapLessThan)
            }
            "power_3s_less_than" => Some(WktStepDuration::Power3sLessThan),
            "power_10s_less_than" => Some(WktStepDuration::Power10sLessThan),
            "power_30s_less_than" => Some(WktStepDuration::Power30sLessThan),
            "power_3s_greater_than" => Some(WktStepDuration::Power3sGreaterThan),
            "power_10s_greater_than" => Some(WktStepDuration::Power10sGreaterThan),
            "power_30s_greater_than" => Some(WktStepDuration::Power30sGreaterThan),
            "power_lap_less_than" => Some(WktStepDuration::PowerLapLessThan),
            "power_lap_greater_than" => Some(WktStepDuration::PowerLapGreaterThan),
            "repeat_until_training_peaks_tss" => Some(WktStepDuration::RepeatUntilTrainingPeaksTss),
            "repetition_time" => Some(WktStepDuration::RepetitionTime),
            "reps" => Some(WktStepDuration::Reps),
            "time_only" => Some(WktStepDuration::TimeOnly),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum WktStepTarget {
    Speed = 0,
    HeartRate = 1,
    Open = 2,
    Cadence = 3,
    Power = 4,
    Grade = 5,
    Resistance = 6,
    Power3s = 7,
    Power10s = 8,
    Power30s = 9,
    PowerLap = 10,
    SwimStroke = 11,
    SpeedLap = 12,
    HeartRateLap = 13,
}

impl WktStepTarget {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            WktStepTarget::Speed => "speed",
            WktStepTarget::HeartRate => "heart_rate",
            WktStepTarget::Open => "open",
            WktStepTarget::Cadence => "cadence",
            WktStepTarget::Power => "power",
            WktStepTarget::Grade => "grade",
            WktStepTarget::Resistance => "resistance",
            WktStepTarget::Power3s => "power_3s",
            WktStepTarget::Power10s => "power_10s",
            WktStepTarget::Power30s => "power_30s",
            WktStepTarget::PowerLap => "power_lap",
            WktStepTarget::SwimStroke => "swim_stroke",
            WktStepTarget::SpeedLap => "speed_lap",
            WktStepTarget::HeartRateLap => "heart_rate_lap",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(WktStepTarget::Speed),
            1 => Some(WktStepTarget::HeartRate),
            2 => Some(WktStepTarget::Open),
            3 => Some(WktStepTarget::Cadence),
            4 => Some(WktStepTarget::Power),
            5 => Some(WktStepTarget::Grade),
            6 => Some(WktStepTarget::Resistance),
            7 => Some(WktStepTarget::Power3s),
            8 => Some(WktStepTarget::Power10s),
            9 => Some(WktStepTarget::Power30s),
            10 => Some(WktStepTarget::PowerLap),
            11 => Some(WktStepTarget::SwimStroke),
            12 => Some(WktStepTarget::SpeedLap),
            13 => Some(WktStepTarget::HeartRateLap),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "speed" => Some(WktStepTarget::Speed),
            "heart_rate" => Some(WktStepTarget::HeartRate),
            "open" => Some(WktStepTarget::Open),
            "cadence" => Some(WktStepTarget::Cadence),
            "power" => Some(WktStepTarget::Power),
            "grade" => Some(WktStepTarget::Grade),
            "resistance" => Some(WktStepTarget::Resistance),
            "power_3s" => Some(WktStepTarget::Power3s),
            "power_10s" => Some(WktStepTarget::Power10s),
            "power_30s" => Some(WktStepTarget::Power30s),
            "power_lap" => Some(WktStepTarget::PowerLap),
            "swim_stroke" => Some(WktStepTarget::SwimStroke),
            "speed_lap" => Some(WktStepTarget::SpeedLap),
            "heart_rate_lap" => Some(WktStepTarget::HeartRateLap),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum Goal {
    Time = 0,
    Distance = 1,
    Calories = 2,
    Frequency = 3,
    Steps = 4,
    Ascent = 5,
    ActiveMinutes = 6,
}

impl Goal {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            Goal::Time => "time",
            Goal::Distance => "distance",
            Goal::Calories => "calories",
            Goal::Frequency => "frequency",
            Goal::Steps => "steps",
            Goal::Ascent => "ascent",
            Goal::ActiveMinutes => "active_minutes",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(Goal::Time),
            1 => Some(Goal::Distance),
            2 => Some(Goal::Calories),
            3 => Some(Goal::Frequency),
            4 => Some(Goal::Steps),
            5 => Some(Goal::Ascent),
            6 => Some(Goal::ActiveMinutes),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "time" => Some(Goal::Time),
            "distance" => Some(Goal::Distance),
            "calories" => Some(Goal::Calories),
            "frequency" => Some(Goal::Frequency),
            "steps" => Some(Goal::Steps),
            "ascent" => Some(Goal::Ascent),
            "active_minutes" => Some(Goal::ActiveMinutes),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum GoalRecurrence {
    Off = 0,
    Daily = 1,
    Weekly = 2,
    Monthly = 3,
    Yearly = 4,
    Custom = 5,
}

impl GoalRecurrence {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            GoalRecurrence::Off => "off",
            GoalRecurrence::Daily => "daily",
            GoalRecurrence::Weekly => "weekly",
            GoalRecurrence::Monthly => "monthly",
            GoalRecurrence::Yearly => "yearly",
            GoalRecurrence::Custom => "custom",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(GoalRecurrence::Off),
            1 => Some(GoalRecurrence::Daily),
            2 => Some(GoalRecurrence::Weekly),
            3 => Some(GoalRecurrence::Monthly),
            4 => Some(GoalRecurrence::Yearly),
            5 => Some(GoalRecurrence::Custom),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "off" => Some(GoalRecurrence::Off),
            "daily" => Some(GoalRecurrence::Daily),
            "weekly" => Some(GoalRecurrence::Weekly),
            "monthly" => Some(GoalRecurrence::Monthly),
            "yearly" => Some(GoalRecurrence::Yearly),
            "custom" => Some(GoalRecurrence::Custom),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum GoalSource {
    Auto = 0,
    Community = 1,
    User = 2,
}

impl GoalSource {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            GoalSource::Auto => "auto",
            GoalSource::Community => "community",
            GoalSource::User => "user",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(GoalSource::Auto),
            1 => Some(GoalSource::Community),
            2 => Some(GoalSource::User),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "auto" => Some(GoalSource::Auto),
            "community" => Some(GoalSource::Community),
            "user" => Some(GoalSource::User),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum Schedule {
    Workout = 0,
    Course = 1,
}

impl Schedule {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            Schedule::Workout => "workout",
            Schedule::Course => "course",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(Schedule::Workout),
            1 => Some(Schedule::Course),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "workout" => Some(Schedule::Workout),
            "course" => Some(Schedule::Course),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum CoursePoint {
    Generic = 0,
    Summit = 1,
    Valley = 2,
    Water = 3,
    Food = 4,
    Danger = 5,
    Left = 6,
    Right = 7,
    Straight = 8,
    FirstAid = 9,
    FourthCategory = 10,
    ThirdCategory = 11,
    SecondCategory = 12,
    FirstCategory = 13,
    HorsCategory = 14,
    Sprint = 15,
    LeftFork = 16,
    RightFork = 17,
    MiddleFork = 18,
    SlightLeft = 19,
    SharpLeft = 20,
    SlightRight = 21,
    SharpRight = 22,
    UTurn = 23,
    SegmentStart = 24,
    SegmentEnd = 25,
    Campsite = 27,
    AidStation = 28,
    RestArea = 29,
    GeneralDistance = 30,
    Service = 31,
    EnergyGel = 32,
    SportsDrink = 33,
    MileMarker = 34,
    Checkpoint = 35,
    Shelter = 36,
    MeetingSpot = 37,
    Overlook = 38,
    Toilet = 39,
    Shower = 40,
    Gear = 41,
    SharpCurve = 42,
    SteepIncline = 43,
    Tunnel = 44,
    Bridge = 45,
    Obstacle = 46,
    Crossing = 47,
    Store = 48,
    Transition = 49,
    Navaid = 50,
    Transport = 51,
    Alert = 52,
    Info = 53,
}

impl CoursePoint {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            CoursePoint::Generic => "generic",
            CoursePoint::Summit => "summit",
            CoursePoint::Valley => "valley",
            CoursePoint::Water => "water",
            CoursePoint::Food => "food",
            CoursePoint::Danger => "danger",
            CoursePoint::Left => "left",
            CoursePoint::Right => "right",
            CoursePoint::Straight => "straight",
            CoursePoint::FirstAid => "first_aid",
            CoursePoint::FourthCategory => "fourth_category",
            CoursePoint::ThirdCategory => "third_category",
            CoursePoint::SecondCategory => "second_category",
            CoursePoint::FirstCategory => "first_category",
            CoursePoint::HorsCategory => "hors_category",
            CoursePoint::Sprint => "sprint",
            CoursePoint::LeftFork => "left_fork",
            CoursePoint::RightFork => "right_fork",
            CoursePoint::MiddleFork => "middle_fork",
            CoursePoint::SlightLeft => "slight_left",
            CoursePoint::SharpLeft => "sharp_left",
            CoursePoint::SlightRight => "slight_right",
            CoursePoint::SharpRight => "sharp_right",
            CoursePoint::UTurn => "u_turn",
            CoursePoint::SegmentStart => "segment_start",
            CoursePoint::SegmentEnd => "segment_end",
            CoursePoint::Campsite => "campsite",
            CoursePoint::AidStation => "aid_station",
            CoursePoint::RestArea => "rest_area",
            CoursePoint::GeneralDistance => "general_distance",
            CoursePoint::Service => "service",
            CoursePoint::EnergyGel => "energy_gel",
            CoursePoint::SportsDrink => "sports_drink",
            CoursePoint::MileMarker => "mile_marker",
            CoursePoint::Checkpoint => "checkpoint",
            CoursePoint::Shelter => "shelter",
            CoursePoint::MeetingSpot => "meeting_spot",
            CoursePoint::Overlook => "overlook",
            CoursePoint::Toilet => "toilet",
            CoursePoint::Shower => "shower",
            CoursePoint::Gear => "gear",
            CoursePoint::SharpCurve => "sharp_curve",
            CoursePoint::SteepIncline => "steep_incline",
            CoursePoint::Tunnel => "tunnel",
            CoursePoint::Bridge => "bridge",
            CoursePoint::Obstacle => "obstacle",
            CoursePoint::Crossing => "crossing",
            CoursePoint::Store => "store",
            CoursePoint::Transition => "transition",
            CoursePoint::Navaid => "navaid",
            CoursePoint::Transport => "transport",
            CoursePoint::Alert => "alert",
            CoursePoint::Info => "info",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(CoursePoint::Generic),
            1 => Some(CoursePoint::Summit),
            2 => Some(CoursePoint::Valley),
            3 => Some(CoursePoint::Water),
            4 => Some(CoursePoint::Food),
            5 => Some(CoursePoint::Danger),
            6 => Some(CoursePoint::Left),
            7 => Some(CoursePoint::Right),
            8 => Some(CoursePoint::Straight),
            9 => Some(CoursePoint::FirstAid),
            10 => Some(CoursePoint::FourthCategory),
            11 => Some(CoursePoint::ThirdCategory),
            12 => Some(CoursePoint::SecondCategory),
            13 => Some(CoursePoint::FirstCategory),
            14 => Some(CoursePoint::HorsCategory),
            15 => Some(CoursePoint::Sprint),
            16 => Some(CoursePoint::LeftFork),
            17 => Some(CoursePoint::RightFork),
            18 => Some(CoursePoint::MiddleFork),
            19 => Some(CoursePoint::SlightLeft),
            20 => Some(CoursePoint::SharpLeft),
            21 => Some(CoursePoint::SlightRight),
            22 => Some(CoursePoint::SharpRight),
            23 => Some(CoursePoint::UTurn),
            24 => Some(CoursePoint::SegmentStart),
            25 => Some(CoursePoint::SegmentEnd),
            27 => Some(CoursePoint::Campsite),
            28 => Some(CoursePoint::AidStation),
            29 => Some(CoursePoint::RestArea),
            30 => Some(CoursePoint::GeneralDistance),
            31 => Some(CoursePoint::Service),
            32 => Some(CoursePoint::EnergyGel),
            33 => Some(CoursePoint::SportsDrink),
            34 => Some(CoursePoint::MileMarker),
            35 => Some(CoursePoint::Checkpoint),
            36 => Some(CoursePoint::Shelter),
            37 => Some(CoursePoint::MeetingSpot),
            38 => Some(CoursePoint::Overlook),
            39 => Some(CoursePoint::Toilet),
            40 => Some(CoursePoint::Shower),
            41 => Some(CoursePoint::Gear),
            42 => Some(CoursePoint::SharpCurve),
            43 => Some(CoursePoint::SteepIncline),
            44 => Some(CoursePoint::Tunnel),
            45 => Some(CoursePoint::Bridge),
            46 => Some(CoursePoint::Obstacle),
            47 => Some(CoursePoint::Crossing),
            48 => Some(CoursePoint::Store),
            49 => Some(CoursePoint::Transition),
            50 => Some(CoursePoint::Navaid),
            51 => Some(CoursePoint::Transport),
            52 => Some(CoursePoint::Alert),
            53 => Some(CoursePoint::Info),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "generic" => Some(CoursePoint::Generic),
            "summit" => Some(CoursePoint::Summit),
            "valley" => Some(CoursePoint::Valley),
            "water" => Some(CoursePoint::Water),
            "food" => Some(CoursePoint::Food),
            "danger" => Some(CoursePoint::Danger),
            "left" => Some(CoursePoint::Left),
            "right" => Some(CoursePoint::Right),
            "straight" => Some(CoursePoint::Straight),
            "first_aid" => Some(CoursePoint::FirstAid),
            "fourth_category" => Some(CoursePoint::FourthCategory),
            "third_category" => Some(CoursePoint::ThirdCategory),
            "second_category" => Some(CoursePoint::SecondCategory),
            "first_category" => Some(CoursePoint::FirstCategory),
            "hors_category" => Some(CoursePoint::HorsCategory),
            "sprint" => Some(CoursePoint::Sprint),
            "left_fork" => Some(CoursePoint::LeftFork),
            "right_fork" => Some(CoursePoint::RightFork),
            "middle_fork" => Some(CoursePoint::MiddleFork),
            "slight_left" => Some(CoursePoint::SlightLeft),
            "sharp_left" => Some(CoursePoint::SharpLeft),
            "slight_right" => Some(CoursePoint::SlightRight),
            "sharp_right" => Some(CoursePoint::SharpRight),
            "u_turn" => Some(CoursePoint::UTurn),
            "segment_start" => Some(CoursePoint::SegmentStart),
            "segment_end" => Some(CoursePoint::SegmentEnd),
            "campsite" => Some(CoursePoint::Campsite),
            "aid_station" => Some(CoursePoint::AidStation),
            "rest_area" => Some(CoursePoint::RestArea),
            "general_distance" => Some(CoursePoint::GeneralDistance),
            "service" => Some(CoursePoint::Service),
            "energy_gel" => Some(CoursePoint::EnergyGel),
            "sports_drink" => Some(CoursePoint::SportsDrink),
            "mile_marker" => Some(CoursePoint::MileMarker),
            "checkpoint" => Some(CoursePoint::Checkpoint),
            "shelter" => Some(CoursePoint::Shelter),
            "meeting_spot" => Some(CoursePoint::MeetingSpot),
            "overlook" => Some(CoursePoint::Overlook),
            "toilet" => Some(CoursePoint::Toilet),
            "shower" => Some(CoursePoint::Shower),
            "gear" => Some(CoursePoint::Gear),
            "sharp_curve" => Some(CoursePoint::SharpCurve),
            "steep_incline" => Some(CoursePoint::SteepIncline),
            "tunnel" => Some(CoursePoint::Tunnel),
            "bridge" => Some(CoursePoint::Bridge),
            "obstacle" => Some(CoursePoint::Obstacle),
            "crossing" => Some(CoursePoint::Crossing),
            "store" => Some(CoursePoint::Store),
            "transition" => Some(CoursePoint::Transition),
            "navaid" => Some(CoursePoint::Navaid),
            "transport" => Some(CoursePoint::Transport),
            "alert" => Some(CoursePoint::Alert),
            "info" => Some(CoursePoint::Info),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum Manufacturer {
    Garmin = 1,
    GarminFr405Antfs = 2,
    Zephyr = 3,
    Dayton = 4,
    Idt = 5,
    Srm = 6,
    Quarq = 7,
    Ibike = 8,
    Saris = 9,
    SparkHk = 10,
    Tanita = 11,
    Echowell = 12,
    DynastreamOem = 13,
    Nautilus = 14,
    Dynastream = 15,
    Timex = 16,
    Metrigear = 17,
    Xelic = 18,
    Beurer = 19,
    Cardiosport = 20,
    AAndD = 21,
    Hmm = 22,
    Suunto = 23,
    ThitaElektronik = 24,
    Gpulse = 25,
    CleanMobile = 26,
    PedalBrain = 27,
    Peaksware = 28,
    Saxonar = 29,
    LemondFitness = 30,
    Dexcom = 31,
    WahooFitness = 32,
    OctaneFitness = 33,
    Archinoetics = 34,
    TheHurtBox = 35,
    CitizenSystems = 36,
    Magellan = 37,
    Osynce = 38,
    Holux = 39,
    Concept2 = 40,
    Shimano = 41,
    OneGiantLeap = 42,
    AceSensor = 43,
    BrimBrothers = 44,
    Xplova = 45,
    PerceptionDigital = 46,
    Bf1systems = 47,
    Pioneer = 48,
    Spantec = 49,
    Metalogics = 50,
    _4iiiis = 51,
    SeikoEpson = 52,
    SeikoEpsonOem = 53,
    IforPowell = 54,
    MaxwellGuider = 55,
    StarTrac = 56,
    Breakaway = 57,
    AlatechTechnologyLtd = 58,
    MioTechnologyEurope = 59,
    Rotor = 60,
    Geonaute = 61,
    IdBike = 62,
    Specialized = 63,
    Wtek = 64,
    PhysicalEnterprises = 65,
    NorthPoleEngineering = 66,
    Bkool = 67,
    Cateye = 68,
    StagesCycling = 69,
    Sigmasport = 70,
    Tomtom = 71,
    Peripedal = 72,
    Wattbike = 73,
    Moxy = 76,
    Ciclosport = 77,
    Powerbahn = 78,
    AcornProjectsAps = 79,
    Lifebeam = 80,
    Bontrager = 81,
    Wellgo = 82,
    Scosche = 83,
    Magura = 84,
    Woodway = 85,
    Elite = 86,
    NielsenKellerman = 87,
    DkCity = 88,
    Tacx = 89,
    DirectionTechnology = 90,
    Magtonic = 91,
    _1partcarbon = 92,
    InsideRideTechnologies = 93,
    SoundOfMotion = 94,
    Stryd = 95,
    Icg = 96,
    MiPulse = 97,
    BsxAthletics = 98,
    Look = 99,
    CampagnoloSrl = 100,
    BodyBikeSmart = 101,
    Praxisworks = 102,
    LimitsTechnology = 103,
    TopactionTechnology = 104,
    Cosinuss = 105,
    Fitcare = 106,
    Magene = 107,
    GiantManufacturingCo = 108,
    Tigrasport = 109,
    Salutron = 110,
    Technogym = 111,
    BrytonSensors = 112,
    LatitudeLimited = 113,
    SoaringTechnology = 114,
    Igpsport = 115,
    Thinkrider = 116,
    GopherSport = 117,
    Waterrower = 118,
    Orangetheory = 119,
    Inpeak = 120,
    Kinetic = 121,
    JohnsonHealthTech = 122,
    PolarElectro = 123,
    Seesense = 124,
    NciTechnology = 125,
    Iqsquare = 126,
    Leomo = 127,
    IfitCom = 128,
    CorosByte = 129,
    VersaDesign = 130,
    Chileaf = 131,
    Cycplus = 132,
    GravaaByte = 133,
    Sigeyi = 134,
    Coospo = 135,
    Geoid = 136,
    Bosch = 137,
    Kyto = 138,
    KineticSports = 139,
    DecathlonByte = 140,
    TqSystems = 141,
    TagHeuer = 142,
    KeiserFitness = 143,
    ZwiftByte = 144,
    PorscheEp = 145,
    Blackbird = 146,
    MeilanByte = 147,
    Ezon = 148,
    Laisi = 149,
    Myzone = 150,
    Abawo = 151,
    Bafang = 152,
    LuhongTechnology = 153,
    Development = 255,
    Healthandlife = 257,
    Lezyne = 258,
    ScribeLabs = 259,
    Zwift = 260,
    Watteam = 261,
    Recon = 262,
    FaveroElectronics = 263,
    Dynovelo = 264,
    Strava = 265,
    Precor = 266,
    Bryton = 267,
    Sram = 268,
    Navman = 269,
    Cobi = 270,
    Spivi = 271,
    MioMagellan = 272,
    Evesports = 273,
    SensitivusGauge = 274,
    Podoon = 275,
    LifeTimeFitness = 276,
    FalcoEMotors = 277,
    Minoura = 278,
    Cycliq = 279,
    Luxottica = 280,
    TrainerRoad = 281,
    TheSufferfest = 282,
    Fullspeedahead = 283,
    Virtualtraining = 284,
    Feedbacksports = 285,
    Omata = 286,
    Vdo = 287,
    Magneticdays = 288,
    Hammerhead = 289,
    KineticByKurt = 290,
    Shapelog = 291,
    Dabuziduo = 292,
    Jetblack = 293,
    Coros = 294,
    Virtugo = 295,
    Velosense = 296,
    Cycligentinc = 297,
    Trailforks = 298,
    MahleEbikemotion = 299,
    Nurvv = 300,
    Microprogram = 301,
    Zone5cloud = 302,
    Greenteg = 303,
    YamahaMotors = 304,
    Whoop = 305,
    Gravaa = 306,
    Onelap = 307,
    MonarkExercise = 308,
    Form = 309,
    Decathlon = 310,
    Syncros = 311,
    Heatup = 312,
    Cannondale = 313,
    TrueFitness = 314,
    RGTCycling = 315,
    Vasa = 316,
    RaceRepublic = 317,
    Fazua = 318,
    OrekaTraining = 319,
    Lsec = 320,
    LululemonStudio = 321,
    Shanyue = 322,
    SpinningMda = 323,
    Hilldating = 324,
    AeroSensor = 325,
    Nike = 326,
    Magicshine = 327,
    Ictrainer = 328,
    AbsoluteCycling = 329,
    EoSwimbetter = 330,
    Mywhoosh = 331,
    Ravemen = 332,
    TektroRacingProducts = 333,
    DaradInnovationCorporation = 334,
    Cycloptim = 335,
    Runna = 337,
    Zepp = 339,
    Peloton = 340,
    Carv = 341,
    Tissot = 342,
    RealVelo = 345,
    Wetech = 346,
    Jespr = 347,
    Huawei = 348,
    Gotoes = 349,
    Actigraphcorp = 5759,
}

impl Manufacturer {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            Manufacturer::Garmin => "garmin",
            Manufacturer::GarminFr405Antfs => "garmin_fr405_antfs",
            Manufacturer::Zephyr => "zephyr",
            Manufacturer::Dayton => "dayton",
            Manufacturer::Idt => "idt",
            Manufacturer::Srm => "srm",
            Manufacturer::Quarq => "quarq",
            Manufacturer::Ibike => "ibike",
            Manufacturer::Saris => "saris",
            Manufacturer::SparkHk => "spark_hk",
            Manufacturer::Tanita => "tanita",
            Manufacturer::Echowell => "echowell",
            Manufacturer::DynastreamOem => "dynastream_oem",
            Manufacturer::Nautilus => "nautilus",
            Manufacturer::Dynastream => "dynastream",
            Manufacturer::Timex => "timex",
            Manufacturer::Metrigear => "metrigear",
            Manufacturer::Xelic => "xelic",
            Manufacturer::Beurer => "beurer",
            Manufacturer::Cardiosport => "cardiosport",
            Manufacturer::AAndD => "a_and_d",
            Manufacturer::Hmm => "hmm",
            Manufacturer::Suunto => "suunto",
            Manufacturer::ThitaElektronik => "thita_elektronik",
            Manufacturer::Gpulse => "gpulse",
            Manufacturer::CleanMobile => "clean_mobile",
            Manufacturer::PedalBrain => "pedal_brain",
            Manufacturer::Peaksware => "peaksware",
            Manufacturer::Saxonar => "saxonar",
            Manufacturer::LemondFitness => "lemond_fitness",
            Manufacturer::Dexcom => "dexcom",
            Manufacturer::WahooFitness => "wahoo_fitness",
            Manufacturer::OctaneFitness => "octane_fitness",
            Manufacturer::Archinoetics => "archinoetics",
            Manufacturer::TheHurtBox => "the_hurt_box",
            Manufacturer::CitizenSystems => "citizen_systems",
            Manufacturer::Magellan => "magellan",
            Manufacturer::Osynce => "osynce",
            Manufacturer::Holux => "holux",
            Manufacturer::Concept2 => "concept2",
            Manufacturer::Shimano => "shimano",
            Manufacturer::OneGiantLeap => "one_giant_leap",
            Manufacturer::AceSensor => "ace_sensor",
            Manufacturer::BrimBrothers => "brim_brothers",
            Manufacturer::Xplova => "xplova",
            Manufacturer::PerceptionDigital => "perception_digital",
            Manufacturer::Bf1systems => "bf1systems",
            Manufacturer::Pioneer => "pioneer",
            Manufacturer::Spantec => "spantec",
            Manufacturer::Metalogics => "metalogics",
            Manufacturer::_4iiiis => "4iiiis",
            Manufacturer::SeikoEpson => "seiko_epson",
            Manufacturer::SeikoEpsonOem => "seiko_epson_oem",
            Manufacturer::IforPowell => "ifor_powell",
            Manufacturer::MaxwellGuider => "maxwell_guider",
            Manufacturer::StarTrac => "star_trac",
            Manufacturer::Breakaway => "breakaway",
            Manufacturer::AlatechTechnologyLtd => "alatech_technology_ltd",
            Manufacturer::MioTechnologyEurope => "mio_technology_europe",
            Manufacturer::Rotor => "rotor",
            Manufacturer::Geonaute => "geonaute",
            Manufacturer::IdBike => "id_bike",
            Manufacturer::Specialized => "specialized",
            Manufacturer::Wtek => "wtek",
            Manufacturer::PhysicalEnterprises => "physical_enterprises",
            Manufacturer::NorthPoleEngineering => "north_pole_engineering",
            Manufacturer::Bkool => "bkool",
            Manufacturer::Cateye => "cateye",
            Manufacturer::StagesCycling => "stages_cycling",
            Manufacturer::Sigmasport => "sigmasport",
            Manufacturer::Tomtom => "tomtom",
            Manufacturer::Peripedal => "peripedal",
            Manufacturer::Wattbike => "wattbike",
            Manufacturer::Moxy => "moxy",
            Manufacturer::Ciclosport => "ciclosport",
            Manufacturer::Powerbahn => "powerbahn",
            Manufacturer::AcornProjectsAps => "acorn_projects_aps",
            Manufacturer::Lifebeam => "lifebeam",
            Manufacturer::Bontrager => "bontrager",
            Manufacturer::Wellgo => "wellgo",
            Manufacturer::Scosche => "scosche",
            Manufacturer::Magura => "magura",
            Manufacturer::Woodway => "woodway",
            Manufacturer::Elite => "elite",
            Manufacturer::NielsenKellerman => "nielsen_kellerman",
            Manufacturer::DkCity => "dk_city",
            Manufacturer::Tacx => "tacx",
            Manufacturer::DirectionTechnology => "direction_technology",
            Manufacturer::Magtonic => "magtonic",
            Manufacturer::_1partcarbon => "1partcarbon",
            Manufacturer::InsideRideTechnologies => "inside_ride_technologies",
            Manufacturer::SoundOfMotion => "sound_of_motion",
            Manufacturer::Stryd => "stryd",
            Manufacturer::Icg => "icg",
            Manufacturer::MiPulse => "MiPulse",
            Manufacturer::BsxAthletics => "bsx_athletics",
            Manufacturer::Look => "look",
            Manufacturer::CampagnoloSrl => "campagnolo_srl",
            Manufacturer::BodyBikeSmart => "body_bike_smart",
            Manufacturer::Praxisworks => "praxisworks",
            Manufacturer::LimitsTechnology => "limits_technology",
            Manufacturer::TopactionTechnology => "topaction_technology",
            Manufacturer::Cosinuss => "cosinuss",
            Manufacturer::Fitcare => "fitcare",
            Manufacturer::Magene => "magene",
            Manufacturer::GiantManufacturingCo => "giant_manufacturing_co",
            Manufacturer::Tigrasport => "tigrasport",
            Manufacturer::Salutron => "salutron",
            Manufacturer::Technogym => "technogym",
            Manufacturer::BrytonSensors => "bryton_sensors",
            Manufacturer::LatitudeLimited => "latitude_limited",
            Manufacturer::SoaringTechnology => "soaring_technology",
            Manufacturer::Igpsport => "igpsport",
            Manufacturer::Thinkrider => "thinkrider",
            Manufacturer::GopherSport => "gopher_sport",
            Manufacturer::Waterrower => "waterrower",
            Manufacturer::Orangetheory => "orangetheory",
            Manufacturer::Inpeak => "inpeak",
            Manufacturer::Kinetic => "kinetic",
            Manufacturer::JohnsonHealthTech => "johnson_health_tech",
            Manufacturer::PolarElectro => "polar_electro",
            Manufacturer::Seesense => "seesense",
            Manufacturer::NciTechnology => "nci_technology",
            Manufacturer::Iqsquare => "iqsquare",
            Manufacturer::Leomo => "leomo",
            Manufacturer::IfitCom => "ifit_com",
            Manufacturer::CorosByte => "coros_byte",
            Manufacturer::VersaDesign => "versa_design",
            Manufacturer::Chileaf => "chileaf",
            Manufacturer::Cycplus => "cycplus",
            Manufacturer::GravaaByte => "gravaa_byte",
            Manufacturer::Sigeyi => "sigeyi",
            Manufacturer::Coospo => "coospo",
            Manufacturer::Geoid => "geoid",
            Manufacturer::Bosch => "bosch",
            Manufacturer::Kyto => "kyto",
            Manufacturer::KineticSports => "kinetic_sports",
            Manufacturer::DecathlonByte => "decathlon_byte",
            Manufacturer::TqSystems => "tq_systems",
            Manufacturer::TagHeuer => "tag_heuer",
            Manufacturer::KeiserFitness => "keiser_fitness",
            Manufacturer::ZwiftByte => "zwift_byte",
            Manufacturer::PorscheEp => "porsche_ep",
            Manufacturer::Blackbird => "blackbird",
            Manufacturer::MeilanByte => "meilan_byte",
            Manufacturer::Ezon => "ezon",
            Manufacturer::Laisi => "laisi",
            Manufacturer::Myzone => "myzone",
            Manufacturer::Abawo => "abawo",
            Manufacturer::Bafang => "bafang",
            Manufacturer::LuhongTechnology => "luhong_technology",
            Manufacturer::Development => "development",
            Manufacturer::Healthandlife => "healthandlife",
            Manufacturer::Lezyne => "lezyne",
            Manufacturer::ScribeLabs => "scribe_labs",
            Manufacturer::Zwift => "zwift",
            Manufacturer::Watteam => "watteam",
            Manufacturer::Recon => "recon",
            Manufacturer::FaveroElectronics => "favero_electronics",
            Manufacturer::Dynovelo => "dynovelo",
            Manufacturer::Strava => "strava",
            Manufacturer::Precor => "precor",
            Manufacturer::Bryton => "bryton",
            Manufacturer::Sram => "sram",
            Manufacturer::Navman => "navman",
            Manufacturer::Cobi => "cobi",
            Manufacturer::Spivi => "spivi",
            Manufacturer::MioMagellan => "mio_magellan",
            Manufacturer::Evesports => "evesports",
            Manufacturer::SensitivusGauge => "sensitivus_gauge",
            Manufacturer::Podoon => "podoon",
            Manufacturer::LifeTimeFitness => "life_time_fitness",
            Manufacturer::FalcoEMotors => "falco_e_motors",
            Manufacturer::Minoura => "minoura",
            Manufacturer::Cycliq => "cycliq",
            Manufacturer::Luxottica => "luxottica",
            Manufacturer::TrainerRoad => "trainer_road",
            Manufacturer::TheSufferfest => "the_sufferfest",
            Manufacturer::Fullspeedahead => "fullspeedahead",
            Manufacturer::Virtualtraining => "virtualtraining",
            Manufacturer::Feedbacksports => "feedbacksports",
            Manufacturer::Omata => "omata",
            Manufacturer::Vdo => "vdo",
            Manufacturer::Magneticdays => "magneticdays",
            Manufacturer::Hammerhead => "hammerhead",
            Manufacturer::KineticByKurt => "kinetic_by_kurt",
            Manufacturer::Shapelog => "shapelog",
            Manufacturer::Dabuziduo => "dabuziduo",
            Manufacturer::Jetblack => "jetblack",
            Manufacturer::Coros => "coros",
            Manufacturer::Virtugo => "virtugo",
            Manufacturer::Velosense => "velosense",
            Manufacturer::Cycligentinc => "cycligentinc",
            Manufacturer::Trailforks => "trailforks",
            Manufacturer::MahleEbikemotion => "mahle_ebikemotion",
            Manufacturer::Nurvv => "nurvv",
            Manufacturer::Microprogram => "microprogram",
            Manufacturer::Zone5cloud => "zone5cloud",
            Manufacturer::Greenteg => "greenteg",
            Manufacturer::YamahaMotors => "yamaha_motors",
            Manufacturer::Whoop => "whoop",
            Manufacturer::Gravaa => "gravaa",
            Manufacturer::Onelap => "onelap",
            Manufacturer::MonarkExercise => "monark_exercise",
            Manufacturer::Form => "form",
            Manufacturer::Decathlon => "decathlon",
            Manufacturer::Syncros => "syncros",
            Manufacturer::Heatup => "heatup",
            Manufacturer::Cannondale => "cannondale",
            Manufacturer::TrueFitness => "true_fitness",
            Manufacturer::RGTCycling => "RGT_cycling",
            Manufacturer::Vasa => "vasa",
            Manufacturer::RaceRepublic => "race_republic",
            Manufacturer::Fazua => "fazua",
            Manufacturer::OrekaTraining => "oreka_training",
            Manufacturer::Lsec => "lsec",
            Manufacturer::LululemonStudio => "lululemon_studio",
            Manufacturer::Shanyue => "shanyue",
            Manufacturer::SpinningMda => "spinning_mda",
            Manufacturer::Hilldating => "hilldating",
            Manufacturer::AeroSensor => "aero_sensor",
            Manufacturer::Nike => "nike",
            Manufacturer::Magicshine => "magicshine",
            Manufacturer::Ictrainer => "ictrainer",
            Manufacturer::AbsoluteCycling => "absolute_cycling",
            Manufacturer::EoSwimbetter => "eo_swimbetter",
            Manufacturer::Mywhoosh => "mywhoosh",
            Manufacturer::Ravemen => "ravemen",
            Manufacturer::TektroRacingProducts => "tektro_racing_products",
            Manufacturer::DaradInnovationCorporation => "darad_innovation_corporation",
            Manufacturer::Cycloptim => "cycloptim",
            Manufacturer::Runna => "runna",
            Manufacturer::Zepp => "zepp",
            Manufacturer::Peloton => "peloton",
            Manufacturer::Carv => "carv",
            Manufacturer::Tissot => "tissot",
            Manufacturer::RealVelo => "real_velo",
            Manufacturer::Wetech => "wetech",
            Manufacturer::Jespr => "jespr",
            Manufacturer::Huawei => "huawei",
            Manufacturer::Gotoes => "gotoes",
            Manufacturer::Actigraphcorp => "actigraphcorp",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            1 => Some(Manufacturer::Garmin),
            2 => Some(Manufacturer::GarminFr405Antfs),
            3 => Some(Manufacturer::Zephyr),
            4 => Some(Manufacturer::Dayton),
            5 => Some(Manufacturer::Idt),
            6 => Some(Manufacturer::Srm),
            7 => Some(Manufacturer::Quarq),
            8 => Some(Manufacturer::Ibike),
            9 => Some(Manufacturer::Saris),
            10 => Some(Manufacturer::SparkHk),
            11 => Some(Manufacturer::Tanita),
            12 => Some(Manufacturer::Echowell),
            13 => Some(Manufacturer::DynastreamOem),
            14 => Some(Manufacturer::Nautilus),
            15 => Some(Manufacturer::Dynastream),
            16 => Some(Manufacturer::Timex),
            17 => Some(Manufacturer::Metrigear),
            18 => Some(Manufacturer::Xelic),
            19 => Some(Manufacturer::Beurer),
            20 => Some(Manufacturer::Cardiosport),
            21 => Some(Manufacturer::AAndD),
            22 => Some(Manufacturer::Hmm),
            23 => Some(Manufacturer::Suunto),
            24 => Some(Manufacturer::ThitaElektronik),
            25 => Some(Manufacturer::Gpulse),
            26 => Some(Manufacturer::CleanMobile),
            27 => Some(Manufacturer::PedalBrain),
            28 => Some(Manufacturer::Peaksware),
            29 => Some(Manufacturer::Saxonar),
            30 => Some(Manufacturer::LemondFitness),
            31 => Some(Manufacturer::Dexcom),
            32 => Some(Manufacturer::WahooFitness),
            33 => Some(Manufacturer::OctaneFitness),
            34 => Some(Manufacturer::Archinoetics),
            35 => Some(Manufacturer::TheHurtBox),
            36 => Some(Manufacturer::CitizenSystems),
            37 => Some(Manufacturer::Magellan),
            38 => Some(Manufacturer::Osynce),
            39 => Some(Manufacturer::Holux),
            40 => Some(Manufacturer::Concept2),
            41 => Some(Manufacturer::Shimano),
            42 => Some(Manufacturer::OneGiantLeap),
            43 => Some(Manufacturer::AceSensor),
            44 => Some(Manufacturer::BrimBrothers),
            45 => Some(Manufacturer::Xplova),
            46 => Some(Manufacturer::PerceptionDigital),
            47 => Some(Manufacturer::Bf1systems),
            48 => Some(Manufacturer::Pioneer),
            49 => Some(Manufacturer::Spantec),
            50 => Some(Manufacturer::Metalogics),
            51 => Some(Manufacturer::_4iiiis),
            52 => Some(Manufacturer::SeikoEpson),
            53 => Some(Manufacturer::SeikoEpsonOem),
            54 => Some(Manufacturer::IforPowell),
            55 => Some(Manufacturer::MaxwellGuider),
            56 => Some(Manufacturer::StarTrac),
            57 => Some(Manufacturer::Breakaway),
            58 => Some(Manufacturer::AlatechTechnologyLtd),
            59 => Some(Manufacturer::MioTechnologyEurope),
            60 => Some(Manufacturer::Rotor),
            61 => Some(Manufacturer::Geonaute),
            62 => Some(Manufacturer::IdBike),
            63 => Some(Manufacturer::Specialized),
            64 => Some(Manufacturer::Wtek),
            65 => Some(Manufacturer::PhysicalEnterprises),
            66 => Some(Manufacturer::NorthPoleEngineering),
            67 => Some(Manufacturer::Bkool),
            68 => Some(Manufacturer::Cateye),
            69 => Some(Manufacturer::StagesCycling),
            70 => Some(Manufacturer::Sigmasport),
            71 => Some(Manufacturer::Tomtom),
            72 => Some(Manufacturer::Peripedal),
            73 => Some(Manufacturer::Wattbike),
            76 => Some(Manufacturer::Moxy),
            77 => Some(Manufacturer::Ciclosport),
            78 => Some(Manufacturer::Powerbahn),
            79 => Some(Manufacturer::AcornProjectsAps),
            80 => Some(Manufacturer::Lifebeam),
            81 => Some(Manufacturer::Bontrager),
            82 => Some(Manufacturer::Wellgo),
            83 => Some(Manufacturer::Scosche),
            84 => Some(Manufacturer::Magura),
            85 => Some(Manufacturer::Woodway),
            86 => Some(Manufacturer::Elite),
            87 => Some(Manufacturer::NielsenKellerman),
            88 => Some(Manufacturer::DkCity),
            89 => Some(Manufacturer::Tacx),
            90 => Some(Manufacturer::DirectionTechnology),
            91 => Some(Manufacturer::Magtonic),
            92 => Some(Manufacturer::_1partcarbon),
            93 => Some(Manufacturer::InsideRideTechnologies),
            94 => Some(Manufacturer::SoundOfMotion),
            95 => Some(Manufacturer::Stryd),
            96 => Some(Manufacturer::Icg),
            97 => Some(Manufacturer::MiPulse),
            98 => Some(Manufacturer::BsxAthletics),
            99 => Some(Manufacturer::Look),
            100 => Some(Manufacturer::CampagnoloSrl),
            101 => Some(Manufacturer::BodyBikeSmart),
            102 => Some(Manufacturer::Praxisworks),
            103 => Some(Manufacturer::LimitsTechnology),
            104 => Some(Manufacturer::TopactionTechnology),
            105 => Some(Manufacturer::Cosinuss),
            106 => Some(Manufacturer::Fitcare),
            107 => Some(Manufacturer::Magene),
            108 => Some(Manufacturer::GiantManufacturingCo),
            109 => Some(Manufacturer::Tigrasport),
            110 => Some(Manufacturer::Salutron),
            111 => Some(Manufacturer::Technogym),
            112 => Some(Manufacturer::BrytonSensors),
            113 => Some(Manufacturer::LatitudeLimited),
            114 => Some(Manufacturer::SoaringTechnology),
            115 => Some(Manufacturer::Igpsport),
            116 => Some(Manufacturer::Thinkrider),
            117 => Some(Manufacturer::GopherSport),
            118 => Some(Manufacturer::Waterrower),
            119 => Some(Manufacturer::Orangetheory),
            120 => Some(Manufacturer::Inpeak),
            121 => Some(Manufacturer::Kinetic),
            122 => Some(Manufacturer::JohnsonHealthTech),
            123 => Some(Manufacturer::PolarElectro),
            124 => Some(Manufacturer::Seesense),
            125 => Some(Manufacturer::NciTechnology),
            126 => Some(Manufacturer::Iqsquare),
            127 => Some(Manufacturer::Leomo),
            128 => Some(Manufacturer::IfitCom),
            129 => Some(Manufacturer::CorosByte),
            130 => Some(Manufacturer::VersaDesign),
            131 => Some(Manufacturer::Chileaf),
            132 => Some(Manufacturer::Cycplus),
            133 => Some(Manufacturer::GravaaByte),
            134 => Some(Manufacturer::Sigeyi),
            135 => Some(Manufacturer::Coospo),
            136 => Some(Manufacturer::Geoid),
            137 => Some(Manufacturer::Bosch),
            138 => Some(Manufacturer::Kyto),
            139 => Some(Manufacturer::KineticSports),
            140 => Some(Manufacturer::DecathlonByte),
            141 => Some(Manufacturer::TqSystems),
            142 => Some(Manufacturer::TagHeuer),
            143 => Some(Manufacturer::KeiserFitness),
            144 => Some(Manufacturer::ZwiftByte),
            145 => Some(Manufacturer::PorscheEp),
            146 => Some(Manufacturer::Blackbird),
            147 => Some(Manufacturer::MeilanByte),
            148 => Some(Manufacturer::Ezon),
            149 => Some(Manufacturer::Laisi),
            150 => Some(Manufacturer::Myzone),
            151 => Some(Manufacturer::Abawo),
            152 => Some(Manufacturer::Bafang),
            153 => Some(Manufacturer::LuhongTechnology),
            255 => Some(Manufacturer::Development),
            257 => Some(Manufacturer::Healthandlife),
            258 => Some(Manufacturer::Lezyne),
            259 => Some(Manufacturer::ScribeLabs),
            260 => Some(Manufacturer::Zwift),
            261 => Some(Manufacturer::Watteam),
            262 => Some(Manufacturer::Recon),
            263 => Some(Manufacturer::FaveroElectronics),
            264 => Some(Manufacturer::Dynovelo),
            265 => Some(Manufacturer::Strava),
            266 => Some(Manufacturer::Precor),
            267 => Some(Manufacturer::Bryton),
            268 => Some(Manufacturer::Sram),
            269 => Some(Manufacturer::Navman),
            270 => Some(Manufacturer::Cobi),
            271 => Some(Manufacturer::Spivi),
            272 => Some(Manufacturer::MioMagellan),
            273 => Some(Manufacturer::Evesports),
            274 => Some(Manufacturer::SensitivusGauge),
            275 => Some(Manufacturer::Podoon),
            276 => Some(Manufacturer::LifeTimeFitness),
            277 => Some(Manufacturer::FalcoEMotors),
            278 => Some(Manufacturer::Minoura),
            279 => Some(Manufacturer::Cycliq),
            280 => Some(Manufacturer::Luxottica),
            281 => Some(Manufacturer::TrainerRoad),
            282 => Some(Manufacturer::TheSufferfest),
            283 => Some(Manufacturer::Fullspeedahead),
            284 => Some(Manufacturer::Virtualtraining),
            285 => Some(Manufacturer::Feedbacksports),
            286 => Some(Manufacturer::Omata),
            287 => Some(Manufacturer::Vdo),
            288 => Some(Manufacturer::Magneticdays),
            289 => Some(Manufacturer::Hammerhead),
            290 => Some(Manufacturer::KineticByKurt),
            291 => Some(Manufacturer::Shapelog),
            292 => Some(Manufacturer::Dabuziduo),
            293 => Some(Manufacturer::Jetblack),
            294 => Some(Manufacturer::Coros),
            295 => Some(Manufacturer::Virtugo),
            296 => Some(Manufacturer::Velosense),
            297 => Some(Manufacturer::Cycligentinc),
            298 => Some(Manufacturer::Trailforks),
            299 => Some(Manufacturer::MahleEbikemotion),
            300 => Some(Manufacturer::Nurvv),
            301 => Some(Manufacturer::Microprogram),
            302 => Some(Manufacturer::Zone5cloud),
            303 => Some(Manufacturer::Greenteg),
            304 => Some(Manufacturer::YamahaMotors),
            305 => Some(Manufacturer::Whoop),
            306 => Some(Manufacturer::Gravaa),
            307 => Some(Manufacturer::Onelap),
            308 => Some(Manufacturer::MonarkExercise),
            309 => Some(Manufacturer::Form),
            310 => Some(Manufacturer::Decathlon),
            311 => Some(Manufacturer::Syncros),
            312 => Some(Manufacturer::Heatup),
            313 => Some(Manufacturer::Cannondale),
            314 => Some(Manufacturer::TrueFitness),
            315 => Some(Manufacturer::RGTCycling),
            316 => Some(Manufacturer::Vasa),
            317 => Some(Manufacturer::RaceRepublic),
            318 => Some(Manufacturer::Fazua),
            319 => Some(Manufacturer::OrekaTraining),
            320 => Some(Manufacturer::Lsec),
            321 => Some(Manufacturer::LululemonStudio),
            322 => Some(Manufacturer::Shanyue),
            323 => Some(Manufacturer::SpinningMda),
            324 => Some(Manufacturer::Hilldating),
            325 => Some(Manufacturer::AeroSensor),
            326 => Some(Manufacturer::Nike),
            327 => Some(Manufacturer::Magicshine),
            328 => Some(Manufacturer::Ictrainer),
            329 => Some(Manufacturer::AbsoluteCycling),
            330 => Some(Manufacturer::EoSwimbetter),
            331 => Some(Manufacturer::Mywhoosh),
            332 => Some(Manufacturer::Ravemen),
            333 => Some(Manufacturer::TektroRacingProducts),
            334 => Some(Manufacturer::DaradInnovationCorporation),
            335 => Some(Manufacturer::Cycloptim),
            337 => Some(Manufacturer::Runna),
            339 => Some(Manufacturer::Zepp),
            340 => Some(Manufacturer::Peloton),
            341 => Some(Manufacturer::Carv),
            342 => Some(Manufacturer::Tissot),
            345 => Some(Manufacturer::RealVelo),
            346 => Some(Manufacturer::Wetech),
            347 => Some(Manufacturer::Jespr),
            348 => Some(Manufacturer::Huawei),
            349 => Some(Manufacturer::Gotoes),
            5759 => Some(Manufacturer::Actigraphcorp),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "garmin" => Some(Manufacturer::Garmin),
            "garmin_fr405_antfs" => Some(Manufacturer::GarminFr405Antfs),
            "zephyr" => Some(Manufacturer::Zephyr),
            "dayton" => Some(Manufacturer::Dayton),
            "idt" => Some(Manufacturer::Idt),
            "srm" => Some(Manufacturer::Srm),
            "quarq" => Some(Manufacturer::Quarq),
            "ibike" => Some(Manufacturer::Ibike),
            "saris" => Some(Manufacturer::Saris),
            "spark_hk" => Some(Manufacturer::SparkHk),
            "tanita" => Some(Manufacturer::Tanita),
            "echowell" => Some(Manufacturer::Echowell),
            "dynastream_oem" => Some(Manufacturer::DynastreamOem),
            "nautilus" => Some(Manufacturer::Nautilus),
            "dynastream" => Some(Manufacturer::Dynastream),
            "timex" => Some(Manufacturer::Timex),
            "metrigear" => Some(Manufacturer::Metrigear),
            "xelic" => Some(Manufacturer::Xelic),
            "beurer" => Some(Manufacturer::Beurer),
            "cardiosport" => Some(Manufacturer::Cardiosport),
            "a_and_d" => Some(Manufacturer::AAndD),
            "hmm" => Some(Manufacturer::Hmm),
            "suunto" => Some(Manufacturer::Suunto),
            "thita_elektronik" => Some(Manufacturer::ThitaElektronik),
            "gpulse" => Some(Manufacturer::Gpulse),
            "clean_mobile" => Some(Manufacturer::CleanMobile),
            "pedal_brain" => Some(Manufacturer::PedalBrain),
            "peaksware" => Some(Manufacturer::Peaksware),
            "saxonar" => Some(Manufacturer::Saxonar),
            "lemond_fitness" => Some(Manufacturer::LemondFitness),
            "dexcom" => Some(Manufacturer::Dexcom),
            "wahoo_fitness" => Some(Manufacturer::WahooFitness),
            "octane_fitness" => Some(Manufacturer::OctaneFitness),
            "archinoetics" => Some(Manufacturer::Archinoetics),
            "the_hurt_box" => Some(Manufacturer::TheHurtBox),
            "citizen_systems" => Some(Manufacturer::CitizenSystems),
            "magellan" => Some(Manufacturer::Magellan),
            "osynce" => Some(Manufacturer::Osynce),
            "holux" => Some(Manufacturer::Holux),
            "concept2" => Some(Manufacturer::Concept2),
            "shimano" => Some(Manufacturer::Shimano),
            "one_giant_leap" => Some(Manufacturer::OneGiantLeap),
            "ace_sensor" => Some(Manufacturer::AceSensor),
            "brim_brothers" => Some(Manufacturer::BrimBrothers),
            "xplova" => Some(Manufacturer::Xplova),
            "perception_digital" => Some(Manufacturer::PerceptionDigital),
            "bf1systems" => Some(Manufacturer::Bf1systems),
            "pioneer" => Some(Manufacturer::Pioneer),
            "spantec" => Some(Manufacturer::Spantec),
            "metalogics" => Some(Manufacturer::Metalogics),
            "4iiiis" => Some(Manufacturer::_4iiiis),
            "seiko_epson" => Some(Manufacturer::SeikoEpson),
            "seiko_epson_oem" => Some(Manufacturer::SeikoEpsonOem),
            "ifor_powell" => Some(Manufacturer::IforPowell),
            "maxwell_guider" => Some(Manufacturer::MaxwellGuider),
            "star_trac" => Some(Manufacturer::StarTrac),
            "breakaway" => Some(Manufacturer::Breakaway),
            "alatech_technology_ltd" => Some(Manufacturer::AlatechTechnologyLtd),
            "mio_technology_europe" => Some(Manufacturer::MioTechnologyEurope),
            "rotor" => Some(Manufacturer::Rotor),
            "geonaute" => Some(Manufacturer::Geonaute),
            "id_bike" => Some(Manufacturer::IdBike),
            "specialized" => Some(Manufacturer::Specialized),
            "wtek" => Some(Manufacturer::Wtek),
            "physical_enterprises" => Some(Manufacturer::PhysicalEnterprises),
            "north_pole_engineering" => Some(Manufacturer::NorthPoleEngineering),
            "bkool" => Some(Manufacturer::Bkool),
            "cateye" => Some(Manufacturer::Cateye),
            "stages_cycling" => Some(Manufacturer::StagesCycling),
            "sigmasport" => Some(Manufacturer::Sigmasport),
            "tomtom" => Some(Manufacturer::Tomtom),
            "peripedal" => Some(Manufacturer::Peripedal),
            "wattbike" => Some(Manufacturer::Wattbike),
            "moxy" => Some(Manufacturer::Moxy),
            "ciclosport" => Some(Manufacturer::Ciclosport),
            "powerbahn" => Some(Manufacturer::Powerbahn),
            "acorn_projects_aps" => Some(Manufacturer::AcornProjectsAps),
            "lifebeam" => Some(Manufacturer::Lifebeam),
            "bontrager" => Some(Manufacturer::Bontrager),
            "wellgo" => Some(Manufacturer::Wellgo),
            "scosche" => Some(Manufacturer::Scosche),
            "magura" => Some(Manufacturer::Magura),
            "woodway" => Some(Manufacturer::Woodway),
            "elite" => Some(Manufacturer::Elite),
            "nielsen_kellerman" => Some(Manufacturer::NielsenKellerman),
            "dk_city" => Some(Manufacturer::DkCity),
            "tacx" => Some(Manufacturer::Tacx),
            "direction_technology" => Some(Manufacturer::DirectionTechnology),
            "magtonic" => Some(Manufacturer::Magtonic),
            "1partcarbon" => Some(Manufacturer::_1partcarbon),
            "inside_ride_technologies" => Some(Manufacturer::InsideRideTechnologies),
            "sound_of_motion" => Some(Manufacturer::SoundOfMotion),
            "stryd" => Some(Manufacturer::Stryd),
            "icg" => Some(Manufacturer::Icg),
            "MiPulse" => Some(Manufacturer::MiPulse),
            "bsx_athletics" => Some(Manufacturer::BsxAthletics),
            "look" => Some(Manufacturer::Look),
            "campagnolo_srl" => Some(Manufacturer::CampagnoloSrl),
            "body_bike_smart" => Some(Manufacturer::BodyBikeSmart),
            "praxisworks" => Some(Manufacturer::Praxisworks),
            "limits_technology" => Some(Manufacturer::LimitsTechnology),
            "topaction_technology" => Some(Manufacturer::TopactionTechnology),
            "cosinuss" => Some(Manufacturer::Cosinuss),
            "fitcare" => Some(Manufacturer::Fitcare),
            "magene" => Some(Manufacturer::Magene),
            "giant_manufacturing_co" => Some(Manufacturer::GiantManufacturingCo),
            "tigrasport" => Some(Manufacturer::Tigrasport),
            "salutron" => Some(Manufacturer::Salutron),
            "technogym" => Some(Manufacturer::Technogym),
            "bryton_sensors" => Some(Manufacturer::BrytonSensors),
            "latitude_limited" => Some(Manufacturer::LatitudeLimited),
            "soaring_technology" => Some(Manufacturer::SoaringTechnology),
            "igpsport" => Some(Manufacturer::Igpsport),
            "thinkrider" => Some(Manufacturer::Thinkrider),
            "gopher_sport" => Some(Manufacturer::GopherSport),
            "waterrower" => Some(Manufacturer::Waterrower),
            "orangetheory" => Some(Manufacturer::Orangetheory),
            "inpeak" => Some(Manufacturer::Inpeak),
            "kinetic" => Some(Manufacturer::Kinetic),
            "johnson_health_tech" => Some(Manufacturer::JohnsonHealthTech),
            "polar_electro" => Some(Manufacturer::PolarElectro),
            "seesense" => Some(Manufacturer::Seesense),
            "nci_technology" => Some(Manufacturer::NciTechnology),
            "iqsquare" => Some(Manufacturer::Iqsquare),
            "leomo" => Some(Manufacturer::Leomo),
            "ifit_com" => Some(Manufacturer::IfitCom),
            "coros_byte" => Some(Manufacturer::CorosByte),
            "versa_design" => Some(Manufacturer::VersaDesign),
            "chileaf" => Some(Manufacturer::Chileaf),
            "cycplus" => Some(Manufacturer::Cycplus),
            "gravaa_byte" => Some(Manufacturer::GravaaByte),
            "sigeyi" => Some(Manufacturer::Sigeyi),
            "coospo" => Some(Manufacturer::Coospo),
            "geoid" => Some(Manufacturer::Geoid),
            "bosch" => Some(Manufacturer::Bosch),
            "kyto" => Some(Manufacturer::Kyto),
            "kinetic_sports" => Some(Manufacturer::KineticSports),
            "decathlon_byte" => Some(Manufacturer::DecathlonByte),
            "tq_systems" => Some(Manufacturer::TqSystems),
            "tag_heuer" => Some(Manufacturer::TagHeuer),
            "keiser_fitness" => Some(Manufacturer::KeiserFitness),
            "zwift_byte" => Some(Manufacturer::ZwiftByte),
            "porsche_ep" => Some(Manufacturer::PorscheEp),
            "blackbird" => Some(Manufacturer::Blackbird),
            "meilan_byte" => Some(Manufacturer::MeilanByte),
            "ezon" => Some(Manufacturer::Ezon),
            "laisi" => Some(Manufacturer::Laisi),
            "myzone" => Some(Manufacturer::Myzone),
            "abawo" => Some(Manufacturer::Abawo),
            "bafang" => Some(Manufacturer::Bafang),
            "luhong_technology" => Some(Manufacturer::LuhongTechnology),
            "development" => Some(Manufacturer::Development),
            "healthandlife" => Some(Manufacturer::Healthandlife),
            "lezyne" => Some(Manufacturer::Lezyne),
            "scribe_labs" => Some(Manufacturer::ScribeLabs),
            "zwift" => Some(Manufacturer::Zwift),
            "watteam" => Some(Manufacturer::Watteam),
            "recon" => Some(Manufacturer::Recon),
            "favero_electronics" => Some(Manufacturer::FaveroElectronics),
            "dynovelo" => Some(Manufacturer::Dynovelo),
            "strava" => Some(Manufacturer::Strava),
            "precor" => Some(Manufacturer::Precor),
            "bryton" => Some(Manufacturer::Bryton),
            "sram" => Some(Manufacturer::Sram),
            "navman" => Some(Manufacturer::Navman),
            "cobi" => Some(Manufacturer::Cobi),
            "spivi" => Some(Manufacturer::Spivi),
            "mio_magellan" => Some(Manufacturer::MioMagellan),
            "evesports" => Some(Manufacturer::Evesports),
            "sensitivus_gauge" => Some(Manufacturer::SensitivusGauge),
            "podoon" => Some(Manufacturer::Podoon),
            "life_time_fitness" => Some(Manufacturer::LifeTimeFitness),
            "falco_e_motors" => Some(Manufacturer::FalcoEMotors),
            "minoura" => Some(Manufacturer::Minoura),
            "cycliq" => Some(Manufacturer::Cycliq),
            "luxottica" => Some(Manufacturer::Luxottica),
            "trainer_road" => Some(Manufacturer::TrainerRoad),
            "the_sufferfest" => Some(Manufacturer::TheSufferfest),
            "fullspeedahead" => Some(Manufacturer::Fullspeedahead),
            "virtualtraining" => Some(Manufacturer::Virtualtraining),
            "feedbacksports" => Some(Manufacturer::Feedbacksports),
            "omata" => Some(Manufacturer::Omata),
            "vdo" => Some(Manufacturer::Vdo),
            "magneticdays" => Some(Manufacturer::Magneticdays),
            "hammerhead" => Some(Manufacturer::Hammerhead),
            "kinetic_by_kurt" => Some(Manufacturer::KineticByKurt),
            "shapelog" => Some(Manufacturer::Shapelog),
            "dabuziduo" => Some(Manufacturer::Dabuziduo),
            "jetblack" => Some(Manufacturer::Jetblack),
            "coros" => Some(Manufacturer::Coros),
            "virtugo" => Some(Manufacturer::Virtugo),
            "velosense" => Some(Manufacturer::Velosense),
            "cycligentinc" => Some(Manufacturer::Cycligentinc),
            "trailforks" => Some(Manufacturer::Trailforks),
            "mahle_ebikemotion" => Some(Manufacturer::MahleEbikemotion),
            "nurvv" => Some(Manufacturer::Nurvv),
            "microprogram" => Some(Manufacturer::Microprogram),
            "zone5cloud" => Some(Manufacturer::Zone5cloud),
            "greenteg" => Some(Manufacturer::Greenteg),
            "yamaha_motors" => Some(Manufacturer::YamahaMotors),
            "whoop" => Some(Manufacturer::Whoop),
            "gravaa" => Some(Manufacturer::Gravaa),
            "onelap" => Some(Manufacturer::Onelap),
            "monark_exercise" => Some(Manufacturer::MonarkExercise),
            "form" => Some(Manufacturer::Form),
            "decathlon" => Some(Manufacturer::Decathlon),
            "syncros" => Some(Manufacturer::Syncros),
            "heatup" => Some(Manufacturer::Heatup),
            "cannondale" => Some(Manufacturer::Cannondale),
            "true_fitness" => Some(Manufacturer::TrueFitness),
            "RGT_cycling" => Some(Manufacturer::RGTCycling),
            "vasa" => Some(Manufacturer::Vasa),
            "race_republic" => Some(Manufacturer::RaceRepublic),
            "fazua" => Some(Manufacturer::Fazua),
            "oreka_training" => Some(Manufacturer::OrekaTraining),
            "lsec" => Some(Manufacturer::Lsec),
            "lululemon_studio" => Some(Manufacturer::LululemonStudio),
            "shanyue" => Some(Manufacturer::Shanyue),
            "spinning_mda" => Some(Manufacturer::SpinningMda),
            "hilldating" => Some(Manufacturer::Hilldating),
            "aero_sensor" => Some(Manufacturer::AeroSensor),
            "nike" => Some(Manufacturer::Nike),
            "magicshine" => Some(Manufacturer::Magicshine),
            "ictrainer" => Some(Manufacturer::Ictrainer),
            "absolute_cycling" => Some(Manufacturer::AbsoluteCycling),
            "eo_swimbetter" => Some(Manufacturer::EoSwimbetter),
            "mywhoosh" => Some(Manufacturer::Mywhoosh),
            "ravemen" => Some(Manufacturer::Ravemen),
            "tektro_racing_products" => Some(Manufacturer::TektroRacingProducts),
            "darad_innovation_corporation" => Some(Manufacturer::DaradInnovationCorporation),
            "cycloptim" => Some(Manufacturer::Cycloptim),
            "runna" => Some(Manufacturer::Runna),
            "zepp" => Some(Manufacturer::Zepp),
            "peloton" => Some(Manufacturer::Peloton),
            "carv" => Some(Manufacturer::Carv),
            "tissot" => Some(Manufacturer::Tissot),
            "real_velo" => Some(Manufacturer::RealVelo),
            "wetech" => Some(Manufacturer::Wetech),
            "jespr" => Some(Manufacturer::Jespr),
            "huawei" => Some(Manufacturer::Huawei),
            "gotoes" => Some(Manufacturer::Gotoes),
            "actigraphcorp" => Some(Manufacturer::Actigraphcorp),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum GarminProduct {
    Hrm1 = 1,
    Axh01 = 2,
    Axb01 = 3,
    Axb02 = 4,
    Hrm2ss = 5,
    DsiAlf02 = 6,
    Hrm3ss = 7,
    HrmRunSingleByteProductId = 8,
    Bsm = 9,
    Bcm = 10,
    Axs01 = 11,
    HrmTriSingleByteProductId = 12,
    Hrm4RunSingleByteProductId = 13,
    Fr225SingleByteProductId = 14,
    Gen3BsmSingleByteProductId = 15,
    Gen3BcmSingleByteProductId = 16,
    HrmFitSingleByteProductId = 22,
    OHR = 255,
    Fr301China = 473,
    Fr301Japan = 474,
    Fr301Korea = 475,
    Fr301Taiwan = 494,
    Fr405 = 717,
    Fr50 = 782,
    Fr405Japan = 987,
    Fr60 = 988,
    DsiAlf01 = 1011,
    Fr310xt = 1018,
    Edge500 = 1036,
    Fr110 = 1124,
    Edge800 = 1169,
    Edge500Taiwan = 1199,
    Edge500Japan = 1213,
    Chirp = 1253,
    Fr110Japan = 1274,
    Edge200 = 1325,
    Fr910xt = 1328,
    Edge800Taiwan = 1333,
    Edge800Japan = 1334,
    Alf04 = 1341,
    Fr610 = 1345,
    Fr210Japan = 1360,
    VectorSs = 1380,
    VectorCp = 1381,
    Edge800China = 1386,
    Edge500China = 1387,
    ApproachG10 = 1405,
    Fr610Japan = 1410,
    Edge500Korea = 1422,
    Fr70 = 1436,
    Fr310xt4t = 1446,
    Amx = 1461,
    Fr10 = 1482,
    Edge800Korea = 1497,
    Swim = 1499,
    Fr910xtChina = 1537,
    Fenix = 1551,
    Edge200Taiwan = 1555,
    Edge510 = 1561,
    Edge810 = 1567,
    Tempe = 1570,
    Fr910xtJapan = 1600,
    Fr620 = 1623,
    Fr220 = 1632,
    Fr910xtKorea = 1664,
    Fr10Japan = 1688,
    Edge810Japan = 1721,
    VirbElite = 1735,
    EdgeTouring = 1736,
    Edge510Japan = 1742,
    HrmTri = 1743,
    HrmRun = 1752,
    Fr920xt = 1765,
    Edge510Asia = 1821,
    Edge810China = 1822,
    Edge810Taiwan = 1823,
    Edge1000 = 1836,
    VivoFit = 1837,
    VirbRemote = 1853,
    VivoKi = 1885,
    Fr15 = 1903,
    VivoActive = 1907,
    Edge510Korea = 1918,
    Fr620Japan = 1928,
    Fr620China = 1929,
    Fr220Japan = 1930,
    Fr220China = 1931,
    ApproachS6 = 1936,
    VivoSmart = 1956,
    Fenix2 = 1967,
    Epix = 1988,
    Fenix3 = 2050,
    Edge1000Taiwan = 2052,
    Edge1000Japan = 2053,
    Fr15Japan = 2061,
    Edge520 = 2067,
    Edge1000China = 2070,
    Fr620Russia = 2072,
    Fr220Russia = 2073,
    VectorS = 2079,
    Edge1000Korea = 2100,
    Fr920xtTaiwan = 2130,
    Fr920xtChina = 2131,
    Fr920xtJapan = 2132,
    Virbx = 2134,
    VivoSmartApac = 2135,
    EtrexTouch = 2140,
    Edge25 = 2147,
    Fr25 = 2148,
    VivoFit2 = 2150,
    Fr225 = 2153,
    Fr630 = 2156,
    Fr230 = 2157,
    Fr735xt = 2158,
    VivoActiveApac = 2160,
    Vector2 = 2161,
    Vector2s = 2162,
    Virbxe = 2172,
    Fr620Taiwan = 2173,
    Fr220Taiwan = 2174,
    Truswing = 2175,
    D2airvenu = 2187,
    Fenix3China = 2188,
    Fenix3Twn = 2189,
    VariaHeadlight = 2192,
    VariaTaillightOld = 2193,
    EdgeExplore1000 = 2204,
    Fr225Asia = 2219,
    VariaRadarTaillight = 2225,
    VariaRadarDisplay = 2226,
    Edge20 = 2238,
    Edge520Asia = 2260,
    Edge520Japan = 2261,
    D2Bravo = 2262,
    ApproachS20 = 2266,
    VivoSmart2 = 2271,
    Edge1000Thai = 2274,
    VariaRemote = 2276,
    Edge25Asia = 2288,
    Edge25Jpn = 2289,
    Edge20Asia = 2290,
    ApproachX40 = 2292,
    Fenix3Japan = 2293,
    VivoSmartEmea = 2294,
    Fr630Asia = 2310,
    Fr630Jpn = 2311,
    Fr230Jpn = 2313,
    Hrm4Run = 2327,
    EpixJapan = 2332,
    VivoActiveHr = 2337,
    VivoSmartGpsHr = 2347,
    VivoSmartHr = 2348,
    VivoSmartHrAsia = 2361,
    VivoSmartGpsHrAsia = 2362,
    VivoMove = 2368,
    VariaTaillight = 2379,
    Fr235Asia = 2396,
    Fr235Japan = 2397,
    VariaVision = 2398,
    VivoFit3 = 2406,
    Fenix3Korea = 2407,
    Fenix3Sea = 2408,
    Fenix3Hr = 2413,
    VirbUltra30 = 2417,
    IndexSmartScale = 2429,
    Fr235 = 2431,
    Fenix3Chronos = 2432,
    Oregon7xx = 2441,
    Rino7xx = 2444,
    EpixKorea = 2457,
    Fenix3HrChn = 2473,
    Fenix3HrTwn = 2474,
    Fenix3HrJpn = 2475,
    Fenix3HrSea = 2476,
    Fenix3HrKor = 2477,
    Nautix = 2496,
    VivoActiveHrApac = 2497,
    Fr35 = 2503,
    Oregon7xxWw = 2512,
    Edge820 = 2530,
    EdgeExplore820 = 2531,
    Fr735xtApac = 2533,
    Fr735xtJapan = 2534,
    Fenix5s = 2544,
    D2BravoTitanium = 2547,
    VariaUt800 = 2567,
    RunningDynamicsPod = 2593,
    Edge820China = 2599,
    Edge820Japan = 2600,
    Fenix5x = 2604,
    VivoFitJr = 2606,
    VivoSmart3 = 2622,
    VivoSport = 2623,
    Edge820Taiwan = 2628,
    Edge820Korea = 2629,
    Edge820Sea = 2630,
    Fr35Hebrew = 2650,
    ApproachS60 = 2656,
    Fr35Apac = 2667,
    Fr35Japan = 2668,
    Fenix3ChronosAsia = 2675,
    Virb360 = 2687,
    Fr935 = 2691,
    Fenix5 = 2697,
    Vivoactive3 = 2700,
    Fr235ChinaNfc = 2733,
    Foretrex601701 = 2769,
    VivoMoveHr = 2772,
    Edge1030 = 2713,
    Fr35Sea = 2727,
    Vector3 = 2787,
    Fenix5Asia = 2796,
    Fenix5sAsia = 2797,
    Fenix5xAsia = 2798,
    ApproachZ80 = 2806,
    Fr35Korea = 2814,
    D2charlie = 2819,
    VivoSmart3Apac = 2831,
    VivoSportApac = 2832,
    Fr935Asia = 2833,
    Descent = 2859,
    VivoFit4 = 2878,
    Fr645 = 2886,
    Fr645m = 2888,
    Fr30 = 2891,
    Fenix5sPlus = 2900,
    Edge130 = 2909,
    Edge1030Asia = 2924,
    Vivosmart4 = 2927,
    VivoMoveHrAsia = 2945,
    ApproachX10 = 2962,
    Fr30Asia = 2977,
    Vivoactive3mW = 2988,
    Fr645Asia = 3003,
    Fr645mAsia = 3004,
    EdgeExplore = 3011,
    Gpsmap66 = 3028,
    ApproachS10 = 3049,
    Vivoactive3mL = 3066,
    Fr245 = 3076,
    Fr245Music = 3077,
    ApproachG80 = 3085,
    Edge130Asia = 3092,
    Edge1030Bontrager = 3095,
    Fenix5Plus = 3110,
    Fenix5xPlus = 3111,
    Edge520Plus = 3112,
    Fr945 = 3113,
    Edge530 = 3121,
    Edge830 = 3122,
    InstinctEsports = 3126,
    Fenix5sPlusApac = 3134,
    Fenix5xPlusApac = 3135,
    Edge520PlusApac = 3142,
    DescentT1 = 3143,
    Fr235lAsia = 3144,
    Fr245Asia = 3145,
    VivoActive3mApac = 3163,
    Gen3Bsm = 3192,
    Gen3Bcm = 3193,
    VivoSmart4Asia = 3218,
    Vivoactive4Small = 3224,
    Vivoactive4Large = 3225,
    Venu = 3226,
    MarqDriver = 3246,
    MarqAviator = 3247,
    MarqCaptain = 3248,
    MarqCommander = 3249,
    MarqExpedition = 3250,
    MarqAthlete = 3251,
    DescentMk2 = 3258,
    Fr45 = 3282,
    Gpsmap66i = 3284,
    Fenix6SSport = 3287,
    Fenix6S = 3288,
    Fenix6Sport = 3289,
    Fenix6 = 3290,
    Fenix6x = 3291,
    HrmDual = 3299,
    HrmPro = 3300,
    VivoMove3Premium = 3308,
    ApproachS40 = 3314,
    Fr245mAsia = 3321,
    Edge530Apac = 3349,
    Edge830Apac = 3350,
    VivoMove3 = 3378,
    VivoActive4SmallAsia = 3387,
    VivoActive4LargeAsia = 3388,
    VivoActive4OledAsia = 3389,
    Swim2 = 3405,
    MarqDriverAsia = 3420,
    MarqAviatorAsia = 3421,
    VivoMove3Asia = 3422,
    Fr945Asia = 3441,
    VivoActive3tChn = 3446,
    MarqCaptainAsia = 3448,
    MarqCommanderAsia = 3449,
    MarqExpeditionAsia = 3450,
    MarqAthleteAsia = 3451,
    IndexSmartScale2 = 3461,
    InstinctSolar = 3466,
    Fr45Asia = 3469,
    Vivoactive3Daimler = 3473,
    LegacyRey = 3498,
    LegacyDarthVader = 3499,
    LegacyCaptainMarvel = 3500,
    LegacyFirstAvenger = 3501,
    Fenix6sSportAsia = 3512,
    Fenix6sAsia = 3513,
    Fenix6SportAsia = 3514,
    Fenix6Asia = 3515,
    Fenix6xAsia = 3516,
    LegacyCaptainMarvelAsia = 3535,
    LegacyFirstAvengerAsia = 3536,
    LegacyReyAsia = 3537,
    LegacyDarthVaderAsia = 3538,
    DescentMk2s = 3542,
    Edge130Plus = 3558,
    Edge1030Plus = 3570,
    Rally200 = 3578,
    Fr745 = 3589,
    VenusqMusic = 3596,
    VenusqMusicV2 = 3599,
    Venusq = 3600,
    Lily = 3615,
    MarqAdventurer = 3624,
    Enduro = 3638,
    Swim2Apac = 3639,
    MarqAdventurerAsia = 3648,
    Fr945Lte = 3652,
    DescentMk2Asia = 3702,
    Venu2 = 3703,
    Venu2s = 3704,
    VenuDaimlerAsia = 3737,
    MarqGolfer = 3739,
    VenuDaimler = 3740,
    Fr745Asia = 3794,
    VariaRct715 = 3808,
    LilyAsia = 3809,
    Edge1030PlusAsia = 3812,
    Edge130PlusAsia = 3813,
    ApproachS12 = 3823,
    EnduroAsia = 3872,
    VenusqAsia = 3837,
    Edge1040 = 3843,
    MarqGolferAsia = 3850,
    Venu2Plus = 3851,
    Gnss = 3865,
    Fr55 = 3869,
    Instinct2 = 3888,
    Instinct2s = 3889,
    Fenix7s = 3905,
    Fenix7 = 3906,
    Fenix7x = 3907,
    Fenix7sApac = 3908,
    Fenix7Apac = 3909,
    Fenix7xApac = 3910,
    ApproachG12 = 3927,
    DescentMk2sAsia = 3930,
    ApproachS42 = 3934,
    EpixGen2 = 3943,
    EpixGen2Apac = 3944,
    Venu2sAsia = 3949,
    Venu2Asia = 3950,
    Fr945LteAsia = 3978,
    VivoMoveSport = 3982,
    VivomoveTrend = 3983,
    ApproachS12Asia = 3986,
    Fr255Music = 3990,
    Fr255SmallMusic = 3991,
    Fr255 = 3992,
    Fr255Small = 3993,
    ApproachG12Asia = 4001,
    ApproachS42Asia = 4002,
    DescentG1 = 4005,
    Venu2PlusAsia = 4017,
    Fr955 = 4024,
    Fr55Asia = 4033,
    Edge540 = 4061,
    Edge840 = 4062,
    Vivosmart5 = 4063,
    Instinct2Asia = 4071,
    MarqGen2 = 4105,
    Venusq2 = 4115,
    Venusq2music = 4116,
    MarqGen2Aviator = 4124,
    D2AirX10 = 4125,
    HrmProPlus = 4130,
    DescentG1Asia = 4132,
    Tactix7 = 4135,
    InstinctCrossover = 4155,
    EdgeExplore2 = 4169,
    DescentMk3 = 4222,
    DescentMk3i = 4223,
    ApproachS70 = 4233,
    Fr265Large = 4257,
    Fr265Small = 4258,
    Venu3 = 4260,
    Venu3s = 4261,
    TacxNeoSmart = 4265,
    TacxNeo2Smart = 4266,
    TacxNeo2TSmart = 4267,
    TacxNeoSmartBike = 4268,
    TacxSatoriSmart = 4269,
    TacxFlowSmart = 4270,
    TacxVortexSmart = 4271,
    TacxBushidoSmart = 4272,
    TacxGeniusSmart = 4273,
    TacxFluxFluxSSmart = 4274,
    TacxFlux2Smart = 4275,
    TacxMagnum = 4276,
    Edge1040Asia = 4305,
    EpixGen2Pro42 = 4312,
    EpixGen2Pro47 = 4313,
    EpixGen2Pro51 = 4314,
    Fr965 = 4315,
    Enduro2 = 4341,
    Fenix7sProSolar = 4374,
    Fenix7ProSolar = 4375,
    Fenix7xProSolar = 4376,
    Lily2 = 4380,
    Instinct2x = 4394,
    Vivoactive5 = 4426,
    Fr165 = 4432,
    Fr165Music = 4433,
    Edge1050 = 4440,
    DescentT2 = 4442,
    HrmFit = 4446,
    MarqGen2Commander = 4472,
    LilyAthlete = 4477,
    RallyX10 = 4525,
    Fenix8Solar = 4532,
    Fenix8SolarLarge = 4533,
    Fenix8Small = 4534,
    Fenix8 = 4536,
    D2Mach1Pro = 4556,
    Enduro3 = 4575,
    InstinctE40mm = 4583,
    InstinctE45mm = 4584,
    Instinct3Solar45mm = 4585,
    Instinct3Amoled45mm = 4586,
    Instinct3Amoled50mm = 4587,
    DescentG2 = 4588,
    VenuX1 = 4603,
    Hrm200 = 4606,
    Vivoactive6 = 4625,
    Fenix8Pro = 4631,
    Edge550 = 4633,
    Edge850 = 4634,
    Venu4 = 4643,
    Venu4s = 4644,
    ApproachS44 = 4647,
    EdgeMtb = 4655,
    ApproachS50 = 4656,
    FenixE = 4666,
    Bounce2 = 4745,
    Instinct3Solar50mm = 4759,
    Tactix8Amoled = 4775,
    Tactix8Solar = 4776,
    ApproachJ1 = 4825,
    D2Mach2 = 4879,
    InstinctCrossoverAmoled = 4678,
    D2AirX15 = 4944,
    Sdm4 = 10007,
    EdgeRemote = 10014,
    TacxTrainingAppWin = 20533,
    TacxTrainingAppMac = 20534,
    TacxTrainingAppMacCatalyst = 20565,
    TrainingCenter = 20119,
    TacxTrainingAppAndroid = 30045,
    TacxTrainingAppIos = 30046,
    TacxTrainingAppLegacy = 30047,
    ConnectiqSimulator = 65531,
    AndroidAntplusPlugin = 65532,
    Connect = 65534,
}

impl GarminProduct {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            GarminProduct::Hrm1 => "hrm1",
            GarminProduct::Axh01 => "axh01",
            GarminProduct::Axb01 => "axb01",
            GarminProduct::Axb02 => "axb02",
            GarminProduct::Hrm2ss => "hrm2ss",
            GarminProduct::DsiAlf02 => "dsi_alf02",
            GarminProduct::Hrm3ss => "hrm3ss",
            GarminProduct::HrmRunSingleByteProductId => "hrm_run_single_byte_product_id",
            GarminProduct::Bsm => "bsm",
            GarminProduct::Bcm => "bcm",
            GarminProduct::Axs01 => "axs01",
            GarminProduct::HrmTriSingleByteProductId => "hrm_tri_single_byte_product_id",
            GarminProduct::Hrm4RunSingleByteProductId => "hrm4_run_single_byte_product_id",
            GarminProduct::Fr225SingleByteProductId => "fr225_single_byte_product_id",
            GarminProduct::Gen3BsmSingleByteProductId => "gen3_bsm_single_byte_product_id",
            GarminProduct::Gen3BcmSingleByteProductId => "gen3_bcm_single_byte_product_id",
            GarminProduct::HrmFitSingleByteProductId => "hrm_fit_single_byte_product_id",
            GarminProduct::OHR => "OHR",
            GarminProduct::Fr301China => "fr301_china",
            GarminProduct::Fr301Japan => "fr301_japan",
            GarminProduct::Fr301Korea => "fr301_korea",
            GarminProduct::Fr301Taiwan => "fr301_taiwan",
            GarminProduct::Fr405 => "fr405",
            GarminProduct::Fr50 => "fr50",
            GarminProduct::Fr405Japan => "fr405_japan",
            GarminProduct::Fr60 => "fr60",
            GarminProduct::DsiAlf01 => "dsi_alf01",
            GarminProduct::Fr310xt => "fr310xt",
            GarminProduct::Edge500 => "edge500",
            GarminProduct::Fr110 => "fr110",
            GarminProduct::Edge800 => "edge800",
            GarminProduct::Edge500Taiwan => "edge500_taiwan",
            GarminProduct::Edge500Japan => "edge500_japan",
            GarminProduct::Chirp => "chirp",
            GarminProduct::Fr110Japan => "fr110_japan",
            GarminProduct::Edge200 => "edge200",
            GarminProduct::Fr910xt => "fr910xt",
            GarminProduct::Edge800Taiwan => "edge800_taiwan",
            GarminProduct::Edge800Japan => "edge800_japan",
            GarminProduct::Alf04 => "alf04",
            GarminProduct::Fr610 => "fr610",
            GarminProduct::Fr210Japan => "fr210_japan",
            GarminProduct::VectorSs => "vector_ss",
            GarminProduct::VectorCp => "vector_cp",
            GarminProduct::Edge800China => "edge800_china",
            GarminProduct::Edge500China => "edge500_china",
            GarminProduct::ApproachG10 => "approach_g10",
            GarminProduct::Fr610Japan => "fr610_japan",
            GarminProduct::Edge500Korea => "edge500_korea",
            GarminProduct::Fr70 => "fr70",
            GarminProduct::Fr310xt4t => "fr310xt_4t",
            GarminProduct::Amx => "amx",
            GarminProduct::Fr10 => "fr10",
            GarminProduct::Edge800Korea => "edge800_korea",
            GarminProduct::Swim => "swim",
            GarminProduct::Fr910xtChina => "fr910xt_china",
            GarminProduct::Fenix => "fenix",
            GarminProduct::Edge200Taiwan => "edge200_taiwan",
            GarminProduct::Edge510 => "edge510",
            GarminProduct::Edge810 => "edge810",
            GarminProduct::Tempe => "tempe",
            GarminProduct::Fr910xtJapan => "fr910xt_japan",
            GarminProduct::Fr620 => "fr620",
            GarminProduct::Fr220 => "fr220",
            GarminProduct::Fr910xtKorea => "fr910xt_korea",
            GarminProduct::Fr10Japan => "fr10_japan",
            GarminProduct::Edge810Japan => "edge810_japan",
            GarminProduct::VirbElite => "virb_elite",
            GarminProduct::EdgeTouring => "edge_touring",
            GarminProduct::Edge510Japan => "edge510_japan",
            GarminProduct::HrmTri => "hrm_tri",
            GarminProduct::HrmRun => "hrm_run",
            GarminProduct::Fr920xt => "fr920xt",
            GarminProduct::Edge510Asia => "edge510_asia",
            GarminProduct::Edge810China => "edge810_china",
            GarminProduct::Edge810Taiwan => "edge810_taiwan",
            GarminProduct::Edge1000 => "edge1000",
            GarminProduct::VivoFit => "vivo_fit",
            GarminProduct::VirbRemote => "virb_remote",
            GarminProduct::VivoKi => "vivo_ki",
            GarminProduct::Fr15 => "fr15",
            GarminProduct::VivoActive => "vivo_active",
            GarminProduct::Edge510Korea => "edge510_korea",
            GarminProduct::Fr620Japan => "fr620_japan",
            GarminProduct::Fr620China => "fr620_china",
            GarminProduct::Fr220Japan => "fr220_japan",
            GarminProduct::Fr220China => "fr220_china",
            GarminProduct::ApproachS6 => "approach_s6",
            GarminProduct::VivoSmart => "vivo_smart",
            GarminProduct::Fenix2 => "fenix2",
            GarminProduct::Epix => "epix",
            GarminProduct::Fenix3 => "fenix3",
            GarminProduct::Edge1000Taiwan => "edge1000_taiwan",
            GarminProduct::Edge1000Japan => "edge1000_japan",
            GarminProduct::Fr15Japan => "fr15_japan",
            GarminProduct::Edge520 => "edge520",
            GarminProduct::Edge1000China => "edge1000_china",
            GarminProduct::Fr620Russia => "fr620_russia",
            GarminProduct::Fr220Russia => "fr220_russia",
            GarminProduct::VectorS => "vector_s",
            GarminProduct::Edge1000Korea => "edge1000_korea",
            GarminProduct::Fr920xtTaiwan => "fr920xt_taiwan",
            GarminProduct::Fr920xtChina => "fr920xt_china",
            GarminProduct::Fr920xtJapan => "fr920xt_japan",
            GarminProduct::Virbx => "virbx",
            GarminProduct::VivoSmartApac => "vivo_smart_apac",
            GarminProduct::EtrexTouch => "etrex_touch",
            GarminProduct::Edge25 => "edge25",
            GarminProduct::Fr25 => "fr25",
            GarminProduct::VivoFit2 => "vivo_fit2",
            GarminProduct::Fr225 => "fr225",
            GarminProduct::Fr630 => "fr630",
            GarminProduct::Fr230 => "fr230",
            GarminProduct::Fr735xt => "fr735xt",
            GarminProduct::VivoActiveApac => "vivo_active_apac",
            GarminProduct::Vector2 => "vector_2",
            GarminProduct::Vector2s => "vector_2s",
            GarminProduct::Virbxe => "virbxe",
            GarminProduct::Fr620Taiwan => "fr620_taiwan",
            GarminProduct::Fr220Taiwan => "fr220_taiwan",
            GarminProduct::Truswing => "truswing",
            GarminProduct::D2airvenu => "d2airvenu",
            GarminProduct::Fenix3China => "fenix3_china",
            GarminProduct::Fenix3Twn => "fenix3_twn",
            GarminProduct::VariaHeadlight => "varia_headlight",
            GarminProduct::VariaTaillightOld => "varia_taillight_old",
            GarminProduct::EdgeExplore1000 => "edge_explore_1000",
            GarminProduct::Fr225Asia => "fr225_asia",
            GarminProduct::VariaRadarTaillight => "varia_radar_taillight",
            GarminProduct::VariaRadarDisplay => "varia_radar_display",
            GarminProduct::Edge20 => "edge20",
            GarminProduct::Edge520Asia => "edge520_asia",
            GarminProduct::Edge520Japan => "edge520_japan",
            GarminProduct::D2Bravo => "d2_bravo",
            GarminProduct::ApproachS20 => "approach_s20",
            GarminProduct::VivoSmart2 => "vivo_smart2",
            GarminProduct::Edge1000Thai => "edge1000_thai",
            GarminProduct::VariaRemote => "varia_remote",
            GarminProduct::Edge25Asia => "edge25_asia",
            GarminProduct::Edge25Jpn => "edge25_jpn",
            GarminProduct::Edge20Asia => "edge20_asia",
            GarminProduct::ApproachX40 => "approach_x40",
            GarminProduct::Fenix3Japan => "fenix3_japan",
            GarminProduct::VivoSmartEmea => "vivo_smart_emea",
            GarminProduct::Fr630Asia => "fr630_asia",
            GarminProduct::Fr630Jpn => "fr630_jpn",
            GarminProduct::Fr230Jpn => "fr230_jpn",
            GarminProduct::Hrm4Run => "hrm4_run",
            GarminProduct::EpixJapan => "epix_japan",
            GarminProduct::VivoActiveHr => "vivo_active_hr",
            GarminProduct::VivoSmartGpsHr => "vivo_smart_gps_hr",
            GarminProduct::VivoSmartHr => "vivo_smart_hr",
            GarminProduct::VivoSmartHrAsia => "vivo_smart_hr_asia",
            GarminProduct::VivoSmartGpsHrAsia => "vivo_smart_gps_hr_asia",
            GarminProduct::VivoMove => "vivo_move",
            GarminProduct::VariaTaillight => "varia_taillight",
            GarminProduct::Fr235Asia => "fr235_asia",
            GarminProduct::Fr235Japan => "fr235_japan",
            GarminProduct::VariaVision => "varia_vision",
            GarminProduct::VivoFit3 => "vivo_fit3",
            GarminProduct::Fenix3Korea => "fenix3_korea",
            GarminProduct::Fenix3Sea => "fenix3_sea",
            GarminProduct::Fenix3Hr => "fenix3_hr",
            GarminProduct::VirbUltra30 => "virb_ultra_30",
            GarminProduct::IndexSmartScale => "index_smart_scale",
            GarminProduct::Fr235 => "fr235",
            GarminProduct::Fenix3Chronos => "fenix3_chronos",
            GarminProduct::Oregon7xx => "oregon7xx",
            GarminProduct::Rino7xx => "rino7xx",
            GarminProduct::EpixKorea => "epix_korea",
            GarminProduct::Fenix3HrChn => "fenix3_hr_chn",
            GarminProduct::Fenix3HrTwn => "fenix3_hr_twn",
            GarminProduct::Fenix3HrJpn => "fenix3_hr_jpn",
            GarminProduct::Fenix3HrSea => "fenix3_hr_sea",
            GarminProduct::Fenix3HrKor => "fenix3_hr_kor",
            GarminProduct::Nautix => "nautix",
            GarminProduct::VivoActiveHrApac => "vivo_active_hr_apac",
            GarminProduct::Fr35 => "fr35",
            GarminProduct::Oregon7xxWw => "oregon7xx_ww",
            GarminProduct::Edge820 => "edge_820",
            GarminProduct::EdgeExplore820 => "edge_explore_820",
            GarminProduct::Fr735xtApac => "fr735xt_apac",
            GarminProduct::Fr735xtJapan => "fr735xt_japan",
            GarminProduct::Fenix5s => "fenix5s",
            GarminProduct::D2BravoTitanium => "d2_bravo_titanium",
            GarminProduct::VariaUt800 => "varia_ut800",
            GarminProduct::RunningDynamicsPod => "running_dynamics_pod",
            GarminProduct::Edge820China => "edge_820_china",
            GarminProduct::Edge820Japan => "edge_820_japan",
            GarminProduct::Fenix5x => "fenix5x",
            GarminProduct::VivoFitJr => "vivo_fit_jr",
            GarminProduct::VivoSmart3 => "vivo_smart3",
            GarminProduct::VivoSport => "vivo_sport",
            GarminProduct::Edge820Taiwan => "edge_820_taiwan",
            GarminProduct::Edge820Korea => "edge_820_korea",
            GarminProduct::Edge820Sea => "edge_820_sea",
            GarminProduct::Fr35Hebrew => "fr35_hebrew",
            GarminProduct::ApproachS60 => "approach_s60",
            GarminProduct::Fr35Apac => "fr35_apac",
            GarminProduct::Fr35Japan => "fr35_japan",
            GarminProduct::Fenix3ChronosAsia => "fenix3_chronos_asia",
            GarminProduct::Virb360 => "virb_360",
            GarminProduct::Fr935 => "fr935",
            GarminProduct::Fenix5 => "fenix5",
            GarminProduct::Vivoactive3 => "vivoactive3",
            GarminProduct::Fr235ChinaNfc => "fr235_china_nfc",
            GarminProduct::Foretrex601701 => "foretrex_601_701",
            GarminProduct::VivoMoveHr => "vivo_move_hr",
            GarminProduct::Edge1030 => "edge_1030",
            GarminProduct::Fr35Sea => "fr35_sea",
            GarminProduct::Vector3 => "vector_3",
            GarminProduct::Fenix5Asia => "fenix5_asia",
            GarminProduct::Fenix5sAsia => "fenix5s_asia",
            GarminProduct::Fenix5xAsia => "fenix5x_asia",
            GarminProduct::ApproachZ80 => "approach_z80",
            GarminProduct::Fr35Korea => "fr35_korea",
            GarminProduct::D2charlie => "d2charlie",
            GarminProduct::VivoSmart3Apac => "vivo_smart3_apac",
            GarminProduct::VivoSportApac => "vivo_sport_apac",
            GarminProduct::Fr935Asia => "fr935_asia",
            GarminProduct::Descent => "descent",
            GarminProduct::VivoFit4 => "vivo_fit4",
            GarminProduct::Fr645 => "fr645",
            GarminProduct::Fr645m => "fr645m",
            GarminProduct::Fr30 => "fr30",
            GarminProduct::Fenix5sPlus => "fenix5s_plus",
            GarminProduct::Edge130 => "Edge_130",
            GarminProduct::Edge1030Asia => "edge_1030_asia",
            GarminProduct::Vivosmart4 => "vivosmart_4",
            GarminProduct::VivoMoveHrAsia => "vivo_move_hr_asia",
            GarminProduct::ApproachX10 => "approach_x10",
            GarminProduct::Fr30Asia => "fr30_asia",
            GarminProduct::Vivoactive3mW => "vivoactive3m_w",
            GarminProduct::Fr645Asia => "fr645_asia",
            GarminProduct::Fr645mAsia => "fr645m_asia",
            GarminProduct::EdgeExplore => "edge_explore",
            GarminProduct::Gpsmap66 => "gpsmap66",
            GarminProduct::ApproachS10 => "approach_s10",
            GarminProduct::Vivoactive3mL => "vivoactive3m_l",
            GarminProduct::Fr245 => "fr245",
            GarminProduct::Fr245Music => "fr245_music",
            GarminProduct::ApproachG80 => "approach_g80",
            GarminProduct::Edge130Asia => "edge_130_asia",
            GarminProduct::Edge1030Bontrager => "edge_1030_bontrager",
            GarminProduct::Fenix5Plus => "fenix5_plus",
            GarminProduct::Fenix5xPlus => "fenix5x_plus",
            GarminProduct::Edge520Plus => "edge_520_plus",
            GarminProduct::Fr945 => "fr945",
            GarminProduct::Edge530 => "edge_530",
            GarminProduct::Edge830 => "edge_830",
            GarminProduct::InstinctEsports => "instinct_esports",
            GarminProduct::Fenix5sPlusApac => "fenix5s_plus_apac",
            GarminProduct::Fenix5xPlusApac => "fenix5x_plus_apac",
            GarminProduct::Edge520PlusApac => "edge_520_plus_apac",
            GarminProduct::DescentT1 => "descent_t1",
            GarminProduct::Fr235lAsia => "fr235l_asia",
            GarminProduct::Fr245Asia => "fr245_asia",
            GarminProduct::VivoActive3mApac => "vivo_active3m_apac",
            GarminProduct::Gen3Bsm => "gen3_bsm",
            GarminProduct::Gen3Bcm => "gen3_bcm",
            GarminProduct::VivoSmart4Asia => "vivo_smart4_asia",
            GarminProduct::Vivoactive4Small => "vivoactive4_small",
            GarminProduct::Vivoactive4Large => "vivoactive4_large",
            GarminProduct::Venu => "venu",
            GarminProduct::MarqDriver => "marq_driver",
            GarminProduct::MarqAviator => "marq_aviator",
            GarminProduct::MarqCaptain => "marq_captain",
            GarminProduct::MarqCommander => "marq_commander",
            GarminProduct::MarqExpedition => "marq_expedition",
            GarminProduct::MarqAthlete => "marq_athlete",
            GarminProduct::DescentMk2 => "descent_mk2",
            GarminProduct::Fr45 => "fr45",
            GarminProduct::Gpsmap66i => "gpsmap66i",
            GarminProduct::Fenix6SSport => "fenix6S_sport",
            GarminProduct::Fenix6S => "fenix6S",
            GarminProduct::Fenix6Sport => "fenix6_sport",
            GarminProduct::Fenix6 => "fenix6",
            GarminProduct::Fenix6x => "fenix6x",
            GarminProduct::HrmDual => "hrm_dual",
            GarminProduct::HrmPro => "hrm_pro",
            GarminProduct::VivoMove3Premium => "vivo_move3_premium",
            GarminProduct::ApproachS40 => "approach_s40",
            GarminProduct::Fr245mAsia => "fr245m_asia",
            GarminProduct::Edge530Apac => "edge_530_apac",
            GarminProduct::Edge830Apac => "edge_830_apac",
            GarminProduct::VivoMove3 => "vivo_move3",
            GarminProduct::VivoActive4SmallAsia => "vivo_active4_small_asia",
            GarminProduct::VivoActive4LargeAsia => "vivo_active4_large_asia",
            GarminProduct::VivoActive4OledAsia => "vivo_active4_oled_asia",
            GarminProduct::Swim2 => "swim2",
            GarminProduct::MarqDriverAsia => "marq_driver_asia",
            GarminProduct::MarqAviatorAsia => "marq_aviator_asia",
            GarminProduct::VivoMove3Asia => "vivo_move3_asia",
            GarminProduct::Fr945Asia => "fr945_asia",
            GarminProduct::VivoActive3tChn => "vivo_active3t_chn",
            GarminProduct::MarqCaptainAsia => "marq_captain_asia",
            GarminProduct::MarqCommanderAsia => "marq_commander_asia",
            GarminProduct::MarqExpeditionAsia => "marq_expedition_asia",
            GarminProduct::MarqAthleteAsia => "marq_athlete_asia",
            GarminProduct::IndexSmartScale2 => "index_smart_scale_2",
            GarminProduct::InstinctSolar => "instinct_solar",
            GarminProduct::Fr45Asia => "fr45_asia",
            GarminProduct::Vivoactive3Daimler => "vivoactive3_daimler",
            GarminProduct::LegacyRey => "legacy_rey",
            GarminProduct::LegacyDarthVader => "legacy_darth_vader",
            GarminProduct::LegacyCaptainMarvel => "legacy_captain_marvel",
            GarminProduct::LegacyFirstAvenger => "legacy_first_avenger",
            GarminProduct::Fenix6sSportAsia => "fenix6s_sport_asia",
            GarminProduct::Fenix6sAsia => "fenix6s_asia",
            GarminProduct::Fenix6SportAsia => "fenix6_sport_asia",
            GarminProduct::Fenix6Asia => "fenix6_asia",
            GarminProduct::Fenix6xAsia => "fenix6x_asia",
            GarminProduct::LegacyCaptainMarvelAsia => "legacy_captain_marvel_asia",
            GarminProduct::LegacyFirstAvengerAsia => "legacy_first_avenger_asia",
            GarminProduct::LegacyReyAsia => "legacy_rey_asia",
            GarminProduct::LegacyDarthVaderAsia => "legacy_darth_vader_asia",
            GarminProduct::DescentMk2s => "descent_mk2s",
            GarminProduct::Edge130Plus => "edge_130_plus",
            GarminProduct::Edge1030Plus => "edge_1030_plus",
            GarminProduct::Rally200 => "rally_200",
            GarminProduct::Fr745 => "fr745",
            GarminProduct::VenusqMusic => "venusq_music",
            GarminProduct::VenusqMusicV2 => "venusq_music_v2",
            GarminProduct::Venusq => "venusq",
            GarminProduct::Lily => "lily",
            GarminProduct::MarqAdventurer => "marq_adventurer",
            GarminProduct::Enduro => "enduro",
            GarminProduct::Swim2Apac => "swim2_apac",
            GarminProduct::MarqAdventurerAsia => "marq_adventurer_asia",
            GarminProduct::Fr945Lte => "fr945_lte",
            GarminProduct::DescentMk2Asia => "descent_mk2_asia",
            GarminProduct::Venu2 => "venu2",
            GarminProduct::Venu2s => "venu2s",
            GarminProduct::VenuDaimlerAsia => "venu_daimler_asia",
            GarminProduct::MarqGolfer => "marq_golfer",
            GarminProduct::VenuDaimler => "venu_daimler",
            GarminProduct::Fr745Asia => "fr745_asia",
            GarminProduct::VariaRct715 => "varia_rct715",
            GarminProduct::LilyAsia => "lily_asia",
            GarminProduct::Edge1030PlusAsia => "edge_1030_plus_asia",
            GarminProduct::Edge130PlusAsia => "edge_130_plus_asia",
            GarminProduct::ApproachS12 => "approach_s12",
            GarminProduct::EnduroAsia => "enduro_asia",
            GarminProduct::VenusqAsia => "venusq_asia",
            GarminProduct::Edge1040 => "edge_1040",
            GarminProduct::MarqGolferAsia => "marq_golfer_asia",
            GarminProduct::Venu2Plus => "venu2_plus",
            GarminProduct::Gnss => "gnss",
            GarminProduct::Fr55 => "fr55",
            GarminProduct::Instinct2 => "instinct_2",
            GarminProduct::Instinct2s => "instinct_2s",
            GarminProduct::Fenix7s => "fenix7s",
            GarminProduct::Fenix7 => "fenix7",
            GarminProduct::Fenix7x => "fenix7x",
            GarminProduct::Fenix7sApac => "fenix7s_apac",
            GarminProduct::Fenix7Apac => "fenix7_apac",
            GarminProduct::Fenix7xApac => "fenix7x_apac",
            GarminProduct::ApproachG12 => "approach_g12",
            GarminProduct::DescentMk2sAsia => "descent_mk2s_asia",
            GarminProduct::ApproachS42 => "approach_s42",
            GarminProduct::EpixGen2 => "epix_gen2",
            GarminProduct::EpixGen2Apac => "epix_gen2_apac",
            GarminProduct::Venu2sAsia => "venu2s_asia",
            GarminProduct::Venu2Asia => "venu2_asia",
            GarminProduct::Fr945LteAsia => "fr945_lte_asia",
            GarminProduct::VivoMoveSport => "vivo_move_sport",
            GarminProduct::VivomoveTrend => "vivomove_trend",
            GarminProduct::ApproachS12Asia => "approach_S12_asia",
            GarminProduct::Fr255Music => "fr255_music",
            GarminProduct::Fr255SmallMusic => "fr255_small_music",
            GarminProduct::Fr255 => "fr255",
            GarminProduct::Fr255Small => "fr255_small",
            GarminProduct::ApproachG12Asia => "approach_g12_asia",
            GarminProduct::ApproachS42Asia => "approach_s42_asia",
            GarminProduct::DescentG1 => "descent_g1",
            GarminProduct::Venu2PlusAsia => "venu2_plus_asia",
            GarminProduct::Fr955 => "fr955",
            GarminProduct::Fr55Asia => "fr55_asia",
            GarminProduct::Edge540 => "edge_540",
            GarminProduct::Edge840 => "edge_840",
            GarminProduct::Vivosmart5 => "vivosmart_5",
            GarminProduct::Instinct2Asia => "instinct_2_asia",
            GarminProduct::MarqGen2 => "marq_gen2",
            GarminProduct::Venusq2 => "venusq2",
            GarminProduct::Venusq2music => "venusq2music",
            GarminProduct::MarqGen2Aviator => "marq_gen2_aviator",
            GarminProduct::D2AirX10 => "d2_air_x10",
            GarminProduct::HrmProPlus => "hrm_pro_plus",
            GarminProduct::DescentG1Asia => "descent_g1_asia",
            GarminProduct::Tactix7 => "tactix7",
            GarminProduct::InstinctCrossover => "instinct_crossover",
            GarminProduct::EdgeExplore2 => "edge_explore2",
            GarminProduct::DescentMk3 => "descent_mk3",
            GarminProduct::DescentMk3i => "descent_mk3i",
            GarminProduct::ApproachS70 => "approach_s70",
            GarminProduct::Fr265Large => "fr265_large",
            GarminProduct::Fr265Small => "fr265_small",
            GarminProduct::Venu3 => "venu3",
            GarminProduct::Venu3s => "venu3s",
            GarminProduct::TacxNeoSmart => "tacx_neo_smart",
            GarminProduct::TacxNeo2Smart => "tacx_neo2_smart",
            GarminProduct::TacxNeo2TSmart => "tacx_neo2_t_smart",
            GarminProduct::TacxNeoSmartBike => "tacx_neo_smart_bike",
            GarminProduct::TacxSatoriSmart => "tacx_satori_smart",
            GarminProduct::TacxFlowSmart => "tacx_flow_smart",
            GarminProduct::TacxVortexSmart => "tacx_vortex_smart",
            GarminProduct::TacxBushidoSmart => "tacx_bushido_smart",
            GarminProduct::TacxGeniusSmart => "tacx_genius_smart",
            GarminProduct::TacxFluxFluxSSmart => "tacx_flux_flux_s_smart",
            GarminProduct::TacxFlux2Smart => "tacx_flux2_smart",
            GarminProduct::TacxMagnum => "tacx_magnum",
            GarminProduct::Edge1040Asia => "edge_1040_asia",
            GarminProduct::EpixGen2Pro42 => "epix_gen2_pro_42",
            GarminProduct::EpixGen2Pro47 => "epix_gen2_pro_47",
            GarminProduct::EpixGen2Pro51 => "epix_gen2_pro_51",
            GarminProduct::Fr965 => "fr965",
            GarminProduct::Enduro2 => "enduro2",
            GarminProduct::Fenix7sProSolar => "fenix7s_pro_solar",
            GarminProduct::Fenix7ProSolar => "fenix7_pro_solar",
            GarminProduct::Fenix7xProSolar => "fenix7x_pro_solar",
            GarminProduct::Lily2 => "lily2",
            GarminProduct::Instinct2x => "instinct_2x",
            GarminProduct::Vivoactive5 => "vivoactive5",
            GarminProduct::Fr165 => "fr165",
            GarminProduct::Fr165Music => "fr165_music",
            GarminProduct::Edge1050 => "edge_1050",
            GarminProduct::DescentT2 => "descent_t2",
            GarminProduct::HrmFit => "hrm_fit",
            GarminProduct::MarqGen2Commander => "marq_gen2_commander",
            GarminProduct::LilyAthlete => "lily_athlete",
            GarminProduct::RallyX10 => "rally_x10",
            GarminProduct::Fenix8Solar => "fenix8_solar",
            GarminProduct::Fenix8SolarLarge => "fenix8_solar_large",
            GarminProduct::Fenix8Small => "fenix8_small",
            GarminProduct::Fenix8 => "fenix8",
            GarminProduct::D2Mach1Pro => "d2_mach1_pro",
            GarminProduct::Enduro3 => "enduro3",
            GarminProduct::InstinctE40mm => "instinctE_40mm",
            GarminProduct::InstinctE45mm => "instinctE_45mm",
            GarminProduct::Instinct3Solar45mm => "instinct3_solar_45mm",
            GarminProduct::Instinct3Amoled45mm => "instinct3_amoled_45mm",
            GarminProduct::Instinct3Amoled50mm => "instinct3_amoled_50mm",
            GarminProduct::DescentG2 => "descent_g2",
            GarminProduct::VenuX1 => "venu_x1",
            GarminProduct::Hrm200 => "hrm_200",
            GarminProduct::Vivoactive6 => "vivoactive6",
            GarminProduct::Fenix8Pro => "fenix8_pro",
            GarminProduct::Edge550 => "edge_550",
            GarminProduct::Edge850 => "edge_850",
            GarminProduct::Venu4 => "venu4",
            GarminProduct::Venu4s => "venu4s",
            GarminProduct::ApproachS44 => "approachS44",
            GarminProduct::EdgeMtb => "edge_mtb",
            GarminProduct::ApproachS50 => "approachS50",
            GarminProduct::FenixE => "fenix_e",
            GarminProduct::Bounce2 => "bounce2",
            GarminProduct::Instinct3Solar50mm => "instinct3_solar_50mm",
            GarminProduct::Tactix8Amoled => "tactix8_amoled",
            GarminProduct::Tactix8Solar => "tactix8_solar",
            GarminProduct::ApproachJ1 => "approach_j1",
            GarminProduct::D2Mach2 => "d2_mach2",
            GarminProduct::InstinctCrossoverAmoled => "instinct_crossover_amoled",
            GarminProduct::D2AirX15 => "d2_air_x15",
            GarminProduct::Sdm4 => "sdm4",
            GarminProduct::EdgeRemote => "edge_remote",
            GarminProduct::TacxTrainingAppWin => "tacx_training_app_win",
            GarminProduct::TacxTrainingAppMac => "tacx_training_app_mac",
            GarminProduct::TacxTrainingAppMacCatalyst => "tacx_training_app_mac_catalyst",
            GarminProduct::TrainingCenter => "training_center",
            GarminProduct::TacxTrainingAppAndroid => "tacx_training_app_android",
            GarminProduct::TacxTrainingAppIos => "tacx_training_app_ios",
            GarminProduct::TacxTrainingAppLegacy => "tacx_training_app_legacy",
            GarminProduct::ConnectiqSimulator => "connectiq_simulator",
            GarminProduct::AndroidAntplusPlugin => "android_antplus_plugin",
            GarminProduct::Connect => "connect",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            1 => Some(GarminProduct::Hrm1),
            2 => Some(GarminProduct::Axh01),
            3 => Some(GarminProduct::Axb01),
            4 => Some(GarminProduct::Axb02),
            5 => Some(GarminProduct::Hrm2ss),
            6 => Some(GarminProduct::DsiAlf02),
            7 => Some(GarminProduct::Hrm3ss),
            8 => Some(GarminProduct::HrmRunSingleByteProductId),
            9 => Some(GarminProduct::Bsm),
            10 => Some(GarminProduct::Bcm),
            11 => Some(GarminProduct::Axs01),
            12 => Some(GarminProduct::HrmTriSingleByteProductId),
            13 => Some(GarminProduct::Hrm4RunSingleByteProductId),
            14 => Some(GarminProduct::Fr225SingleByteProductId),
            15 => Some(GarminProduct::Gen3BsmSingleByteProductId),
            16 => Some(GarminProduct::Gen3BcmSingleByteProductId),
            22 => Some(GarminProduct::HrmFitSingleByteProductId),
            255 => Some(GarminProduct::OHR),
            473 => Some(GarminProduct::Fr301China),
            474 => Some(GarminProduct::Fr301Japan),
            475 => Some(GarminProduct::Fr301Korea),
            494 => Some(GarminProduct::Fr301Taiwan),
            717 => Some(GarminProduct::Fr405),
            782 => Some(GarminProduct::Fr50),
            987 => Some(GarminProduct::Fr405Japan),
            988 => Some(GarminProduct::Fr60),
            1011 => Some(GarminProduct::DsiAlf01),
            1018 => Some(GarminProduct::Fr310xt),
            1036 => Some(GarminProduct::Edge500),
            1124 => Some(GarminProduct::Fr110),
            1169 => Some(GarminProduct::Edge800),
            1199 => Some(GarminProduct::Edge500Taiwan),
            1213 => Some(GarminProduct::Edge500Japan),
            1253 => Some(GarminProduct::Chirp),
            1274 => Some(GarminProduct::Fr110Japan),
            1325 => Some(GarminProduct::Edge200),
            1328 => Some(GarminProduct::Fr910xt),
            1333 => Some(GarminProduct::Edge800Taiwan),
            1334 => Some(GarminProduct::Edge800Japan),
            1341 => Some(GarminProduct::Alf04),
            1345 => Some(GarminProduct::Fr610),
            1360 => Some(GarminProduct::Fr210Japan),
            1380 => Some(GarminProduct::VectorSs),
            1381 => Some(GarminProduct::VectorCp),
            1386 => Some(GarminProduct::Edge800China),
            1387 => Some(GarminProduct::Edge500China),
            1405 => Some(GarminProduct::ApproachG10),
            1410 => Some(GarminProduct::Fr610Japan),
            1422 => Some(GarminProduct::Edge500Korea),
            1436 => Some(GarminProduct::Fr70),
            1446 => Some(GarminProduct::Fr310xt4t),
            1461 => Some(GarminProduct::Amx),
            1482 => Some(GarminProduct::Fr10),
            1497 => Some(GarminProduct::Edge800Korea),
            1499 => Some(GarminProduct::Swim),
            1537 => Some(GarminProduct::Fr910xtChina),
            1551 => Some(GarminProduct::Fenix),
            1555 => Some(GarminProduct::Edge200Taiwan),
            1561 => Some(GarminProduct::Edge510),
            1567 => Some(GarminProduct::Edge810),
            1570 => Some(GarminProduct::Tempe),
            1600 => Some(GarminProduct::Fr910xtJapan),
            1623 => Some(GarminProduct::Fr620),
            1632 => Some(GarminProduct::Fr220),
            1664 => Some(GarminProduct::Fr910xtKorea),
            1688 => Some(GarminProduct::Fr10Japan),
            1721 => Some(GarminProduct::Edge810Japan),
            1735 => Some(GarminProduct::VirbElite),
            1736 => Some(GarminProduct::EdgeTouring),
            1742 => Some(GarminProduct::Edge510Japan),
            1743 => Some(GarminProduct::HrmTri),
            1752 => Some(GarminProduct::HrmRun),
            1765 => Some(GarminProduct::Fr920xt),
            1821 => Some(GarminProduct::Edge510Asia),
            1822 => Some(GarminProduct::Edge810China),
            1823 => Some(GarminProduct::Edge810Taiwan),
            1836 => Some(GarminProduct::Edge1000),
            1837 => Some(GarminProduct::VivoFit),
            1853 => Some(GarminProduct::VirbRemote),
            1885 => Some(GarminProduct::VivoKi),
            1903 => Some(GarminProduct::Fr15),
            1907 => Some(GarminProduct::VivoActive),
            1918 => Some(GarminProduct::Edge510Korea),
            1928 => Some(GarminProduct::Fr620Japan),
            1929 => Some(GarminProduct::Fr620China),
            1930 => Some(GarminProduct::Fr220Japan),
            1931 => Some(GarminProduct::Fr220China),
            1936 => Some(GarminProduct::ApproachS6),
            1956 => Some(GarminProduct::VivoSmart),
            1967 => Some(GarminProduct::Fenix2),
            1988 => Some(GarminProduct::Epix),
            2050 => Some(GarminProduct::Fenix3),
            2052 => Some(GarminProduct::Edge1000Taiwan),
            2053 => Some(GarminProduct::Edge1000Japan),
            2061 => Some(GarminProduct::Fr15Japan),
            2067 => Some(GarminProduct::Edge520),
            2070 => Some(GarminProduct::Edge1000China),
            2072 => Some(GarminProduct::Fr620Russia),
            2073 => Some(GarminProduct::Fr220Russia),
            2079 => Some(GarminProduct::VectorS),
            2100 => Some(GarminProduct::Edge1000Korea),
            2130 => Some(GarminProduct::Fr920xtTaiwan),
            2131 => Some(GarminProduct::Fr920xtChina),
            2132 => Some(GarminProduct::Fr920xtJapan),
            2134 => Some(GarminProduct::Virbx),
            2135 => Some(GarminProduct::VivoSmartApac),
            2140 => Some(GarminProduct::EtrexTouch),
            2147 => Some(GarminProduct::Edge25),
            2148 => Some(GarminProduct::Fr25),
            2150 => Some(GarminProduct::VivoFit2),
            2153 => Some(GarminProduct::Fr225),
            2156 => Some(GarminProduct::Fr630),
            2157 => Some(GarminProduct::Fr230),
            2158 => Some(GarminProduct::Fr735xt),
            2160 => Some(GarminProduct::VivoActiveApac),
            2161 => Some(GarminProduct::Vector2),
            2162 => Some(GarminProduct::Vector2s),
            2172 => Some(GarminProduct::Virbxe),
            2173 => Some(GarminProduct::Fr620Taiwan),
            2174 => Some(GarminProduct::Fr220Taiwan),
            2175 => Some(GarminProduct::Truswing),
            2187 => Some(GarminProduct::D2airvenu),
            2188 => Some(GarminProduct::Fenix3China),
            2189 => Some(GarminProduct::Fenix3Twn),
            2192 => Some(GarminProduct::VariaHeadlight),
            2193 => Some(GarminProduct::VariaTaillightOld),
            2204 => Some(GarminProduct::EdgeExplore1000),
            2219 => Some(GarminProduct::Fr225Asia),
            2225 => Some(GarminProduct::VariaRadarTaillight),
            2226 => Some(GarminProduct::VariaRadarDisplay),
            2238 => Some(GarminProduct::Edge20),
            2260 => Some(GarminProduct::Edge520Asia),
            2261 => Some(GarminProduct::Edge520Japan),
            2262 => Some(GarminProduct::D2Bravo),
            2266 => Some(GarminProduct::ApproachS20),
            2271 => Some(GarminProduct::VivoSmart2),
            2274 => Some(GarminProduct::Edge1000Thai),
            2276 => Some(GarminProduct::VariaRemote),
            2288 => Some(GarminProduct::Edge25Asia),
            2289 => Some(GarminProduct::Edge25Jpn),
            2290 => Some(GarminProduct::Edge20Asia),
            2292 => Some(GarminProduct::ApproachX40),
            2293 => Some(GarminProduct::Fenix3Japan),
            2294 => Some(GarminProduct::VivoSmartEmea),
            2310 => Some(GarminProduct::Fr630Asia),
            2311 => Some(GarminProduct::Fr630Jpn),
            2313 => Some(GarminProduct::Fr230Jpn),
            2327 => Some(GarminProduct::Hrm4Run),
            2332 => Some(GarminProduct::EpixJapan),
            2337 => Some(GarminProduct::VivoActiveHr),
            2347 => Some(GarminProduct::VivoSmartGpsHr),
            2348 => Some(GarminProduct::VivoSmartHr),
            2361 => Some(GarminProduct::VivoSmartHrAsia),
            2362 => Some(GarminProduct::VivoSmartGpsHrAsia),
            2368 => Some(GarminProduct::VivoMove),
            2379 => Some(GarminProduct::VariaTaillight),
            2396 => Some(GarminProduct::Fr235Asia),
            2397 => Some(GarminProduct::Fr235Japan),
            2398 => Some(GarminProduct::VariaVision),
            2406 => Some(GarminProduct::VivoFit3),
            2407 => Some(GarminProduct::Fenix3Korea),
            2408 => Some(GarminProduct::Fenix3Sea),
            2413 => Some(GarminProduct::Fenix3Hr),
            2417 => Some(GarminProduct::VirbUltra30),
            2429 => Some(GarminProduct::IndexSmartScale),
            2431 => Some(GarminProduct::Fr235),
            2432 => Some(GarminProduct::Fenix3Chronos),
            2441 => Some(GarminProduct::Oregon7xx),
            2444 => Some(GarminProduct::Rino7xx),
            2457 => Some(GarminProduct::EpixKorea),
            2473 => Some(GarminProduct::Fenix3HrChn),
            2474 => Some(GarminProduct::Fenix3HrTwn),
            2475 => Some(GarminProduct::Fenix3HrJpn),
            2476 => Some(GarminProduct::Fenix3HrSea),
            2477 => Some(GarminProduct::Fenix3HrKor),
            2496 => Some(GarminProduct::Nautix),
            2497 => Some(GarminProduct::VivoActiveHrApac),
            2503 => Some(GarminProduct::Fr35),
            2512 => Some(GarminProduct::Oregon7xxWw),
            2530 => Some(GarminProduct::Edge820),
            2531 => Some(GarminProduct::EdgeExplore820),
            2533 => Some(GarminProduct::Fr735xtApac),
            2534 => Some(GarminProduct::Fr735xtJapan),
            2544 => Some(GarminProduct::Fenix5s),
            2547 => Some(GarminProduct::D2BravoTitanium),
            2567 => Some(GarminProduct::VariaUt800),
            2593 => Some(GarminProduct::RunningDynamicsPod),
            2599 => Some(GarminProduct::Edge820China),
            2600 => Some(GarminProduct::Edge820Japan),
            2604 => Some(GarminProduct::Fenix5x),
            2606 => Some(GarminProduct::VivoFitJr),
            2622 => Some(GarminProduct::VivoSmart3),
            2623 => Some(GarminProduct::VivoSport),
            2628 => Some(GarminProduct::Edge820Taiwan),
            2629 => Some(GarminProduct::Edge820Korea),
            2630 => Some(GarminProduct::Edge820Sea),
            2650 => Some(GarminProduct::Fr35Hebrew),
            2656 => Some(GarminProduct::ApproachS60),
            2667 => Some(GarminProduct::Fr35Apac),
            2668 => Some(GarminProduct::Fr35Japan),
            2675 => Some(GarminProduct::Fenix3ChronosAsia),
            2687 => Some(GarminProduct::Virb360),
            2691 => Some(GarminProduct::Fr935),
            2697 => Some(GarminProduct::Fenix5),
            2700 => Some(GarminProduct::Vivoactive3),
            2733 => Some(GarminProduct::Fr235ChinaNfc),
            2769 => Some(GarminProduct::Foretrex601701),
            2772 => Some(GarminProduct::VivoMoveHr),
            2713 => Some(GarminProduct::Edge1030),
            2727 => Some(GarminProduct::Fr35Sea),
            2787 => Some(GarminProduct::Vector3),
            2796 => Some(GarminProduct::Fenix5Asia),
            2797 => Some(GarminProduct::Fenix5sAsia),
            2798 => Some(GarminProduct::Fenix5xAsia),
            2806 => Some(GarminProduct::ApproachZ80),
            2814 => Some(GarminProduct::Fr35Korea),
            2819 => Some(GarminProduct::D2charlie),
            2831 => Some(GarminProduct::VivoSmart3Apac),
            2832 => Some(GarminProduct::VivoSportApac),
            2833 => Some(GarminProduct::Fr935Asia),
            2859 => Some(GarminProduct::Descent),
            2878 => Some(GarminProduct::VivoFit4),
            2886 => Some(GarminProduct::Fr645),
            2888 => Some(GarminProduct::Fr645m),
            2891 => Some(GarminProduct::Fr30),
            2900 => Some(GarminProduct::Fenix5sPlus),
            2909 => Some(GarminProduct::Edge130),
            2924 => Some(GarminProduct::Edge1030Asia),
            2927 => Some(GarminProduct::Vivosmart4),
            2945 => Some(GarminProduct::VivoMoveHrAsia),
            2962 => Some(GarminProduct::ApproachX10),
            2977 => Some(GarminProduct::Fr30Asia),
            2988 => Some(GarminProduct::Vivoactive3mW),
            3003 => Some(GarminProduct::Fr645Asia),
            3004 => Some(GarminProduct::Fr645mAsia),
            3011 => Some(GarminProduct::EdgeExplore),
            3028 => Some(GarminProduct::Gpsmap66),
            3049 => Some(GarminProduct::ApproachS10),
            3066 => Some(GarminProduct::Vivoactive3mL),
            3076 => Some(GarminProduct::Fr245),
            3077 => Some(GarminProduct::Fr245Music),
            3085 => Some(GarminProduct::ApproachG80),
            3092 => Some(GarminProduct::Edge130Asia),
            3095 => Some(GarminProduct::Edge1030Bontrager),
            3110 => Some(GarminProduct::Fenix5Plus),
            3111 => Some(GarminProduct::Fenix5xPlus),
            3112 => Some(GarminProduct::Edge520Plus),
            3113 => Some(GarminProduct::Fr945),
            3121 => Some(GarminProduct::Edge530),
            3122 => Some(GarminProduct::Edge830),
            3126 => Some(GarminProduct::InstinctEsports),
            3134 => Some(GarminProduct::Fenix5sPlusApac),
            3135 => Some(GarminProduct::Fenix5xPlusApac),
            3142 => Some(GarminProduct::Edge520PlusApac),
            3143 => Some(GarminProduct::DescentT1),
            3144 => Some(GarminProduct::Fr235lAsia),
            3145 => Some(GarminProduct::Fr245Asia),
            3163 => Some(GarminProduct::VivoActive3mApac),
            3192 => Some(GarminProduct::Gen3Bsm),
            3193 => Some(GarminProduct::Gen3Bcm),
            3218 => Some(GarminProduct::VivoSmart4Asia),
            3224 => Some(GarminProduct::Vivoactive4Small),
            3225 => Some(GarminProduct::Vivoactive4Large),
            3226 => Some(GarminProduct::Venu),
            3246 => Some(GarminProduct::MarqDriver),
            3247 => Some(GarminProduct::MarqAviator),
            3248 => Some(GarminProduct::MarqCaptain),
            3249 => Some(GarminProduct::MarqCommander),
            3250 => Some(GarminProduct::MarqExpedition),
            3251 => Some(GarminProduct::MarqAthlete),
            3258 => Some(GarminProduct::DescentMk2),
            3282 => Some(GarminProduct::Fr45),
            3284 => Some(GarminProduct::Gpsmap66i),
            3287 => Some(GarminProduct::Fenix6SSport),
            3288 => Some(GarminProduct::Fenix6S),
            3289 => Some(GarminProduct::Fenix6Sport),
            3290 => Some(GarminProduct::Fenix6),
            3291 => Some(GarminProduct::Fenix6x),
            3299 => Some(GarminProduct::HrmDual),
            3300 => Some(GarminProduct::HrmPro),
            3308 => Some(GarminProduct::VivoMove3Premium),
            3314 => Some(GarminProduct::ApproachS40),
            3321 => Some(GarminProduct::Fr245mAsia),
            3349 => Some(GarminProduct::Edge530Apac),
            3350 => Some(GarminProduct::Edge830Apac),
            3378 => Some(GarminProduct::VivoMove3),
            3387 => Some(GarminProduct::VivoActive4SmallAsia),
            3388 => Some(GarminProduct::VivoActive4LargeAsia),
            3389 => Some(GarminProduct::VivoActive4OledAsia),
            3405 => Some(GarminProduct::Swim2),
            3420 => Some(GarminProduct::MarqDriverAsia),
            3421 => Some(GarminProduct::MarqAviatorAsia),
            3422 => Some(GarminProduct::VivoMove3Asia),
            3441 => Some(GarminProduct::Fr945Asia),
            3446 => Some(GarminProduct::VivoActive3tChn),
            3448 => Some(GarminProduct::MarqCaptainAsia),
            3449 => Some(GarminProduct::MarqCommanderAsia),
            3450 => Some(GarminProduct::MarqExpeditionAsia),
            3451 => Some(GarminProduct::MarqAthleteAsia),
            3461 => Some(GarminProduct::IndexSmartScale2),
            3466 => Some(GarminProduct::InstinctSolar),
            3469 => Some(GarminProduct::Fr45Asia),
            3473 => Some(GarminProduct::Vivoactive3Daimler),
            3498 => Some(GarminProduct::LegacyRey),
            3499 => Some(GarminProduct::LegacyDarthVader),
            3500 => Some(GarminProduct::LegacyCaptainMarvel),
            3501 => Some(GarminProduct::LegacyFirstAvenger),
            3512 => Some(GarminProduct::Fenix6sSportAsia),
            3513 => Some(GarminProduct::Fenix6sAsia),
            3514 => Some(GarminProduct::Fenix6SportAsia),
            3515 => Some(GarminProduct::Fenix6Asia),
            3516 => Some(GarminProduct::Fenix6xAsia),
            3535 => Some(GarminProduct::LegacyCaptainMarvelAsia),
            3536 => Some(GarminProduct::LegacyFirstAvengerAsia),
            3537 => Some(GarminProduct::LegacyReyAsia),
            3538 => Some(GarminProduct::LegacyDarthVaderAsia),
            3542 => Some(GarminProduct::DescentMk2s),
            3558 => Some(GarminProduct::Edge130Plus),
            3570 => Some(GarminProduct::Edge1030Plus),
            3578 => Some(GarminProduct::Rally200),
            3589 => Some(GarminProduct::Fr745),
            3596 => Some(GarminProduct::VenusqMusic),
            3599 => Some(GarminProduct::VenusqMusicV2),
            3600 => Some(GarminProduct::Venusq),
            3615 => Some(GarminProduct::Lily),
            3624 => Some(GarminProduct::MarqAdventurer),
            3638 => Some(GarminProduct::Enduro),
            3639 => Some(GarminProduct::Swim2Apac),
            3648 => Some(GarminProduct::MarqAdventurerAsia),
            3652 => Some(GarminProduct::Fr945Lte),
            3702 => Some(GarminProduct::DescentMk2Asia),
            3703 => Some(GarminProduct::Venu2),
            3704 => Some(GarminProduct::Venu2s),
            3737 => Some(GarminProduct::VenuDaimlerAsia),
            3739 => Some(GarminProduct::MarqGolfer),
            3740 => Some(GarminProduct::VenuDaimler),
            3794 => Some(GarminProduct::Fr745Asia),
            3808 => Some(GarminProduct::VariaRct715),
            3809 => Some(GarminProduct::LilyAsia),
            3812 => Some(GarminProduct::Edge1030PlusAsia),
            3813 => Some(GarminProduct::Edge130PlusAsia),
            3823 => Some(GarminProduct::ApproachS12),
            3872 => Some(GarminProduct::EnduroAsia),
            3837 => Some(GarminProduct::VenusqAsia),
            3843 => Some(GarminProduct::Edge1040),
            3850 => Some(GarminProduct::MarqGolferAsia),
            3851 => Some(GarminProduct::Venu2Plus),
            3865 => Some(GarminProduct::Gnss),
            3869 => Some(GarminProduct::Fr55),
            3888 => Some(GarminProduct::Instinct2),
            3889 => Some(GarminProduct::Instinct2s),
            3905 => Some(GarminProduct::Fenix7s),
            3906 => Some(GarminProduct::Fenix7),
            3907 => Some(GarminProduct::Fenix7x),
            3908 => Some(GarminProduct::Fenix7sApac),
            3909 => Some(GarminProduct::Fenix7Apac),
            3910 => Some(GarminProduct::Fenix7xApac),
            3927 => Some(GarminProduct::ApproachG12),
            3930 => Some(GarminProduct::DescentMk2sAsia),
            3934 => Some(GarminProduct::ApproachS42),
            3943 => Some(GarminProduct::EpixGen2),
            3944 => Some(GarminProduct::EpixGen2Apac),
            3949 => Some(GarminProduct::Venu2sAsia),
            3950 => Some(GarminProduct::Venu2Asia),
            3978 => Some(GarminProduct::Fr945LteAsia),
            3982 => Some(GarminProduct::VivoMoveSport),
            3983 => Some(GarminProduct::VivomoveTrend),
            3986 => Some(GarminProduct::ApproachS12Asia),
            3990 => Some(GarminProduct::Fr255Music),
            3991 => Some(GarminProduct::Fr255SmallMusic),
            3992 => Some(GarminProduct::Fr255),
            3993 => Some(GarminProduct::Fr255Small),
            4001 => Some(GarminProduct::ApproachG12Asia),
            4002 => Some(GarminProduct::ApproachS42Asia),
            4005 => Some(GarminProduct::DescentG1),
            4017 => Some(GarminProduct::Venu2PlusAsia),
            4024 => Some(GarminProduct::Fr955),
            4033 => Some(GarminProduct::Fr55Asia),
            4061 => Some(GarminProduct::Edge540),
            4062 => Some(GarminProduct::Edge840),
            4063 => Some(GarminProduct::Vivosmart5),
            4071 => Some(GarminProduct::Instinct2Asia),
            4105 => Some(GarminProduct::MarqGen2),
            4115 => Some(GarminProduct::Venusq2),
            4116 => Some(GarminProduct::Venusq2music),
            4124 => Some(GarminProduct::MarqGen2Aviator),
            4125 => Some(GarminProduct::D2AirX10),
            4130 => Some(GarminProduct::HrmProPlus),
            4132 => Some(GarminProduct::DescentG1Asia),
            4135 => Some(GarminProduct::Tactix7),
            4155 => Some(GarminProduct::InstinctCrossover),
            4169 => Some(GarminProduct::EdgeExplore2),
            4222 => Some(GarminProduct::DescentMk3),
            4223 => Some(GarminProduct::DescentMk3i),
            4233 => Some(GarminProduct::ApproachS70),
            4257 => Some(GarminProduct::Fr265Large),
            4258 => Some(GarminProduct::Fr265Small),
            4260 => Some(GarminProduct::Venu3),
            4261 => Some(GarminProduct::Venu3s),
            4265 => Some(GarminProduct::TacxNeoSmart),
            4266 => Some(GarminProduct::TacxNeo2Smart),
            4267 => Some(GarminProduct::TacxNeo2TSmart),
            4268 => Some(GarminProduct::TacxNeoSmartBike),
            4269 => Some(GarminProduct::TacxSatoriSmart),
            4270 => Some(GarminProduct::TacxFlowSmart),
            4271 => Some(GarminProduct::TacxVortexSmart),
            4272 => Some(GarminProduct::TacxBushidoSmart),
            4273 => Some(GarminProduct::TacxGeniusSmart),
            4274 => Some(GarminProduct::TacxFluxFluxSSmart),
            4275 => Some(GarminProduct::TacxFlux2Smart),
            4276 => Some(GarminProduct::TacxMagnum),
            4305 => Some(GarminProduct::Edge1040Asia),
            4312 => Some(GarminProduct::EpixGen2Pro42),
            4313 => Some(GarminProduct::EpixGen2Pro47),
            4314 => Some(GarminProduct::EpixGen2Pro51),
            4315 => Some(GarminProduct::Fr965),
            4341 => Some(GarminProduct::Enduro2),
            4374 => Some(GarminProduct::Fenix7sProSolar),
            4375 => Some(GarminProduct::Fenix7ProSolar),
            4376 => Some(GarminProduct::Fenix7xProSolar),
            4380 => Some(GarminProduct::Lily2),
            4394 => Some(GarminProduct::Instinct2x),
            4426 => Some(GarminProduct::Vivoactive5),
            4432 => Some(GarminProduct::Fr165),
            4433 => Some(GarminProduct::Fr165Music),
            4440 => Some(GarminProduct::Edge1050),
            4442 => Some(GarminProduct::DescentT2),
            4446 => Some(GarminProduct::HrmFit),
            4472 => Some(GarminProduct::MarqGen2Commander),
            4477 => Some(GarminProduct::LilyAthlete),
            4525 => Some(GarminProduct::RallyX10),
            4532 => Some(GarminProduct::Fenix8Solar),
            4533 => Some(GarminProduct::Fenix8SolarLarge),
            4534 => Some(GarminProduct::Fenix8Small),
            4536 => Some(GarminProduct::Fenix8),
            4556 => Some(GarminProduct::D2Mach1Pro),
            4575 => Some(GarminProduct::Enduro3),
            4583 => Some(GarminProduct::InstinctE40mm),
            4584 => Some(GarminProduct::InstinctE45mm),
            4585 => Some(GarminProduct::Instinct3Solar45mm),
            4586 => Some(GarminProduct::Instinct3Amoled45mm),
            4587 => Some(GarminProduct::Instinct3Amoled50mm),
            4588 => Some(GarminProduct::DescentG2),
            4603 => Some(GarminProduct::VenuX1),
            4606 => Some(GarminProduct::Hrm200),
            4625 => Some(GarminProduct::Vivoactive6),
            4631 => Some(GarminProduct::Fenix8Pro),
            4633 => Some(GarminProduct::Edge550),
            4634 => Some(GarminProduct::Edge850),
            4643 => Some(GarminProduct::Venu4),
            4644 => Some(GarminProduct::Venu4s),
            4647 => Some(GarminProduct::ApproachS44),
            4655 => Some(GarminProduct::EdgeMtb),
            4656 => Some(GarminProduct::ApproachS50),
            4666 => Some(GarminProduct::FenixE),
            4745 => Some(GarminProduct::Bounce2),
            4759 => Some(GarminProduct::Instinct3Solar50mm),
            4775 => Some(GarminProduct::Tactix8Amoled),
            4776 => Some(GarminProduct::Tactix8Solar),
            4825 => Some(GarminProduct::ApproachJ1),
            4879 => Some(GarminProduct::D2Mach2),
            4678 => Some(GarminProduct::InstinctCrossoverAmoled),
            4944 => Some(GarminProduct::D2AirX15),
            10007 => Some(GarminProduct::Sdm4),
            10014 => Some(GarminProduct::EdgeRemote),
            20533 => Some(GarminProduct::TacxTrainingAppWin),
            20534 => Some(GarminProduct::TacxTrainingAppMac),
            20565 => Some(GarminProduct::TacxTrainingAppMacCatalyst),
            20119 => Some(GarminProduct::TrainingCenter),
            30045 => Some(GarminProduct::TacxTrainingAppAndroid),
            30046 => Some(GarminProduct::TacxTrainingAppIos),
            30047 => Some(GarminProduct::TacxTrainingAppLegacy),
            65531 => Some(GarminProduct::ConnectiqSimulator),
            65532 => Some(GarminProduct::AndroidAntplusPlugin),
            65534 => Some(GarminProduct::Connect),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "hrm1" => Some(GarminProduct::Hrm1),
            "axh01" => Some(GarminProduct::Axh01),
            "axb01" => Some(GarminProduct::Axb01),
            "axb02" => Some(GarminProduct::Axb02),
            "hrm2ss" => Some(GarminProduct::Hrm2ss),
            "dsi_alf02" => Some(GarminProduct::DsiAlf02),
            "hrm3ss" => Some(GarminProduct::Hrm3ss),
            "hrm_run_single_byte_product_id" => Some(GarminProduct::HrmRunSingleByteProductId),
            "bsm" => Some(GarminProduct::Bsm),
            "bcm" => Some(GarminProduct::Bcm),
            "axs01" => Some(GarminProduct::Axs01),
            "hrm_tri_single_byte_product_id" => Some(GarminProduct::HrmTriSingleByteProductId),
            "hrm4_run_single_byte_product_id" => Some(GarminProduct::Hrm4RunSingleByteProductId),
            "fr225_single_byte_product_id" => Some(GarminProduct::Fr225SingleByteProductId),
            "gen3_bsm_single_byte_product_id" => Some(GarminProduct::Gen3BsmSingleByteProductId),
            "gen3_bcm_single_byte_product_id" => Some(GarminProduct::Gen3BcmSingleByteProductId),
            "hrm_fit_single_byte_product_id" => Some(GarminProduct::HrmFitSingleByteProductId),
            "OHR" => Some(GarminProduct::OHR),
            "fr301_china" => Some(GarminProduct::Fr301China),
            "fr301_japan" => Some(GarminProduct::Fr301Japan),
            "fr301_korea" => Some(GarminProduct::Fr301Korea),
            "fr301_taiwan" => Some(GarminProduct::Fr301Taiwan),
            "fr405" => Some(GarminProduct::Fr405),
            "fr50" => Some(GarminProduct::Fr50),
            "fr405_japan" => Some(GarminProduct::Fr405Japan),
            "fr60" => Some(GarminProduct::Fr60),
            "dsi_alf01" => Some(GarminProduct::DsiAlf01),
            "fr310xt" => Some(GarminProduct::Fr310xt),
            "edge500" => Some(GarminProduct::Edge500),
            "fr110" => Some(GarminProduct::Fr110),
            "edge800" => Some(GarminProduct::Edge800),
            "edge500_taiwan" => Some(GarminProduct::Edge500Taiwan),
            "edge500_japan" => Some(GarminProduct::Edge500Japan),
            "chirp" => Some(GarminProduct::Chirp),
            "fr110_japan" => Some(GarminProduct::Fr110Japan),
            "edge200" => Some(GarminProduct::Edge200),
            "fr910xt" => Some(GarminProduct::Fr910xt),
            "edge800_taiwan" => Some(GarminProduct::Edge800Taiwan),
            "edge800_japan" => Some(GarminProduct::Edge800Japan),
            "alf04" => Some(GarminProduct::Alf04),
            "fr610" => Some(GarminProduct::Fr610),
            "fr210_japan" => Some(GarminProduct::Fr210Japan),
            "vector_ss" => Some(GarminProduct::VectorSs),
            "vector_cp" => Some(GarminProduct::VectorCp),
            "edge800_china" => Some(GarminProduct::Edge800China),
            "edge500_china" => Some(GarminProduct::Edge500China),
            "approach_g10" => Some(GarminProduct::ApproachG10),
            "fr610_japan" => Some(GarminProduct::Fr610Japan),
            "edge500_korea" => Some(GarminProduct::Edge500Korea),
            "fr70" => Some(GarminProduct::Fr70),
            "fr310xt_4t" => Some(GarminProduct::Fr310xt4t),
            "amx" => Some(GarminProduct::Amx),
            "fr10" => Some(GarminProduct::Fr10),
            "edge800_korea" => Some(GarminProduct::Edge800Korea),
            "swim" => Some(GarminProduct::Swim),
            "fr910xt_china" => Some(GarminProduct::Fr910xtChina),
            "fenix" => Some(GarminProduct::Fenix),
            "edge200_taiwan" => Some(GarminProduct::Edge200Taiwan),
            "edge510" => Some(GarminProduct::Edge510),
            "edge810" => Some(GarminProduct::Edge810),
            "tempe" => Some(GarminProduct::Tempe),
            "fr910xt_japan" => Some(GarminProduct::Fr910xtJapan),
            "fr620" => Some(GarminProduct::Fr620),
            "fr220" => Some(GarminProduct::Fr220),
            "fr910xt_korea" => Some(GarminProduct::Fr910xtKorea),
            "fr10_japan" => Some(GarminProduct::Fr10Japan),
            "edge810_japan" => Some(GarminProduct::Edge810Japan),
            "virb_elite" => Some(GarminProduct::VirbElite),
            "edge_touring" => Some(GarminProduct::EdgeTouring),
            "edge510_japan" => Some(GarminProduct::Edge510Japan),
            "hrm_tri" => Some(GarminProduct::HrmTri),
            "hrm_run" => Some(GarminProduct::HrmRun),
            "fr920xt" => Some(GarminProduct::Fr920xt),
            "edge510_asia" => Some(GarminProduct::Edge510Asia),
            "edge810_china" => Some(GarminProduct::Edge810China),
            "edge810_taiwan" => Some(GarminProduct::Edge810Taiwan),
            "edge1000" => Some(GarminProduct::Edge1000),
            "vivo_fit" => Some(GarminProduct::VivoFit),
            "virb_remote" => Some(GarminProduct::VirbRemote),
            "vivo_ki" => Some(GarminProduct::VivoKi),
            "fr15" => Some(GarminProduct::Fr15),
            "vivo_active" => Some(GarminProduct::VivoActive),
            "edge510_korea" => Some(GarminProduct::Edge510Korea),
            "fr620_japan" => Some(GarminProduct::Fr620Japan),
            "fr620_china" => Some(GarminProduct::Fr620China),
            "fr220_japan" => Some(GarminProduct::Fr220Japan),
            "fr220_china" => Some(GarminProduct::Fr220China),
            "approach_s6" => Some(GarminProduct::ApproachS6),
            "vivo_smart" => Some(GarminProduct::VivoSmart),
            "fenix2" => Some(GarminProduct::Fenix2),
            "epix" => Some(GarminProduct::Epix),
            "fenix3" => Some(GarminProduct::Fenix3),
            "edge1000_taiwan" => Some(GarminProduct::Edge1000Taiwan),
            "edge1000_japan" => Some(GarminProduct::Edge1000Japan),
            "fr15_japan" => Some(GarminProduct::Fr15Japan),
            "edge520" => Some(GarminProduct::Edge520),
            "edge1000_china" => Some(GarminProduct::Edge1000China),
            "fr620_russia" => Some(GarminProduct::Fr620Russia),
            "fr220_russia" => Some(GarminProduct::Fr220Russia),
            "vector_s" => Some(GarminProduct::VectorS),
            "edge1000_korea" => Some(GarminProduct::Edge1000Korea),
            "fr920xt_taiwan" => Some(GarminProduct::Fr920xtTaiwan),
            "fr920xt_china" => Some(GarminProduct::Fr920xtChina),
            "fr920xt_japan" => Some(GarminProduct::Fr920xtJapan),
            "virbx" => Some(GarminProduct::Virbx),
            "vivo_smart_apac" => Some(GarminProduct::VivoSmartApac),
            "etrex_touch" => Some(GarminProduct::EtrexTouch),
            "edge25" => Some(GarminProduct::Edge25),
            "fr25" => Some(GarminProduct::Fr25),
            "vivo_fit2" => Some(GarminProduct::VivoFit2),
            "fr225" => Some(GarminProduct::Fr225),
            "fr630" => Some(GarminProduct::Fr630),
            "fr230" => Some(GarminProduct::Fr230),
            "fr735xt" => Some(GarminProduct::Fr735xt),
            "vivo_active_apac" => Some(GarminProduct::VivoActiveApac),
            "vector_2" => Some(GarminProduct::Vector2),
            "vector_2s" => Some(GarminProduct::Vector2s),
            "virbxe" => Some(GarminProduct::Virbxe),
            "fr620_taiwan" => Some(GarminProduct::Fr620Taiwan),
            "fr220_taiwan" => Some(GarminProduct::Fr220Taiwan),
            "truswing" => Some(GarminProduct::Truswing),
            "d2airvenu" => Some(GarminProduct::D2airvenu),
            "fenix3_china" => Some(GarminProduct::Fenix3China),
            "fenix3_twn" => Some(GarminProduct::Fenix3Twn),
            "varia_headlight" => Some(GarminProduct::VariaHeadlight),
            "varia_taillight_old" => Some(GarminProduct::VariaTaillightOld),
            "edge_explore_1000" => Some(GarminProduct::EdgeExplore1000),
            "fr225_asia" => Some(GarminProduct::Fr225Asia),
            "varia_radar_taillight" => Some(GarminProduct::VariaRadarTaillight),
            "varia_radar_display" => Some(GarminProduct::VariaRadarDisplay),
            "edge20" => Some(GarminProduct::Edge20),
            "edge520_asia" => Some(GarminProduct::Edge520Asia),
            "edge520_japan" => Some(GarminProduct::Edge520Japan),
            "d2_bravo" => Some(GarminProduct::D2Bravo),
            "approach_s20" => Some(GarminProduct::ApproachS20),
            "vivo_smart2" => Some(GarminProduct::VivoSmart2),
            "edge1000_thai" => Some(GarminProduct::Edge1000Thai),
            "varia_remote" => Some(GarminProduct::VariaRemote),
            "edge25_asia" => Some(GarminProduct::Edge25Asia),
            "edge25_jpn" => Some(GarminProduct::Edge25Jpn),
            "edge20_asia" => Some(GarminProduct::Edge20Asia),
            "approach_x40" => Some(GarminProduct::ApproachX40),
            "fenix3_japan" => Some(GarminProduct::Fenix3Japan),
            "vivo_smart_emea" => Some(GarminProduct::VivoSmartEmea),
            "fr630_asia" => Some(GarminProduct::Fr630Asia),
            "fr630_jpn" => Some(GarminProduct::Fr630Jpn),
            "fr230_jpn" => Some(GarminProduct::Fr230Jpn),
            "hrm4_run" => Some(GarminProduct::Hrm4Run),
            "epix_japan" => Some(GarminProduct::EpixJapan),
            "vivo_active_hr" => Some(GarminProduct::VivoActiveHr),
            "vivo_smart_gps_hr" => Some(GarminProduct::VivoSmartGpsHr),
            "vivo_smart_hr" => Some(GarminProduct::VivoSmartHr),
            "vivo_smart_hr_asia" => Some(GarminProduct::VivoSmartHrAsia),
            "vivo_smart_gps_hr_asia" => Some(GarminProduct::VivoSmartGpsHrAsia),
            "vivo_move" => Some(GarminProduct::VivoMove),
            "varia_taillight" => Some(GarminProduct::VariaTaillight),
            "fr235_asia" => Some(GarminProduct::Fr235Asia),
            "fr235_japan" => Some(GarminProduct::Fr235Japan),
            "varia_vision" => Some(GarminProduct::VariaVision),
            "vivo_fit3" => Some(GarminProduct::VivoFit3),
            "fenix3_korea" => Some(GarminProduct::Fenix3Korea),
            "fenix3_sea" => Some(GarminProduct::Fenix3Sea),
            "fenix3_hr" => Some(GarminProduct::Fenix3Hr),
            "virb_ultra_30" => Some(GarminProduct::VirbUltra30),
            "index_smart_scale" => Some(GarminProduct::IndexSmartScale),
            "fr235" => Some(GarminProduct::Fr235),
            "fenix3_chronos" => Some(GarminProduct::Fenix3Chronos),
            "oregon7xx" => Some(GarminProduct::Oregon7xx),
            "rino7xx" => Some(GarminProduct::Rino7xx),
            "epix_korea" => Some(GarminProduct::EpixKorea),
            "fenix3_hr_chn" => Some(GarminProduct::Fenix3HrChn),
            "fenix3_hr_twn" => Some(GarminProduct::Fenix3HrTwn),
            "fenix3_hr_jpn" => Some(GarminProduct::Fenix3HrJpn),
            "fenix3_hr_sea" => Some(GarminProduct::Fenix3HrSea),
            "fenix3_hr_kor" => Some(GarminProduct::Fenix3HrKor),
            "nautix" => Some(GarminProduct::Nautix),
            "vivo_active_hr_apac" => Some(GarminProduct::VivoActiveHrApac),
            "fr35" => Some(GarminProduct::Fr35),
            "oregon7xx_ww" => Some(GarminProduct::Oregon7xxWw),
            "edge_820" => Some(GarminProduct::Edge820),
            "edge_explore_820" => Some(GarminProduct::EdgeExplore820),
            "fr735xt_apac" => Some(GarminProduct::Fr735xtApac),
            "fr735xt_japan" => Some(GarminProduct::Fr735xtJapan),
            "fenix5s" => Some(GarminProduct::Fenix5s),
            "d2_bravo_titanium" => Some(GarminProduct::D2BravoTitanium),
            "varia_ut800" => Some(GarminProduct::VariaUt800),
            "running_dynamics_pod" => Some(GarminProduct::RunningDynamicsPod),
            "edge_820_china" => Some(GarminProduct::Edge820China),
            "edge_820_japan" => Some(GarminProduct::Edge820Japan),
            "fenix5x" => Some(GarminProduct::Fenix5x),
            "vivo_fit_jr" => Some(GarminProduct::VivoFitJr),
            "vivo_smart3" => Some(GarminProduct::VivoSmart3),
            "vivo_sport" => Some(GarminProduct::VivoSport),
            "edge_820_taiwan" => Some(GarminProduct::Edge820Taiwan),
            "edge_820_korea" => Some(GarminProduct::Edge820Korea),
            "edge_820_sea" => Some(GarminProduct::Edge820Sea),
            "fr35_hebrew" => Some(GarminProduct::Fr35Hebrew),
            "approach_s60" => Some(GarminProduct::ApproachS60),
            "fr35_apac" => Some(GarminProduct::Fr35Apac),
            "fr35_japan" => Some(GarminProduct::Fr35Japan),
            "fenix3_chronos_asia" => Some(GarminProduct::Fenix3ChronosAsia),
            "virb_360" => Some(GarminProduct::Virb360),
            "fr935" => Some(GarminProduct::Fr935),
            "fenix5" => Some(GarminProduct::Fenix5),
            "vivoactive3" => Some(GarminProduct::Vivoactive3),
            "fr235_china_nfc" => Some(GarminProduct::Fr235ChinaNfc),
            "foretrex_601_701" => Some(GarminProduct::Foretrex601701),
            "vivo_move_hr" => Some(GarminProduct::VivoMoveHr),
            "edge_1030" => Some(GarminProduct::Edge1030),
            "fr35_sea" => Some(GarminProduct::Fr35Sea),
            "vector_3" => Some(GarminProduct::Vector3),
            "fenix5_asia" => Some(GarminProduct::Fenix5Asia),
            "fenix5s_asia" => Some(GarminProduct::Fenix5sAsia),
            "fenix5x_asia" => Some(GarminProduct::Fenix5xAsia),
            "approach_z80" => Some(GarminProduct::ApproachZ80),
            "fr35_korea" => Some(GarminProduct::Fr35Korea),
            "d2charlie" => Some(GarminProduct::D2charlie),
            "vivo_smart3_apac" => Some(GarminProduct::VivoSmart3Apac),
            "vivo_sport_apac" => Some(GarminProduct::VivoSportApac),
            "fr935_asia" => Some(GarminProduct::Fr935Asia),
            "descent" => Some(GarminProduct::Descent),
            "vivo_fit4" => Some(GarminProduct::VivoFit4),
            "fr645" => Some(GarminProduct::Fr645),
            "fr645m" => Some(GarminProduct::Fr645m),
            "fr30" => Some(GarminProduct::Fr30),
            "fenix5s_plus" => Some(GarminProduct::Fenix5sPlus),
            "Edge_130" => Some(GarminProduct::Edge130),
            "edge_1030_asia" => Some(GarminProduct::Edge1030Asia),
            "vivosmart_4" => Some(GarminProduct::Vivosmart4),
            "vivo_move_hr_asia" => Some(GarminProduct::VivoMoveHrAsia),
            "approach_x10" => Some(GarminProduct::ApproachX10),
            "fr30_asia" => Some(GarminProduct::Fr30Asia),
            "vivoactive3m_w" => Some(GarminProduct::Vivoactive3mW),
            "fr645_asia" => Some(GarminProduct::Fr645Asia),
            "fr645m_asia" => Some(GarminProduct::Fr645mAsia),
            "edge_explore" => Some(GarminProduct::EdgeExplore),
            "gpsmap66" => Some(GarminProduct::Gpsmap66),
            "approach_s10" => Some(GarminProduct::ApproachS10),
            "vivoactive3m_l" => Some(GarminProduct::Vivoactive3mL),
            "fr245" => Some(GarminProduct::Fr245),
            "fr245_music" => Some(GarminProduct::Fr245Music),
            "approach_g80" => Some(GarminProduct::ApproachG80),
            "edge_130_asia" => Some(GarminProduct::Edge130Asia),
            "edge_1030_bontrager" => Some(GarminProduct::Edge1030Bontrager),
            "fenix5_plus" => Some(GarminProduct::Fenix5Plus),
            "fenix5x_plus" => Some(GarminProduct::Fenix5xPlus),
            "edge_520_plus" => Some(GarminProduct::Edge520Plus),
            "fr945" => Some(GarminProduct::Fr945),
            "edge_530" => Some(GarminProduct::Edge530),
            "edge_830" => Some(GarminProduct::Edge830),
            "instinct_esports" => Some(GarminProduct::InstinctEsports),
            "fenix5s_plus_apac" => Some(GarminProduct::Fenix5sPlusApac),
            "fenix5x_plus_apac" => Some(GarminProduct::Fenix5xPlusApac),
            "edge_520_plus_apac" => Some(GarminProduct::Edge520PlusApac),
            "descent_t1" => Some(GarminProduct::DescentT1),
            "fr235l_asia" => Some(GarminProduct::Fr235lAsia),
            "fr245_asia" => Some(GarminProduct::Fr245Asia),
            "vivo_active3m_apac" => Some(GarminProduct::VivoActive3mApac),
            "gen3_bsm" => Some(GarminProduct::Gen3Bsm),
            "gen3_bcm" => Some(GarminProduct::Gen3Bcm),
            "vivo_smart4_asia" => Some(GarminProduct::VivoSmart4Asia),
            "vivoactive4_small" => Some(GarminProduct::Vivoactive4Small),
            "vivoactive4_large" => Some(GarminProduct::Vivoactive4Large),
            "venu" => Some(GarminProduct::Venu),
            "marq_driver" => Some(GarminProduct::MarqDriver),
            "marq_aviator" => Some(GarminProduct::MarqAviator),
            "marq_captain" => Some(GarminProduct::MarqCaptain),
            "marq_commander" => Some(GarminProduct::MarqCommander),
            "marq_expedition" => Some(GarminProduct::MarqExpedition),
            "marq_athlete" => Some(GarminProduct::MarqAthlete),
            "descent_mk2" => Some(GarminProduct::DescentMk2),
            "fr45" => Some(GarminProduct::Fr45),
            "gpsmap66i" => Some(GarminProduct::Gpsmap66i),
            "fenix6S_sport" => Some(GarminProduct::Fenix6SSport),
            "fenix6S" => Some(GarminProduct::Fenix6S),
            "fenix6_sport" => Some(GarminProduct::Fenix6Sport),
            "fenix6" => Some(GarminProduct::Fenix6),
            "fenix6x" => Some(GarminProduct::Fenix6x),
            "hrm_dual" => Some(GarminProduct::HrmDual),
            "hrm_pro" => Some(GarminProduct::HrmPro),
            "vivo_move3_premium" => Some(GarminProduct::VivoMove3Premium),
            "approach_s40" => Some(GarminProduct::ApproachS40),
            "fr245m_asia" => Some(GarminProduct::Fr245mAsia),
            "edge_530_apac" => Some(GarminProduct::Edge530Apac),
            "edge_830_apac" => Some(GarminProduct::Edge830Apac),
            "vivo_move3" => Some(GarminProduct::VivoMove3),
            "vivo_active4_small_asia" => Some(GarminProduct::VivoActive4SmallAsia),
            "vivo_active4_large_asia" => Some(GarminProduct::VivoActive4LargeAsia),
            "vivo_active4_oled_asia" => Some(GarminProduct::VivoActive4OledAsia),
            "swim2" => Some(GarminProduct::Swim2),
            "marq_driver_asia" => Some(GarminProduct::MarqDriverAsia),
            "marq_aviator_asia" => Some(GarminProduct::MarqAviatorAsia),
            "vivo_move3_asia" => Some(GarminProduct::VivoMove3Asia),
            "fr945_asia" => Some(GarminProduct::Fr945Asia),
            "vivo_active3t_chn" => Some(GarminProduct::VivoActive3tChn),
            "marq_captain_asia" => Some(GarminProduct::MarqCaptainAsia),
            "marq_commander_asia" => Some(GarminProduct::MarqCommanderAsia),
            "marq_expedition_asia" => Some(GarminProduct::MarqExpeditionAsia),
            "marq_athlete_asia" => Some(GarminProduct::MarqAthleteAsia),
            "index_smart_scale_2" => Some(GarminProduct::IndexSmartScale2),
            "instinct_solar" => Some(GarminProduct::InstinctSolar),
            "fr45_asia" => Some(GarminProduct::Fr45Asia),
            "vivoactive3_daimler" => Some(GarminProduct::Vivoactive3Daimler),
            "legacy_rey" => Some(GarminProduct::LegacyRey),
            "legacy_darth_vader" => Some(GarminProduct::LegacyDarthVader),
            "legacy_captain_marvel" => Some(GarminProduct::LegacyCaptainMarvel),
            "legacy_first_avenger" => Some(GarminProduct::LegacyFirstAvenger),
            "fenix6s_sport_asia" => Some(GarminProduct::Fenix6sSportAsia),
            "fenix6s_asia" => Some(GarminProduct::Fenix6sAsia),
            "fenix6_sport_asia" => Some(GarminProduct::Fenix6SportAsia),
            "fenix6_asia" => Some(GarminProduct::Fenix6Asia),
            "fenix6x_asia" => Some(GarminProduct::Fenix6xAsia),
            "legacy_captain_marvel_asia" => Some(GarminProduct::LegacyCaptainMarvelAsia),
            "legacy_first_avenger_asia" => Some(GarminProduct::LegacyFirstAvengerAsia),
            "legacy_rey_asia" => Some(GarminProduct::LegacyReyAsia),
            "legacy_darth_vader_asia" => Some(GarminProduct::LegacyDarthVaderAsia),
            "descent_mk2s" => Some(GarminProduct::DescentMk2s),
            "edge_130_plus" => Some(GarminProduct::Edge130Plus),
            "edge_1030_plus" => Some(GarminProduct::Edge1030Plus),
            "rally_200" => Some(GarminProduct::Rally200),
            "fr745" => Some(GarminProduct::Fr745),
            "venusq_music" => Some(GarminProduct::VenusqMusic),
            "venusq_music_v2" => Some(GarminProduct::VenusqMusicV2),
            "venusq" => Some(GarminProduct::Venusq),
            "lily" => Some(GarminProduct::Lily),
            "marq_adventurer" => Some(GarminProduct::MarqAdventurer),
            "enduro" => Some(GarminProduct::Enduro),
            "swim2_apac" => Some(GarminProduct::Swim2Apac),
            "marq_adventurer_asia" => Some(GarminProduct::MarqAdventurerAsia),
            "fr945_lte" => Some(GarminProduct::Fr945Lte),
            "descent_mk2_asia" => Some(GarminProduct::DescentMk2Asia),
            "venu2" => Some(GarminProduct::Venu2),
            "venu2s" => Some(GarminProduct::Venu2s),
            "venu_daimler_asia" => Some(GarminProduct::VenuDaimlerAsia),
            "marq_golfer" => Some(GarminProduct::MarqGolfer),
            "venu_daimler" => Some(GarminProduct::VenuDaimler),
            "fr745_asia" => Some(GarminProduct::Fr745Asia),
            "varia_rct715" => Some(GarminProduct::VariaRct715),
            "lily_asia" => Some(GarminProduct::LilyAsia),
            "edge_1030_plus_asia" => Some(GarminProduct::Edge1030PlusAsia),
            "edge_130_plus_asia" => Some(GarminProduct::Edge130PlusAsia),
            "approach_s12" => Some(GarminProduct::ApproachS12),
            "enduro_asia" => Some(GarminProduct::EnduroAsia),
            "venusq_asia" => Some(GarminProduct::VenusqAsia),
            "edge_1040" => Some(GarminProduct::Edge1040),
            "marq_golfer_asia" => Some(GarminProduct::MarqGolferAsia),
            "venu2_plus" => Some(GarminProduct::Venu2Plus),
            "gnss" => Some(GarminProduct::Gnss),
            "fr55" => Some(GarminProduct::Fr55),
            "instinct_2" => Some(GarminProduct::Instinct2),
            "instinct_2s" => Some(GarminProduct::Instinct2s),
            "fenix7s" => Some(GarminProduct::Fenix7s),
            "fenix7" => Some(GarminProduct::Fenix7),
            "fenix7x" => Some(GarminProduct::Fenix7x),
            "fenix7s_apac" => Some(GarminProduct::Fenix7sApac),
            "fenix7_apac" => Some(GarminProduct::Fenix7Apac),
            "fenix7x_apac" => Some(GarminProduct::Fenix7xApac),
            "approach_g12" => Some(GarminProduct::ApproachG12),
            "descent_mk2s_asia" => Some(GarminProduct::DescentMk2sAsia),
            "approach_s42" => Some(GarminProduct::ApproachS42),
            "epix_gen2" => Some(GarminProduct::EpixGen2),
            "epix_gen2_apac" => Some(GarminProduct::EpixGen2Apac),
            "venu2s_asia" => Some(GarminProduct::Venu2sAsia),
            "venu2_asia" => Some(GarminProduct::Venu2Asia),
            "fr945_lte_asia" => Some(GarminProduct::Fr945LteAsia),
            "vivo_move_sport" => Some(GarminProduct::VivoMoveSport),
            "vivomove_trend" => Some(GarminProduct::VivomoveTrend),
            "approach_S12_asia" => Some(GarminProduct::ApproachS12Asia),
            "fr255_music" => Some(GarminProduct::Fr255Music),
            "fr255_small_music" => Some(GarminProduct::Fr255SmallMusic),
            "fr255" => Some(GarminProduct::Fr255),
            "fr255_small" => Some(GarminProduct::Fr255Small),
            "approach_g12_asia" => Some(GarminProduct::ApproachG12Asia),
            "approach_s42_asia" => Some(GarminProduct::ApproachS42Asia),
            "descent_g1" => Some(GarminProduct::DescentG1),
            "venu2_plus_asia" => Some(GarminProduct::Venu2PlusAsia),
            "fr955" => Some(GarminProduct::Fr955),
            "fr55_asia" => Some(GarminProduct::Fr55Asia),
            "edge_540" => Some(GarminProduct::Edge540),
            "edge_840" => Some(GarminProduct::Edge840),
            "vivosmart_5" => Some(GarminProduct::Vivosmart5),
            "instinct_2_asia" => Some(GarminProduct::Instinct2Asia),
            "marq_gen2" => Some(GarminProduct::MarqGen2),
            "venusq2" => Some(GarminProduct::Venusq2),
            "venusq2music" => Some(GarminProduct::Venusq2music),
            "marq_gen2_aviator" => Some(GarminProduct::MarqGen2Aviator),
            "d2_air_x10" => Some(GarminProduct::D2AirX10),
            "hrm_pro_plus" => Some(GarminProduct::HrmProPlus),
            "descent_g1_asia" => Some(GarminProduct::DescentG1Asia),
            "tactix7" => Some(GarminProduct::Tactix7),
            "instinct_crossover" => Some(GarminProduct::InstinctCrossover),
            "edge_explore2" => Some(GarminProduct::EdgeExplore2),
            "descent_mk3" => Some(GarminProduct::DescentMk3),
            "descent_mk3i" => Some(GarminProduct::DescentMk3i),
            "approach_s70" => Some(GarminProduct::ApproachS70),
            "fr265_large" => Some(GarminProduct::Fr265Large),
            "fr265_small" => Some(GarminProduct::Fr265Small),
            "venu3" => Some(GarminProduct::Venu3),
            "venu3s" => Some(GarminProduct::Venu3s),
            "tacx_neo_smart" => Some(GarminProduct::TacxNeoSmart),
            "tacx_neo2_smart" => Some(GarminProduct::TacxNeo2Smart),
            "tacx_neo2_t_smart" => Some(GarminProduct::TacxNeo2TSmart),
            "tacx_neo_smart_bike" => Some(GarminProduct::TacxNeoSmartBike),
            "tacx_satori_smart" => Some(GarminProduct::TacxSatoriSmart),
            "tacx_flow_smart" => Some(GarminProduct::TacxFlowSmart),
            "tacx_vortex_smart" => Some(GarminProduct::TacxVortexSmart),
            "tacx_bushido_smart" => Some(GarminProduct::TacxBushidoSmart),
            "tacx_genius_smart" => Some(GarminProduct::TacxGeniusSmart),
            "tacx_flux_flux_s_smart" => Some(GarminProduct::TacxFluxFluxSSmart),
            "tacx_flux2_smart" => Some(GarminProduct::TacxFlux2Smart),
            "tacx_magnum" => Some(GarminProduct::TacxMagnum),
            "edge_1040_asia" => Some(GarminProduct::Edge1040Asia),
            "epix_gen2_pro_42" => Some(GarminProduct::EpixGen2Pro42),
            "epix_gen2_pro_47" => Some(GarminProduct::EpixGen2Pro47),
            "epix_gen2_pro_51" => Some(GarminProduct::EpixGen2Pro51),
            "fr965" => Some(GarminProduct::Fr965),
            "enduro2" => Some(GarminProduct::Enduro2),
            "fenix7s_pro_solar" => Some(GarminProduct::Fenix7sProSolar),
            "fenix7_pro_solar" => Some(GarminProduct::Fenix7ProSolar),
            "fenix7x_pro_solar" => Some(GarminProduct::Fenix7xProSolar),
            "lily2" => Some(GarminProduct::Lily2),
            "instinct_2x" => Some(GarminProduct::Instinct2x),
            "vivoactive5" => Some(GarminProduct::Vivoactive5),
            "fr165" => Some(GarminProduct::Fr165),
            "fr165_music" => Some(GarminProduct::Fr165Music),
            "edge_1050" => Some(GarminProduct::Edge1050),
            "descent_t2" => Some(GarminProduct::DescentT2),
            "hrm_fit" => Some(GarminProduct::HrmFit),
            "marq_gen2_commander" => Some(GarminProduct::MarqGen2Commander),
            "lily_athlete" => Some(GarminProduct::LilyAthlete),
            "rally_x10" => Some(GarminProduct::RallyX10),
            "fenix8_solar" => Some(GarminProduct::Fenix8Solar),
            "fenix8_solar_large" => Some(GarminProduct::Fenix8SolarLarge),
            "fenix8_small" => Some(GarminProduct::Fenix8Small),
            "fenix8" => Some(GarminProduct::Fenix8),
            "d2_mach1_pro" => Some(GarminProduct::D2Mach1Pro),
            "enduro3" => Some(GarminProduct::Enduro3),
            "instinctE_40mm" => Some(GarminProduct::InstinctE40mm),
            "instinctE_45mm" => Some(GarminProduct::InstinctE45mm),
            "instinct3_solar_45mm" => Some(GarminProduct::Instinct3Solar45mm),
            "instinct3_amoled_45mm" => Some(GarminProduct::Instinct3Amoled45mm),
            "instinct3_amoled_50mm" => Some(GarminProduct::Instinct3Amoled50mm),
            "descent_g2" => Some(GarminProduct::DescentG2),
            "venu_x1" => Some(GarminProduct::VenuX1),
            "hrm_200" => Some(GarminProduct::Hrm200),
            "vivoactive6" => Some(GarminProduct::Vivoactive6),
            "fenix8_pro" => Some(GarminProduct::Fenix8Pro),
            "edge_550" => Some(GarminProduct::Edge550),
            "edge_850" => Some(GarminProduct::Edge850),
            "venu4" => Some(GarminProduct::Venu4),
            "venu4s" => Some(GarminProduct::Venu4s),
            "approachS44" => Some(GarminProduct::ApproachS44),
            "edge_mtb" => Some(GarminProduct::EdgeMtb),
            "approachS50" => Some(GarminProduct::ApproachS50),
            "fenix_e" => Some(GarminProduct::FenixE),
            "bounce2" => Some(GarminProduct::Bounce2),
            "instinct3_solar_50mm" => Some(GarminProduct::Instinct3Solar50mm),
            "tactix8_amoled" => Some(GarminProduct::Tactix8Amoled),
            "tactix8_solar" => Some(GarminProduct::Tactix8Solar),
            "approach_j1" => Some(GarminProduct::ApproachJ1),
            "d2_mach2" => Some(GarminProduct::D2Mach2),
            "instinct_crossover_amoled" => Some(GarminProduct::InstinctCrossoverAmoled),
            "d2_air_x15" => Some(GarminProduct::D2AirX15),
            "sdm4" => Some(GarminProduct::Sdm4),
            "edge_remote" => Some(GarminProduct::EdgeRemote),
            "tacx_training_app_win" => Some(GarminProduct::TacxTrainingAppWin),
            "tacx_training_app_mac" => Some(GarminProduct::TacxTrainingAppMac),
            "tacx_training_app_mac_catalyst" => Some(GarminProduct::TacxTrainingAppMacCatalyst),
            "training_center" => Some(GarminProduct::TrainingCenter),
            "tacx_training_app_android" => Some(GarminProduct::TacxTrainingAppAndroid),
            "tacx_training_app_ios" => Some(GarminProduct::TacxTrainingAppIos),
            "tacx_training_app_legacy" => Some(GarminProduct::TacxTrainingAppLegacy),
            "connectiq_simulator" => Some(GarminProduct::ConnectiqSimulator),
            "android_antplus_plugin" => Some(GarminProduct::AndroidAntplusPlugin),
            "connect" => Some(GarminProduct::Connect),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum AntplusDeviceType {
    Antfs = 1,
    BikePower = 11,
    EnvironmentSensorLegacy = 12,
    MultiSportSpeedDistance = 15,
    Control = 16,
    FitnessEquipment = 17,
    BloodPressure = 18,
    GeocacheNode = 19,
    LightElectricVehicle = 20,
    EnvSensor = 25,
    Racquet = 26,
    ControlHub = 27,
    MuscleOxygen = 31,
    Shifting = 34,
    BikeLightMain = 35,
    BikeLightShared = 36,
    Exd = 38,
    BikeRadar = 40,
    BikeAero = 46,
    WeightScale = 119,
    HeartRate = 120,
    BikeSpeedCadence = 121,
    BikeCadence = 122,
    BikeSpeed = 123,
    StrideSpeedDistance = 124,
}

impl AntplusDeviceType {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            AntplusDeviceType::Antfs => "antfs",
            AntplusDeviceType::BikePower => "bike_power",
            AntplusDeviceType::EnvironmentSensorLegacy => "environment_sensor_legacy",
            AntplusDeviceType::MultiSportSpeedDistance => "multi_sport_speed_distance",
            AntplusDeviceType::Control => "control",
            AntplusDeviceType::FitnessEquipment => "fitness_equipment",
            AntplusDeviceType::BloodPressure => "blood_pressure",
            AntplusDeviceType::GeocacheNode => "geocache_node",
            AntplusDeviceType::LightElectricVehicle => "light_electric_vehicle",
            AntplusDeviceType::EnvSensor => "env_sensor",
            AntplusDeviceType::Racquet => "racquet",
            AntplusDeviceType::ControlHub => "control_hub",
            AntplusDeviceType::MuscleOxygen => "muscle_oxygen",
            AntplusDeviceType::Shifting => "shifting",
            AntplusDeviceType::BikeLightMain => "bike_light_main",
            AntplusDeviceType::BikeLightShared => "bike_light_shared",
            AntplusDeviceType::Exd => "exd",
            AntplusDeviceType::BikeRadar => "bike_radar",
            AntplusDeviceType::BikeAero => "bike_aero",
            AntplusDeviceType::WeightScale => "weight_scale",
            AntplusDeviceType::HeartRate => "heart_rate",
            AntplusDeviceType::BikeSpeedCadence => "bike_speed_cadence",
            AntplusDeviceType::BikeCadence => "bike_cadence",
            AntplusDeviceType::BikeSpeed => "bike_speed",
            AntplusDeviceType::StrideSpeedDistance => "stride_speed_distance",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            1 => Some(AntplusDeviceType::Antfs),
            11 => Some(AntplusDeviceType::BikePower),
            12 => Some(AntplusDeviceType::EnvironmentSensorLegacy),
            15 => Some(AntplusDeviceType::MultiSportSpeedDistance),
            16 => Some(AntplusDeviceType::Control),
            17 => Some(AntplusDeviceType::FitnessEquipment),
            18 => Some(AntplusDeviceType::BloodPressure),
            19 => Some(AntplusDeviceType::GeocacheNode),
            20 => Some(AntplusDeviceType::LightElectricVehicle),
            25 => Some(AntplusDeviceType::EnvSensor),
            26 => Some(AntplusDeviceType::Racquet),
            27 => Some(AntplusDeviceType::ControlHub),
            31 => Some(AntplusDeviceType::MuscleOxygen),
            34 => Some(AntplusDeviceType::Shifting),
            35 => Some(AntplusDeviceType::BikeLightMain),
            36 => Some(AntplusDeviceType::BikeLightShared),
            38 => Some(AntplusDeviceType::Exd),
            40 => Some(AntplusDeviceType::BikeRadar),
            46 => Some(AntplusDeviceType::BikeAero),
            119 => Some(AntplusDeviceType::WeightScale),
            120 => Some(AntplusDeviceType::HeartRate),
            121 => Some(AntplusDeviceType::BikeSpeedCadence),
            122 => Some(AntplusDeviceType::BikeCadence),
            123 => Some(AntplusDeviceType::BikeSpeed),
            124 => Some(AntplusDeviceType::StrideSpeedDistance),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "antfs" => Some(AntplusDeviceType::Antfs),
            "bike_power" => Some(AntplusDeviceType::BikePower),
            "environment_sensor_legacy" => Some(AntplusDeviceType::EnvironmentSensorLegacy),
            "multi_sport_speed_distance" => Some(AntplusDeviceType::MultiSportSpeedDistance),
            "control" => Some(AntplusDeviceType::Control),
            "fitness_equipment" => Some(AntplusDeviceType::FitnessEquipment),
            "blood_pressure" => Some(AntplusDeviceType::BloodPressure),
            "geocache_node" => Some(AntplusDeviceType::GeocacheNode),
            "light_electric_vehicle" => Some(AntplusDeviceType::LightElectricVehicle),
            "env_sensor" => Some(AntplusDeviceType::EnvSensor),
            "racquet" => Some(AntplusDeviceType::Racquet),
            "control_hub" => Some(AntplusDeviceType::ControlHub),
            "muscle_oxygen" => Some(AntplusDeviceType::MuscleOxygen),
            "shifting" => Some(AntplusDeviceType::Shifting),
            "bike_light_main" => Some(AntplusDeviceType::BikeLightMain),
            "bike_light_shared" => Some(AntplusDeviceType::BikeLightShared),
            "exd" => Some(AntplusDeviceType::Exd),
            "bike_radar" => Some(AntplusDeviceType::BikeRadar),
            "bike_aero" => Some(AntplusDeviceType::BikeAero),
            "weight_scale" => Some(AntplusDeviceType::WeightScale),
            "heart_rate" => Some(AntplusDeviceType::HeartRate),
            "bike_speed_cadence" => Some(AntplusDeviceType::BikeSpeedCadence),
            "bike_cadence" => Some(AntplusDeviceType::BikeCadence),
            "bike_speed" => Some(AntplusDeviceType::BikeSpeed),
            "stride_speed_distance" => Some(AntplusDeviceType::StrideSpeedDistance),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum AntNetwork {
    Public = 0,
    Antplus = 1,
    Antfs = 2,
    Private = 3,
}

impl AntNetwork {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            AntNetwork::Public => "public",
            AntNetwork::Antplus => "antplus",
            AntNetwork::Antfs => "antfs",
            AntNetwork::Private => "private",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(AntNetwork::Public),
            1 => Some(AntNetwork::Antplus),
            2 => Some(AntNetwork::Antfs),
            3 => Some(AntNetwork::Private),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "public" => Some(AntNetwork::Public),
            "antplus" => Some(AntNetwork::Antplus),
            "antfs" => Some(AntNetwork::Antfs),
            "private" => Some(AntNetwork::Private),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u32)]
#[non_exhaustive]
pub enum WorkoutCapabilities {
    Interval = 1,
    Custom = 2,
    FitnessEquipment = 4,
    Firstbeat = 8,
    NewLeaf = 16,
    Tcx = 32,
    Speed = 128,
    HeartRate = 256,
    Distance = 512,
    Cadence = 1024,
    Power = 2048,
    Grade = 4096,
    Resistance = 8192,
    Protected = 16384,
}

impl WorkoutCapabilities {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            WorkoutCapabilities::Interval => "interval",
            WorkoutCapabilities::Custom => "custom",
            WorkoutCapabilities::FitnessEquipment => "fitness_equipment",
            WorkoutCapabilities::Firstbeat => "firstbeat",
            WorkoutCapabilities::NewLeaf => "new_leaf",
            WorkoutCapabilities::Tcx => "tcx",
            WorkoutCapabilities::Speed => "speed",
            WorkoutCapabilities::HeartRate => "heart_rate",
            WorkoutCapabilities::Distance => "distance",
            WorkoutCapabilities::Cadence => "cadence",
            WorkoutCapabilities::Power => "power",
            WorkoutCapabilities::Grade => "grade",
            WorkoutCapabilities::Resistance => "resistance",
            WorkoutCapabilities::Protected => "protected",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u32) -> Option<Self> {
        match value {
            1 => Some(WorkoutCapabilities::Interval),
            2 => Some(WorkoutCapabilities::Custom),
            4 => Some(WorkoutCapabilities::FitnessEquipment),
            8 => Some(WorkoutCapabilities::Firstbeat),
            16 => Some(WorkoutCapabilities::NewLeaf),
            32 => Some(WorkoutCapabilities::Tcx),
            128 => Some(WorkoutCapabilities::Speed),
            256 => Some(WorkoutCapabilities::HeartRate),
            512 => Some(WorkoutCapabilities::Distance),
            1024 => Some(WorkoutCapabilities::Cadence),
            2048 => Some(WorkoutCapabilities::Power),
            4096 => Some(WorkoutCapabilities::Grade),
            8192 => Some(WorkoutCapabilities::Resistance),
            16384 => Some(WorkoutCapabilities::Protected),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "interval" => Some(WorkoutCapabilities::Interval),
            "custom" => Some(WorkoutCapabilities::Custom),
            "fitness_equipment" => Some(WorkoutCapabilities::FitnessEquipment),
            "firstbeat" => Some(WorkoutCapabilities::Firstbeat),
            "new_leaf" => Some(WorkoutCapabilities::NewLeaf),
            "tcx" => Some(WorkoutCapabilities::Tcx),
            "speed" => Some(WorkoutCapabilities::Speed),
            "heart_rate" => Some(WorkoutCapabilities::HeartRate),
            "distance" => Some(WorkoutCapabilities::Distance),
            "cadence" => Some(WorkoutCapabilities::Cadence),
            "power" => Some(WorkoutCapabilities::Power),
            "grade" => Some(WorkoutCapabilities::Grade),
            "resistance" => Some(WorkoutCapabilities::Resistance),
            "protected" => Some(WorkoutCapabilities::Protected),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum BatteryStatus {
    New = 1,
    Good = 2,
    Ok = 3,
    Low = 4,
    Critical = 5,
    Charging = 6,
    Unknown = 7,
}

impl BatteryStatus {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            BatteryStatus::New => "new",
            BatteryStatus::Good => "good",
            BatteryStatus::Ok => "ok",
            BatteryStatus::Low => "low",
            BatteryStatus::Critical => "critical",
            BatteryStatus::Charging => "charging",
            BatteryStatus::Unknown => "unknown",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            1 => Some(BatteryStatus::New),
            2 => Some(BatteryStatus::Good),
            3 => Some(BatteryStatus::Ok),
            4 => Some(BatteryStatus::Low),
            5 => Some(BatteryStatus::Critical),
            6 => Some(BatteryStatus::Charging),
            7 => Some(BatteryStatus::Unknown),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "new" => Some(BatteryStatus::New),
            "good" => Some(BatteryStatus::Good),
            "ok" => Some(BatteryStatus::Ok),
            "low" => Some(BatteryStatus::Low),
            "critical" => Some(BatteryStatus::Critical),
            "charging" => Some(BatteryStatus::Charging),
            "unknown" => Some(BatteryStatus::Unknown),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum HrType {
    Normal = 0,
    Irregular = 1,
}

impl HrType {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            HrType::Normal => "normal",
            HrType::Irregular => "irregular",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(HrType::Normal),
            1 => Some(HrType::Irregular),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "normal" => Some(HrType::Normal),
            "irregular" => Some(HrType::Irregular),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u32)]
#[non_exhaustive]
pub enum CourseCapabilities {
    Processed = 1,
    Valid = 2,
    Time = 4,
    Distance = 8,
    Position = 16,
    HeartRate = 32,
    Power = 64,
    Cadence = 128,
    Training = 256,
    Navigation = 512,
    Bikeway = 1024,
    Aviation = 4096,
}

impl CourseCapabilities {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            CourseCapabilities::Processed => "processed",
            CourseCapabilities::Valid => "valid",
            CourseCapabilities::Time => "time",
            CourseCapabilities::Distance => "distance",
            CourseCapabilities::Position => "position",
            CourseCapabilities::HeartRate => "heart_rate",
            CourseCapabilities::Power => "power",
            CourseCapabilities::Cadence => "cadence",
            CourseCapabilities::Training => "training",
            CourseCapabilities::Navigation => "navigation",
            CourseCapabilities::Bikeway => "bikeway",
            CourseCapabilities::Aviation => "aviation",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u32) -> Option<Self> {
        match value {
            1 => Some(CourseCapabilities::Processed),
            2 => Some(CourseCapabilities::Valid),
            4 => Some(CourseCapabilities::Time),
            8 => Some(CourseCapabilities::Distance),
            16 => Some(CourseCapabilities::Position),
            32 => Some(CourseCapabilities::HeartRate),
            64 => Some(CourseCapabilities::Power),
            128 => Some(CourseCapabilities::Cadence),
            256 => Some(CourseCapabilities::Training),
            512 => Some(CourseCapabilities::Navigation),
            1024 => Some(CourseCapabilities::Bikeway),
            4096 => Some(CourseCapabilities::Aviation),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "processed" => Some(CourseCapabilities::Processed),
            "valid" => Some(CourseCapabilities::Valid),
            "time" => Some(CourseCapabilities::Time),
            "distance" => Some(CourseCapabilities::Distance),
            "position" => Some(CourseCapabilities::Position),
            "heart_rate" => Some(CourseCapabilities::HeartRate),
            "power" => Some(CourseCapabilities::Power),
            "cadence" => Some(CourseCapabilities::Cadence),
            "training" => Some(CourseCapabilities::Training),
            "navigation" => Some(CourseCapabilities::Navigation),
            "bikeway" => Some(CourseCapabilities::Bikeway),
            "aviation" => Some(CourseCapabilities::Aviation),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum Weight {
    Calculating = 65534,
}

impl Weight {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            Weight::Calculating => "calculating",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            65534 => Some(Weight::Calculating),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "calculating" => Some(Weight::Calculating),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u32)]
#[non_exhaustive]
pub enum WorkoutHr {
    BpmOffset = 100,
}

impl WorkoutHr {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            WorkoutHr::BpmOffset => "bpm_offset",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u32) -> Option<Self> {
        match value {
            100 => Some(WorkoutHr::BpmOffset),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "bpm_offset" => Some(WorkoutHr::BpmOffset),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u32)]
#[non_exhaustive]
pub enum WorkoutPower {
    WattsOffset = 1000,
}

impl WorkoutPower {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            WorkoutPower::WattsOffset => "watts_offset",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u32) -> Option<Self> {
        match value {
            1000 => Some(WorkoutPower::WattsOffset),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "watts_offset" => Some(WorkoutPower::WattsOffset),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum BpStatus {
    NoError = 0,
    ErrorIncompleteData = 1,
    ErrorNoMeasurement = 2,
    ErrorDataOutOfRange = 3,
    ErrorIrregularHeartRate = 4,
}

impl BpStatus {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            BpStatus::NoError => "no_error",
            BpStatus::ErrorIncompleteData => "error_incomplete_data",
            BpStatus::ErrorNoMeasurement => "error_no_measurement",
            BpStatus::ErrorDataOutOfRange => "error_data_out_of_range",
            BpStatus::ErrorIrregularHeartRate => "error_irregular_heart_rate",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(BpStatus::NoError),
            1 => Some(BpStatus::ErrorIncompleteData),
            2 => Some(BpStatus::ErrorNoMeasurement),
            3 => Some(BpStatus::ErrorDataOutOfRange),
            4 => Some(BpStatus::ErrorIrregularHeartRate),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "no_error" => Some(BpStatus::NoError),
            "error_incomplete_data" => Some(BpStatus::ErrorIncompleteData),
            "error_no_measurement" => Some(BpStatus::ErrorNoMeasurement),
            "error_data_out_of_range" => Some(BpStatus::ErrorDataOutOfRange),
            "error_irregular_heart_rate" => Some(BpStatus::ErrorIrregularHeartRate),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum UserLocalId {
    LocalMin = 0,
    LocalMax = 15,
    StationaryMin = 16,
    StationaryMax = 255,
    PortableMin = 256,
    PortableMax = 65534,
}

impl UserLocalId {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            UserLocalId::LocalMin => "local_min",
            UserLocalId::LocalMax => "local_max",
            UserLocalId::StationaryMin => "stationary_min",
            UserLocalId::StationaryMax => "stationary_max",
            UserLocalId::PortableMin => "portable_min",
            UserLocalId::PortableMax => "portable_max",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(UserLocalId::LocalMin),
            15 => Some(UserLocalId::LocalMax),
            16 => Some(UserLocalId::StationaryMin),
            255 => Some(UserLocalId::StationaryMax),
            256 => Some(UserLocalId::PortableMin),
            65534 => Some(UserLocalId::PortableMax),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "local_min" => Some(UserLocalId::LocalMin),
            "local_max" => Some(UserLocalId::LocalMax),
            "stationary_min" => Some(UserLocalId::StationaryMin),
            "stationary_max" => Some(UserLocalId::StationaryMax),
            "portable_min" => Some(UserLocalId::PortableMin),
            "portable_max" => Some(UserLocalId::PortableMax),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum SwimStroke {
    Freestyle = 0,
    Backstroke = 1,
    Breaststroke = 2,
    Butterfly = 3,
    Drill = 4,
    Mixed = 5,
    Im = 6,
    ImByRound = 7,
    Rimo = 8,
}

impl SwimStroke {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            SwimStroke::Freestyle => "freestyle",
            SwimStroke::Backstroke => "backstroke",
            SwimStroke::Breaststroke => "breaststroke",
            SwimStroke::Butterfly => "butterfly",
            SwimStroke::Drill => "drill",
            SwimStroke::Mixed => "mixed",
            SwimStroke::Im => "im",
            SwimStroke::ImByRound => "im_by_round",
            SwimStroke::Rimo => "rimo",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(SwimStroke::Freestyle),
            1 => Some(SwimStroke::Backstroke),
            2 => Some(SwimStroke::Breaststroke),
            3 => Some(SwimStroke::Butterfly),
            4 => Some(SwimStroke::Drill),
            5 => Some(SwimStroke::Mixed),
            6 => Some(SwimStroke::Im),
            7 => Some(SwimStroke::ImByRound),
            8 => Some(SwimStroke::Rimo),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "freestyle" => Some(SwimStroke::Freestyle),
            "backstroke" => Some(SwimStroke::Backstroke),
            "breaststroke" => Some(SwimStroke::Breaststroke),
            "butterfly" => Some(SwimStroke::Butterfly),
            "drill" => Some(SwimStroke::Drill),
            "mixed" => Some(SwimStroke::Mixed),
            "im" => Some(SwimStroke::Im),
            "im_by_round" => Some(SwimStroke::ImByRound),
            "rimo" => Some(SwimStroke::Rimo),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum ActivityType {
    Generic = 0,
    Running = 1,
    Cycling = 2,
    Transition = 3,
    FitnessEquipment = 4,
    Swimming = 5,
    Walking = 6,
    Sedentary = 8,
    All = 254,
}

impl ActivityType {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            ActivityType::Generic => "generic",
            ActivityType::Running => "running",
            ActivityType::Cycling => "cycling",
            ActivityType::Transition => "transition",
            ActivityType::FitnessEquipment => "fitness_equipment",
            ActivityType::Swimming => "swimming",
            ActivityType::Walking => "walking",
            ActivityType::Sedentary => "sedentary",
            ActivityType::All => "all",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(ActivityType::Generic),
            1 => Some(ActivityType::Running),
            2 => Some(ActivityType::Cycling),
            3 => Some(ActivityType::Transition),
            4 => Some(ActivityType::FitnessEquipment),
            5 => Some(ActivityType::Swimming),
            6 => Some(ActivityType::Walking),
            8 => Some(ActivityType::Sedentary),
            254 => Some(ActivityType::All),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "generic" => Some(ActivityType::Generic),
            "running" => Some(ActivityType::Running),
            "cycling" => Some(ActivityType::Cycling),
            "transition" => Some(ActivityType::Transition),
            "fitness_equipment" => Some(ActivityType::FitnessEquipment),
            "swimming" => Some(ActivityType::Swimming),
            "walking" => Some(ActivityType::Walking),
            "sedentary" => Some(ActivityType::Sedentary),
            "all" => Some(ActivityType::All),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum ActivitySubtype {
    Generic = 0,
    Treadmill = 1,
    Street = 2,
    Trail = 3,
    Track = 4,
    Spin = 5,
    IndoorCycling = 6,
    Road = 7,
    Mountain = 8,
    Downhill = 9,
    Recumbent = 10,
    Cyclocross = 11,
    HandCycling = 12,
    TrackCycling = 13,
    IndoorRowing = 14,
    Elliptical = 15,
    StairClimbing = 16,
    LapSwimming = 17,
    OpenWater = 18,
    All = 254,
}

impl ActivitySubtype {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            ActivitySubtype::Generic => "generic",
            ActivitySubtype::Treadmill => "treadmill",
            ActivitySubtype::Street => "street",
            ActivitySubtype::Trail => "trail",
            ActivitySubtype::Track => "track",
            ActivitySubtype::Spin => "spin",
            ActivitySubtype::IndoorCycling => "indoor_cycling",
            ActivitySubtype::Road => "road",
            ActivitySubtype::Mountain => "mountain",
            ActivitySubtype::Downhill => "downhill",
            ActivitySubtype::Recumbent => "recumbent",
            ActivitySubtype::Cyclocross => "cyclocross",
            ActivitySubtype::HandCycling => "hand_cycling",
            ActivitySubtype::TrackCycling => "track_cycling",
            ActivitySubtype::IndoorRowing => "indoor_rowing",
            ActivitySubtype::Elliptical => "elliptical",
            ActivitySubtype::StairClimbing => "stair_climbing",
            ActivitySubtype::LapSwimming => "lap_swimming",
            ActivitySubtype::OpenWater => "open_water",
            ActivitySubtype::All => "all",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(ActivitySubtype::Generic),
            1 => Some(ActivitySubtype::Treadmill),
            2 => Some(ActivitySubtype::Street),
            3 => Some(ActivitySubtype::Trail),
            4 => Some(ActivitySubtype::Track),
            5 => Some(ActivitySubtype::Spin),
            6 => Some(ActivitySubtype::IndoorCycling),
            7 => Some(ActivitySubtype::Road),
            8 => Some(ActivitySubtype::Mountain),
            9 => Some(ActivitySubtype::Downhill),
            10 => Some(ActivitySubtype::Recumbent),
            11 => Some(ActivitySubtype::Cyclocross),
            12 => Some(ActivitySubtype::HandCycling),
            13 => Some(ActivitySubtype::TrackCycling),
            14 => Some(ActivitySubtype::IndoorRowing),
            15 => Some(ActivitySubtype::Elliptical),
            16 => Some(ActivitySubtype::StairClimbing),
            17 => Some(ActivitySubtype::LapSwimming),
            18 => Some(ActivitySubtype::OpenWater),
            254 => Some(ActivitySubtype::All),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "generic" => Some(ActivitySubtype::Generic),
            "treadmill" => Some(ActivitySubtype::Treadmill),
            "street" => Some(ActivitySubtype::Street),
            "trail" => Some(ActivitySubtype::Trail),
            "track" => Some(ActivitySubtype::Track),
            "spin" => Some(ActivitySubtype::Spin),
            "indoor_cycling" => Some(ActivitySubtype::IndoorCycling),
            "road" => Some(ActivitySubtype::Road),
            "mountain" => Some(ActivitySubtype::Mountain),
            "downhill" => Some(ActivitySubtype::Downhill),
            "recumbent" => Some(ActivitySubtype::Recumbent),
            "cyclocross" => Some(ActivitySubtype::Cyclocross),
            "hand_cycling" => Some(ActivitySubtype::HandCycling),
            "track_cycling" => Some(ActivitySubtype::TrackCycling),
            "indoor_rowing" => Some(ActivitySubtype::IndoorRowing),
            "elliptical" => Some(ActivitySubtype::Elliptical),
            "stair_climbing" => Some(ActivitySubtype::StairClimbing),
            "lap_swimming" => Some(ActivitySubtype::LapSwimming),
            "open_water" => Some(ActivitySubtype::OpenWater),
            "all" => Some(ActivitySubtype::All),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum ActivityLevel {
    Low = 0,
    Medium = 1,
    High = 2,
}

impl ActivityLevel {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            ActivityLevel::Low => "low",
            ActivityLevel::Medium => "medium",
            ActivityLevel::High => "high",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(ActivityLevel::Low),
            1 => Some(ActivityLevel::Medium),
            2 => Some(ActivityLevel::High),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "low" => Some(ActivityLevel::Low),
            "medium" => Some(ActivityLevel::Medium),
            "high" => Some(ActivityLevel::High),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum Side {
    Right = 0,
    Left = 1,
}

impl Side {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            Side::Right => "right",
            Side::Left => "left",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(Side::Right),
            1 => Some(Side::Left),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "right" => Some(Side::Right),
            "left" => Some(Side::Left),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum LeftRightBalance {
    Mask = 127,
    Right = 128,
}

impl LeftRightBalance {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            LeftRightBalance::Mask => "mask",
            LeftRightBalance::Right => "right",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            127 => Some(LeftRightBalance::Mask),
            128 => Some(LeftRightBalance::Right),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "mask" => Some(LeftRightBalance::Mask),
            "right" => Some(LeftRightBalance::Right),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum LeftRightBalance100 {
    Mask = 16383,
    Right = 32768,
}

impl LeftRightBalance100 {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            LeftRightBalance100::Mask => "mask",
            LeftRightBalance100::Right => "right",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            16383 => Some(LeftRightBalance100::Mask),
            32768 => Some(LeftRightBalance100::Right),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "mask" => Some(LeftRightBalance100::Mask),
            "right" => Some(LeftRightBalance100::Right),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum LengthType {
    Idle = 0,
    Active = 1,
}

impl LengthType {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            LengthType::Idle => "idle",
            LengthType::Active => "active",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(LengthType::Idle),
            1 => Some(LengthType::Active),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "idle" => Some(LengthType::Idle),
            "active" => Some(LengthType::Active),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum DayOfWeek {
    Sunday = 0,
    Monday = 1,
    Tuesday = 2,
    Wednesday = 3,
    Thursday = 4,
    Friday = 5,
    Saturday = 6,
}

impl DayOfWeek {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            DayOfWeek::Sunday => "sunday",
            DayOfWeek::Monday => "monday",
            DayOfWeek::Tuesday => "tuesday",
            DayOfWeek::Wednesday => "wednesday",
            DayOfWeek::Thursday => "thursday",
            DayOfWeek::Friday => "friday",
            DayOfWeek::Saturday => "saturday",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(DayOfWeek::Sunday),
            1 => Some(DayOfWeek::Monday),
            2 => Some(DayOfWeek::Tuesday),
            3 => Some(DayOfWeek::Wednesday),
            4 => Some(DayOfWeek::Thursday),
            5 => Some(DayOfWeek::Friday),
            6 => Some(DayOfWeek::Saturday),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "sunday" => Some(DayOfWeek::Sunday),
            "monday" => Some(DayOfWeek::Monday),
            "tuesday" => Some(DayOfWeek::Tuesday),
            "wednesday" => Some(DayOfWeek::Wednesday),
            "thursday" => Some(DayOfWeek::Thursday),
            "friday" => Some(DayOfWeek::Friday),
            "saturday" => Some(DayOfWeek::Saturday),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u32)]
#[non_exhaustive]
pub enum ConnectivityCapabilities {
    Bluetooth = 1,
    BluetoothLe = 2,
    Ant = 4,
    ActivityUpload = 8,
    CourseDownload = 16,
    WorkoutDownload = 32,
    LiveTrack = 64,
    WeatherConditions = 128,
    WeatherAlerts = 256,
    GpsEphemerisDownload = 512,
    ExplicitArchive = 1024,
    SetupIncomplete = 2048,
    ContinueSyncAfterSoftwareUpdate = 4096,
    ConnectIqAppDownload = 8192,
    GolfCourseDownload = 16384,
    DeviceInitiatesSync = 32768,
    ConnectIqWatchAppDownload = 65536,
    ConnectIqWidgetDownload = 131072,
    ConnectIqWatchFaceDownload = 262144,
    ConnectIqDataFieldDownload = 524288,
    ConnectIqAppManagment = 1048576,
    SwingSensor = 2097152,
    SwingSensorRemote = 4194304,
    IncidentDetection = 8388608,
    AudioPrompts = 16777216,
    WifiVerification = 33554432,
    TrueUp = 67108864,
    FindMyWatch = 134217728,
    RemoteManualSync = 268435456,
    LiveTrackAutoStart = 536870912,
    LiveTrackMessaging = 1073741824,
    InstantInput = 2147483648,
}

impl ConnectivityCapabilities {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            ConnectivityCapabilities::Bluetooth => "bluetooth",
            ConnectivityCapabilities::BluetoothLe => "bluetooth_le",
            ConnectivityCapabilities::Ant => "ant",
            ConnectivityCapabilities::ActivityUpload => "activity_upload",
            ConnectivityCapabilities::CourseDownload => "course_download",
            ConnectivityCapabilities::WorkoutDownload => "workout_download",
            ConnectivityCapabilities::LiveTrack => "live_track",
            ConnectivityCapabilities::WeatherConditions => "weather_conditions",
            ConnectivityCapabilities::WeatherAlerts => "weather_alerts",
            ConnectivityCapabilities::GpsEphemerisDownload => "gps_ephemeris_download",
            ConnectivityCapabilities::ExplicitArchive => "explicit_archive",
            ConnectivityCapabilities::SetupIncomplete => "setup_incomplete",
            ConnectivityCapabilities::ContinueSyncAfterSoftwareUpdate => {
                "continue_sync_after_software_update"
            }
            ConnectivityCapabilities::ConnectIqAppDownload => "connect_iq_app_download",
            ConnectivityCapabilities::GolfCourseDownload => "golf_course_download",
            ConnectivityCapabilities::DeviceInitiatesSync => "device_initiates_sync",
            ConnectivityCapabilities::ConnectIqWatchAppDownload => "connect_iq_watch_app_download",
            ConnectivityCapabilities::ConnectIqWidgetDownload => "connect_iq_widget_download",
            ConnectivityCapabilities::ConnectIqWatchFaceDownload => {
                "connect_iq_watch_face_download"
            }
            ConnectivityCapabilities::ConnectIqDataFieldDownload => {
                "connect_iq_data_field_download"
            }
            ConnectivityCapabilities::ConnectIqAppManagment => "connect_iq_app_managment",
            ConnectivityCapabilities::SwingSensor => "swing_sensor",
            ConnectivityCapabilities::SwingSensorRemote => "swing_sensor_remote",
            ConnectivityCapabilities::IncidentDetection => "incident_detection",
            ConnectivityCapabilities::AudioPrompts => "audio_prompts",
            ConnectivityCapabilities::WifiVerification => "wifi_verification",
            ConnectivityCapabilities::TrueUp => "true_up",
            ConnectivityCapabilities::FindMyWatch => "find_my_watch",
            ConnectivityCapabilities::RemoteManualSync => "remote_manual_sync",
            ConnectivityCapabilities::LiveTrackAutoStart => "live_track_auto_start",
            ConnectivityCapabilities::LiveTrackMessaging => "live_track_messaging",
            ConnectivityCapabilities::InstantInput => "instant_input",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u32) -> Option<Self> {
        match value {
            1 => Some(ConnectivityCapabilities::Bluetooth),
            2 => Some(ConnectivityCapabilities::BluetoothLe),
            4 => Some(ConnectivityCapabilities::Ant),
            8 => Some(ConnectivityCapabilities::ActivityUpload),
            16 => Some(ConnectivityCapabilities::CourseDownload),
            32 => Some(ConnectivityCapabilities::WorkoutDownload),
            64 => Some(ConnectivityCapabilities::LiveTrack),
            128 => Some(ConnectivityCapabilities::WeatherConditions),
            256 => Some(ConnectivityCapabilities::WeatherAlerts),
            512 => Some(ConnectivityCapabilities::GpsEphemerisDownload),
            1024 => Some(ConnectivityCapabilities::ExplicitArchive),
            2048 => Some(ConnectivityCapabilities::SetupIncomplete),
            4096 => Some(ConnectivityCapabilities::ContinueSyncAfterSoftwareUpdate),
            8192 => Some(ConnectivityCapabilities::ConnectIqAppDownload),
            16384 => Some(ConnectivityCapabilities::GolfCourseDownload),
            32768 => Some(ConnectivityCapabilities::DeviceInitiatesSync),
            65536 => Some(ConnectivityCapabilities::ConnectIqWatchAppDownload),
            131072 => Some(ConnectivityCapabilities::ConnectIqWidgetDownload),
            262144 => Some(ConnectivityCapabilities::ConnectIqWatchFaceDownload),
            524288 => Some(ConnectivityCapabilities::ConnectIqDataFieldDownload),
            1048576 => Some(ConnectivityCapabilities::ConnectIqAppManagment),
            2097152 => Some(ConnectivityCapabilities::SwingSensor),
            4194304 => Some(ConnectivityCapabilities::SwingSensorRemote),
            8388608 => Some(ConnectivityCapabilities::IncidentDetection),
            16777216 => Some(ConnectivityCapabilities::AudioPrompts),
            33554432 => Some(ConnectivityCapabilities::WifiVerification),
            67108864 => Some(ConnectivityCapabilities::TrueUp),
            134217728 => Some(ConnectivityCapabilities::FindMyWatch),
            268435456 => Some(ConnectivityCapabilities::RemoteManualSync),
            536870912 => Some(ConnectivityCapabilities::LiveTrackAutoStart),
            1073741824 => Some(ConnectivityCapabilities::LiveTrackMessaging),
            2147483648 => Some(ConnectivityCapabilities::InstantInput),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "bluetooth" => Some(ConnectivityCapabilities::Bluetooth),
            "bluetooth_le" => Some(ConnectivityCapabilities::BluetoothLe),
            "ant" => Some(ConnectivityCapabilities::Ant),
            "activity_upload" => Some(ConnectivityCapabilities::ActivityUpload),
            "course_download" => Some(ConnectivityCapabilities::CourseDownload),
            "workout_download" => Some(ConnectivityCapabilities::WorkoutDownload),
            "live_track" => Some(ConnectivityCapabilities::LiveTrack),
            "weather_conditions" => Some(ConnectivityCapabilities::WeatherConditions),
            "weather_alerts" => Some(ConnectivityCapabilities::WeatherAlerts),
            "gps_ephemeris_download" => Some(ConnectivityCapabilities::GpsEphemerisDownload),
            "explicit_archive" => Some(ConnectivityCapabilities::ExplicitArchive),
            "setup_incomplete" => Some(ConnectivityCapabilities::SetupIncomplete),
            "continue_sync_after_software_update" => {
                Some(ConnectivityCapabilities::ContinueSyncAfterSoftwareUpdate)
            }
            "connect_iq_app_download" => Some(ConnectivityCapabilities::ConnectIqAppDownload),
            "golf_course_download" => Some(ConnectivityCapabilities::GolfCourseDownload),
            "device_initiates_sync" => Some(ConnectivityCapabilities::DeviceInitiatesSync),
            "connect_iq_watch_app_download" => {
                Some(ConnectivityCapabilities::ConnectIqWatchAppDownload)
            }
            "connect_iq_widget_download" => Some(ConnectivityCapabilities::ConnectIqWidgetDownload),
            "connect_iq_watch_face_download" => {
                Some(ConnectivityCapabilities::ConnectIqWatchFaceDownload)
            }
            "connect_iq_data_field_download" => {
                Some(ConnectivityCapabilities::ConnectIqDataFieldDownload)
            }
            "connect_iq_app_managment" => Some(ConnectivityCapabilities::ConnectIqAppManagment),
            "swing_sensor" => Some(ConnectivityCapabilities::SwingSensor),
            "swing_sensor_remote" => Some(ConnectivityCapabilities::SwingSensorRemote),
            "incident_detection" => Some(ConnectivityCapabilities::IncidentDetection),
            "audio_prompts" => Some(ConnectivityCapabilities::AudioPrompts),
            "wifi_verification" => Some(ConnectivityCapabilities::WifiVerification),
            "true_up" => Some(ConnectivityCapabilities::TrueUp),
            "find_my_watch" => Some(ConnectivityCapabilities::FindMyWatch),
            "remote_manual_sync" => Some(ConnectivityCapabilities::RemoteManualSync),
            "live_track_auto_start" => Some(ConnectivityCapabilities::LiveTrackAutoStart),
            "live_track_messaging" => Some(ConnectivityCapabilities::LiveTrackMessaging),
            "instant_input" => Some(ConnectivityCapabilities::InstantInput),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum WeatherReport {
    Current = 0,
    Forecast = 1,
    DailyForecast = 2,
}

impl WeatherReport {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            WeatherReport::Current => "current",
            WeatherReport::Forecast => "hourly_forecast",
            WeatherReport::DailyForecast => "daily_forecast",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(WeatherReport::Current),
            1 => Some(WeatherReport::Forecast),
            2 => Some(WeatherReport::DailyForecast),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "current" => Some(WeatherReport::Current),
            "hourly_forecast" => Some(WeatherReport::Forecast),
            "daily_forecast" => Some(WeatherReport::DailyForecast),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum WeatherStatus {
    Clear = 0,
    PartlyCloudy = 1,
    MostlyCloudy = 2,
    Rain = 3,
    Snow = 4,
    Windy = 5,
    Thunderstorms = 6,
    WintryMix = 7,
    Fog = 8,
    Hazy = 11,
    Hail = 12,
    ScatteredShowers = 13,
    ScatteredThunderstorms = 14,
    UnknownPrecipitation = 15,
    LightRain = 16,
    HeavyRain = 17,
    LightSnow = 18,
    HeavySnow = 19,
    LightRainSnow = 20,
    HeavyRainSnow = 21,
    Cloudy = 22,
}

impl WeatherStatus {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            WeatherStatus::Clear => "clear",
            WeatherStatus::PartlyCloudy => "partly_cloudy",
            WeatherStatus::MostlyCloudy => "mostly_cloudy",
            WeatherStatus::Rain => "rain",
            WeatherStatus::Snow => "snow",
            WeatherStatus::Windy => "windy",
            WeatherStatus::Thunderstorms => "thunderstorms",
            WeatherStatus::WintryMix => "wintry_mix",
            WeatherStatus::Fog => "fog",
            WeatherStatus::Hazy => "hazy",
            WeatherStatus::Hail => "hail",
            WeatherStatus::ScatteredShowers => "scattered_showers",
            WeatherStatus::ScatteredThunderstorms => "scattered_thunderstorms",
            WeatherStatus::UnknownPrecipitation => "unknown_precipitation",
            WeatherStatus::LightRain => "light_rain",
            WeatherStatus::HeavyRain => "heavy_rain",
            WeatherStatus::LightSnow => "light_snow",
            WeatherStatus::HeavySnow => "heavy_snow",
            WeatherStatus::LightRainSnow => "light_rain_snow",
            WeatherStatus::HeavyRainSnow => "heavy_rain_snow",
            WeatherStatus::Cloudy => "cloudy",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(WeatherStatus::Clear),
            1 => Some(WeatherStatus::PartlyCloudy),
            2 => Some(WeatherStatus::MostlyCloudy),
            3 => Some(WeatherStatus::Rain),
            4 => Some(WeatherStatus::Snow),
            5 => Some(WeatherStatus::Windy),
            6 => Some(WeatherStatus::Thunderstorms),
            7 => Some(WeatherStatus::WintryMix),
            8 => Some(WeatherStatus::Fog),
            11 => Some(WeatherStatus::Hazy),
            12 => Some(WeatherStatus::Hail),
            13 => Some(WeatherStatus::ScatteredShowers),
            14 => Some(WeatherStatus::ScatteredThunderstorms),
            15 => Some(WeatherStatus::UnknownPrecipitation),
            16 => Some(WeatherStatus::LightRain),
            17 => Some(WeatherStatus::HeavyRain),
            18 => Some(WeatherStatus::LightSnow),
            19 => Some(WeatherStatus::HeavySnow),
            20 => Some(WeatherStatus::LightRainSnow),
            21 => Some(WeatherStatus::HeavyRainSnow),
            22 => Some(WeatherStatus::Cloudy),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "clear" => Some(WeatherStatus::Clear),
            "partly_cloudy" => Some(WeatherStatus::PartlyCloudy),
            "mostly_cloudy" => Some(WeatherStatus::MostlyCloudy),
            "rain" => Some(WeatherStatus::Rain),
            "snow" => Some(WeatherStatus::Snow),
            "windy" => Some(WeatherStatus::Windy),
            "thunderstorms" => Some(WeatherStatus::Thunderstorms),
            "wintry_mix" => Some(WeatherStatus::WintryMix),
            "fog" => Some(WeatherStatus::Fog),
            "hazy" => Some(WeatherStatus::Hazy),
            "hail" => Some(WeatherStatus::Hail),
            "scattered_showers" => Some(WeatherStatus::ScatteredShowers),
            "scattered_thunderstorms" => Some(WeatherStatus::ScatteredThunderstorms),
            "unknown_precipitation" => Some(WeatherStatus::UnknownPrecipitation),
            "light_rain" => Some(WeatherStatus::LightRain),
            "heavy_rain" => Some(WeatherStatus::HeavyRain),
            "light_snow" => Some(WeatherStatus::LightSnow),
            "heavy_snow" => Some(WeatherStatus::HeavySnow),
            "light_rain_snow" => Some(WeatherStatus::LightRainSnow),
            "heavy_rain_snow" => Some(WeatherStatus::HeavyRainSnow),
            "cloudy" => Some(WeatherStatus::Cloudy),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum WeatherSeverity {
    Unknown = 0,
    Warning = 1,
    Watch = 2,
    Advisory = 3,
    Statement = 4,
}

impl WeatherSeverity {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            WeatherSeverity::Unknown => "unknown",
            WeatherSeverity::Warning => "warning",
            WeatherSeverity::Watch => "watch",
            WeatherSeverity::Advisory => "advisory",
            WeatherSeverity::Statement => "statement",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(WeatherSeverity::Unknown),
            1 => Some(WeatherSeverity::Warning),
            2 => Some(WeatherSeverity::Watch),
            3 => Some(WeatherSeverity::Advisory),
            4 => Some(WeatherSeverity::Statement),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "unknown" => Some(WeatherSeverity::Unknown),
            "warning" => Some(WeatherSeverity::Warning),
            "watch" => Some(WeatherSeverity::Watch),
            "advisory" => Some(WeatherSeverity::Advisory),
            "statement" => Some(WeatherSeverity::Statement),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum WeatherSevereType {
    Unspecified = 0,
    Tornado = 1,
    Tsunami = 2,
    Hurricane = 3,
    ExtremeWind = 4,
    Typhoon = 5,
    InlandHurricane = 6,
    HurricaneForceWind = 7,
    Waterspout = 8,
    SevereThunderstorm = 9,
    WreckhouseWinds = 10,
    LesSuetesWind = 11,
    Avalanche = 12,
    FlashFlood = 13,
    TropicalStorm = 14,
    InlandTropicalStorm = 15,
    Blizzard = 16,
    IceStorm = 17,
    FreezingRain = 18,
    DebrisFlow = 19,
    FlashFreeze = 20,
    DustStorm = 21,
    HighWind = 22,
    WinterStorm = 23,
    HeavyFreezingSpray = 24,
    ExtremeCold = 25,
    WindChill = 26,
    ColdWave = 27,
    HeavySnowAlert = 28,
    LakeEffectBlowingSnow = 29,
    SnowSquall = 30,
    LakeEffectSnow = 31,
    WinterWeather = 32,
    Sleet = 33,
    Snowfall = 34,
    SnowAndBlowingSnow = 35,
    BlowingSnow = 36,
    SnowAlert = 37,
    ArcticOutflow = 38,
    FreezingDrizzle = 39,
    Storm = 40,
    StormSurge = 41,
    Rainfall = 42,
    ArealFlood = 43,
    CoastalFlood = 44,
    LakeshoreFlood = 45,
    ExcessiveHeat = 46,
    Heat = 47,
    Weather = 48,
    HighHeatAndHumidity = 49,
    HumidexAndHealth = 50,
    Humidex = 51,
    Gale = 52,
    FreezingSpray = 53,
    SpecialMarine = 54,
    Squall = 55,
    StrongWind = 56,
    LakeWind = 57,
    MarineWeather = 58,
    Wind = 59,
    SmallCraftHazardousSeas = 60,
    HazardousSeas = 61,
    SmallCraft = 62,
    SmallCraftWinds = 63,
    SmallCraftRoughBar = 64,
    HighWaterLevel = 65,
    Ashfall = 66,
    FreezingFog = 67,
    DenseFog = 68,
    DenseSmoke = 69,
    BlowingDust = 70,
    HardFreeze = 71,
    Freeze = 72,
    Frost = 73,
    FireWeather = 74,
    Flood = 75,
    RipTide = 76,
    HighSurf = 77,
    Smog = 78,
    AirQuality = 79,
    BriskWind = 80,
    AirStagnation = 81,
    LowWater = 82,
    Hydrological = 83,
    SpecialWeather = 84,
}

impl WeatherSevereType {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            WeatherSevereType::Unspecified => "unspecified",
            WeatherSevereType::Tornado => "tornado",
            WeatherSevereType::Tsunami => "tsunami",
            WeatherSevereType::Hurricane => "hurricane",
            WeatherSevereType::ExtremeWind => "extreme_wind",
            WeatherSevereType::Typhoon => "typhoon",
            WeatherSevereType::InlandHurricane => "inland_hurricane",
            WeatherSevereType::HurricaneForceWind => "hurricane_force_wind",
            WeatherSevereType::Waterspout => "waterspout",
            WeatherSevereType::SevereThunderstorm => "severe_thunderstorm",
            WeatherSevereType::WreckhouseWinds => "wreckhouse_winds",
            WeatherSevereType::LesSuetesWind => "les_suetes_wind",
            WeatherSevereType::Avalanche => "avalanche",
            WeatherSevereType::FlashFlood => "flash_flood",
            WeatherSevereType::TropicalStorm => "tropical_storm",
            WeatherSevereType::InlandTropicalStorm => "inland_tropical_storm",
            WeatherSevereType::Blizzard => "blizzard",
            WeatherSevereType::IceStorm => "ice_storm",
            WeatherSevereType::FreezingRain => "freezing_rain",
            WeatherSevereType::DebrisFlow => "debris_flow",
            WeatherSevereType::FlashFreeze => "flash_freeze",
            WeatherSevereType::DustStorm => "dust_storm",
            WeatherSevereType::HighWind => "high_wind",
            WeatherSevereType::WinterStorm => "winter_storm",
            WeatherSevereType::HeavyFreezingSpray => "heavy_freezing_spray",
            WeatherSevereType::ExtremeCold => "extreme_cold",
            WeatherSevereType::WindChill => "wind_chill",
            WeatherSevereType::ColdWave => "cold_wave",
            WeatherSevereType::HeavySnowAlert => "heavy_snow_alert",
            WeatherSevereType::LakeEffectBlowingSnow => "lake_effect_blowing_snow",
            WeatherSevereType::SnowSquall => "snow_squall",
            WeatherSevereType::LakeEffectSnow => "lake_effect_snow",
            WeatherSevereType::WinterWeather => "winter_weather",
            WeatherSevereType::Sleet => "sleet",
            WeatherSevereType::Snowfall => "snowfall",
            WeatherSevereType::SnowAndBlowingSnow => "snow_and_blowing_snow",
            WeatherSevereType::BlowingSnow => "blowing_snow",
            WeatherSevereType::SnowAlert => "snow_alert",
            WeatherSevereType::ArcticOutflow => "arctic_outflow",
            WeatherSevereType::FreezingDrizzle => "freezing_drizzle",
            WeatherSevereType::Storm => "storm",
            WeatherSevereType::StormSurge => "storm_surge",
            WeatherSevereType::Rainfall => "rainfall",
            WeatherSevereType::ArealFlood => "areal_flood",
            WeatherSevereType::CoastalFlood => "coastal_flood",
            WeatherSevereType::LakeshoreFlood => "lakeshore_flood",
            WeatherSevereType::ExcessiveHeat => "excessive_heat",
            WeatherSevereType::Heat => "heat",
            WeatherSevereType::Weather => "weather",
            WeatherSevereType::HighHeatAndHumidity => "high_heat_and_humidity",
            WeatherSevereType::HumidexAndHealth => "humidex_and_health",
            WeatherSevereType::Humidex => "humidex",
            WeatherSevereType::Gale => "gale",
            WeatherSevereType::FreezingSpray => "freezing_spray",
            WeatherSevereType::SpecialMarine => "special_marine",
            WeatherSevereType::Squall => "squall",
            WeatherSevereType::StrongWind => "strong_wind",
            WeatherSevereType::LakeWind => "lake_wind",
            WeatherSevereType::MarineWeather => "marine_weather",
            WeatherSevereType::Wind => "wind",
            WeatherSevereType::SmallCraftHazardousSeas => "small_craft_hazardous_seas",
            WeatherSevereType::HazardousSeas => "hazardous_seas",
            WeatherSevereType::SmallCraft => "small_craft",
            WeatherSevereType::SmallCraftWinds => "small_craft_winds",
            WeatherSevereType::SmallCraftRoughBar => "small_craft_rough_bar",
            WeatherSevereType::HighWaterLevel => "high_water_level",
            WeatherSevereType::Ashfall => "ashfall",
            WeatherSevereType::FreezingFog => "freezing_fog",
            WeatherSevereType::DenseFog => "dense_fog",
            WeatherSevereType::DenseSmoke => "dense_smoke",
            WeatherSevereType::BlowingDust => "blowing_dust",
            WeatherSevereType::HardFreeze => "hard_freeze",
            WeatherSevereType::Freeze => "freeze",
            WeatherSevereType::Frost => "frost",
            WeatherSevereType::FireWeather => "fire_weather",
            WeatherSevereType::Flood => "flood",
            WeatherSevereType::RipTide => "rip_tide",
            WeatherSevereType::HighSurf => "high_surf",
            WeatherSevereType::Smog => "smog",
            WeatherSevereType::AirQuality => "air_quality",
            WeatherSevereType::BriskWind => "brisk_wind",
            WeatherSevereType::AirStagnation => "air_stagnation",
            WeatherSevereType::LowWater => "low_water",
            WeatherSevereType::Hydrological => "hydrological",
            WeatherSevereType::SpecialWeather => "special_weather",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(WeatherSevereType::Unspecified),
            1 => Some(WeatherSevereType::Tornado),
            2 => Some(WeatherSevereType::Tsunami),
            3 => Some(WeatherSevereType::Hurricane),
            4 => Some(WeatherSevereType::ExtremeWind),
            5 => Some(WeatherSevereType::Typhoon),
            6 => Some(WeatherSevereType::InlandHurricane),
            7 => Some(WeatherSevereType::HurricaneForceWind),
            8 => Some(WeatherSevereType::Waterspout),
            9 => Some(WeatherSevereType::SevereThunderstorm),
            10 => Some(WeatherSevereType::WreckhouseWinds),
            11 => Some(WeatherSevereType::LesSuetesWind),
            12 => Some(WeatherSevereType::Avalanche),
            13 => Some(WeatherSevereType::FlashFlood),
            14 => Some(WeatherSevereType::TropicalStorm),
            15 => Some(WeatherSevereType::InlandTropicalStorm),
            16 => Some(WeatherSevereType::Blizzard),
            17 => Some(WeatherSevereType::IceStorm),
            18 => Some(WeatherSevereType::FreezingRain),
            19 => Some(WeatherSevereType::DebrisFlow),
            20 => Some(WeatherSevereType::FlashFreeze),
            21 => Some(WeatherSevereType::DustStorm),
            22 => Some(WeatherSevereType::HighWind),
            23 => Some(WeatherSevereType::WinterStorm),
            24 => Some(WeatherSevereType::HeavyFreezingSpray),
            25 => Some(WeatherSevereType::ExtremeCold),
            26 => Some(WeatherSevereType::WindChill),
            27 => Some(WeatherSevereType::ColdWave),
            28 => Some(WeatherSevereType::HeavySnowAlert),
            29 => Some(WeatherSevereType::LakeEffectBlowingSnow),
            30 => Some(WeatherSevereType::SnowSquall),
            31 => Some(WeatherSevereType::LakeEffectSnow),
            32 => Some(WeatherSevereType::WinterWeather),
            33 => Some(WeatherSevereType::Sleet),
            34 => Some(WeatherSevereType::Snowfall),
            35 => Some(WeatherSevereType::SnowAndBlowingSnow),
            36 => Some(WeatherSevereType::BlowingSnow),
            37 => Some(WeatherSevereType::SnowAlert),
            38 => Some(WeatherSevereType::ArcticOutflow),
            39 => Some(WeatherSevereType::FreezingDrizzle),
            40 => Some(WeatherSevereType::Storm),
            41 => Some(WeatherSevereType::StormSurge),
            42 => Some(WeatherSevereType::Rainfall),
            43 => Some(WeatherSevereType::ArealFlood),
            44 => Some(WeatherSevereType::CoastalFlood),
            45 => Some(WeatherSevereType::LakeshoreFlood),
            46 => Some(WeatherSevereType::ExcessiveHeat),
            47 => Some(WeatherSevereType::Heat),
            48 => Some(WeatherSevereType::Weather),
            49 => Some(WeatherSevereType::HighHeatAndHumidity),
            50 => Some(WeatherSevereType::HumidexAndHealth),
            51 => Some(WeatherSevereType::Humidex),
            52 => Some(WeatherSevereType::Gale),
            53 => Some(WeatherSevereType::FreezingSpray),
            54 => Some(WeatherSevereType::SpecialMarine),
            55 => Some(WeatherSevereType::Squall),
            56 => Some(WeatherSevereType::StrongWind),
            57 => Some(WeatherSevereType::LakeWind),
            58 => Some(WeatherSevereType::MarineWeather),
            59 => Some(WeatherSevereType::Wind),
            60 => Some(WeatherSevereType::SmallCraftHazardousSeas),
            61 => Some(WeatherSevereType::HazardousSeas),
            62 => Some(WeatherSevereType::SmallCraft),
            63 => Some(WeatherSevereType::SmallCraftWinds),
            64 => Some(WeatherSevereType::SmallCraftRoughBar),
            65 => Some(WeatherSevereType::HighWaterLevel),
            66 => Some(WeatherSevereType::Ashfall),
            67 => Some(WeatherSevereType::FreezingFog),
            68 => Some(WeatherSevereType::DenseFog),
            69 => Some(WeatherSevereType::DenseSmoke),
            70 => Some(WeatherSevereType::BlowingDust),
            71 => Some(WeatherSevereType::HardFreeze),
            72 => Some(WeatherSevereType::Freeze),
            73 => Some(WeatherSevereType::Frost),
            74 => Some(WeatherSevereType::FireWeather),
            75 => Some(WeatherSevereType::Flood),
            76 => Some(WeatherSevereType::RipTide),
            77 => Some(WeatherSevereType::HighSurf),
            78 => Some(WeatherSevereType::Smog),
            79 => Some(WeatherSevereType::AirQuality),
            80 => Some(WeatherSevereType::BriskWind),
            81 => Some(WeatherSevereType::AirStagnation),
            82 => Some(WeatherSevereType::LowWater),
            83 => Some(WeatherSevereType::Hydrological),
            84 => Some(WeatherSevereType::SpecialWeather),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "unspecified" => Some(WeatherSevereType::Unspecified),
            "tornado" => Some(WeatherSevereType::Tornado),
            "tsunami" => Some(WeatherSevereType::Tsunami),
            "hurricane" => Some(WeatherSevereType::Hurricane),
            "extreme_wind" => Some(WeatherSevereType::ExtremeWind),
            "typhoon" => Some(WeatherSevereType::Typhoon),
            "inland_hurricane" => Some(WeatherSevereType::InlandHurricane),
            "hurricane_force_wind" => Some(WeatherSevereType::HurricaneForceWind),
            "waterspout" => Some(WeatherSevereType::Waterspout),
            "severe_thunderstorm" => Some(WeatherSevereType::SevereThunderstorm),
            "wreckhouse_winds" => Some(WeatherSevereType::WreckhouseWinds),
            "les_suetes_wind" => Some(WeatherSevereType::LesSuetesWind),
            "avalanche" => Some(WeatherSevereType::Avalanche),
            "flash_flood" => Some(WeatherSevereType::FlashFlood),
            "tropical_storm" => Some(WeatherSevereType::TropicalStorm),
            "inland_tropical_storm" => Some(WeatherSevereType::InlandTropicalStorm),
            "blizzard" => Some(WeatherSevereType::Blizzard),
            "ice_storm" => Some(WeatherSevereType::IceStorm),
            "freezing_rain" => Some(WeatherSevereType::FreezingRain),
            "debris_flow" => Some(WeatherSevereType::DebrisFlow),
            "flash_freeze" => Some(WeatherSevereType::FlashFreeze),
            "dust_storm" => Some(WeatherSevereType::DustStorm),
            "high_wind" => Some(WeatherSevereType::HighWind),
            "winter_storm" => Some(WeatherSevereType::WinterStorm),
            "heavy_freezing_spray" => Some(WeatherSevereType::HeavyFreezingSpray),
            "extreme_cold" => Some(WeatherSevereType::ExtremeCold),
            "wind_chill" => Some(WeatherSevereType::WindChill),
            "cold_wave" => Some(WeatherSevereType::ColdWave),
            "heavy_snow_alert" => Some(WeatherSevereType::HeavySnowAlert),
            "lake_effect_blowing_snow" => Some(WeatherSevereType::LakeEffectBlowingSnow),
            "snow_squall" => Some(WeatherSevereType::SnowSquall),
            "lake_effect_snow" => Some(WeatherSevereType::LakeEffectSnow),
            "winter_weather" => Some(WeatherSevereType::WinterWeather),
            "sleet" => Some(WeatherSevereType::Sleet),
            "snowfall" => Some(WeatherSevereType::Snowfall),
            "snow_and_blowing_snow" => Some(WeatherSevereType::SnowAndBlowingSnow),
            "blowing_snow" => Some(WeatherSevereType::BlowingSnow),
            "snow_alert" => Some(WeatherSevereType::SnowAlert),
            "arctic_outflow" => Some(WeatherSevereType::ArcticOutflow),
            "freezing_drizzle" => Some(WeatherSevereType::FreezingDrizzle),
            "storm" => Some(WeatherSevereType::Storm),
            "storm_surge" => Some(WeatherSevereType::StormSurge),
            "rainfall" => Some(WeatherSevereType::Rainfall),
            "areal_flood" => Some(WeatherSevereType::ArealFlood),
            "coastal_flood" => Some(WeatherSevereType::CoastalFlood),
            "lakeshore_flood" => Some(WeatherSevereType::LakeshoreFlood),
            "excessive_heat" => Some(WeatherSevereType::ExcessiveHeat),
            "heat" => Some(WeatherSevereType::Heat),
            "weather" => Some(WeatherSevereType::Weather),
            "high_heat_and_humidity" => Some(WeatherSevereType::HighHeatAndHumidity),
            "humidex_and_health" => Some(WeatherSevereType::HumidexAndHealth),
            "humidex" => Some(WeatherSevereType::Humidex),
            "gale" => Some(WeatherSevereType::Gale),
            "freezing_spray" => Some(WeatherSevereType::FreezingSpray),
            "special_marine" => Some(WeatherSevereType::SpecialMarine),
            "squall" => Some(WeatherSevereType::Squall),
            "strong_wind" => Some(WeatherSevereType::StrongWind),
            "lake_wind" => Some(WeatherSevereType::LakeWind),
            "marine_weather" => Some(WeatherSevereType::MarineWeather),
            "wind" => Some(WeatherSevereType::Wind),
            "small_craft_hazardous_seas" => Some(WeatherSevereType::SmallCraftHazardousSeas),
            "hazardous_seas" => Some(WeatherSevereType::HazardousSeas),
            "small_craft" => Some(WeatherSevereType::SmallCraft),
            "small_craft_winds" => Some(WeatherSevereType::SmallCraftWinds),
            "small_craft_rough_bar" => Some(WeatherSevereType::SmallCraftRoughBar),
            "high_water_level" => Some(WeatherSevereType::HighWaterLevel),
            "ashfall" => Some(WeatherSevereType::Ashfall),
            "freezing_fog" => Some(WeatherSevereType::FreezingFog),
            "dense_fog" => Some(WeatherSevereType::DenseFog),
            "dense_smoke" => Some(WeatherSevereType::DenseSmoke),
            "blowing_dust" => Some(WeatherSevereType::BlowingDust),
            "hard_freeze" => Some(WeatherSevereType::HardFreeze),
            "freeze" => Some(WeatherSevereType::Freeze),
            "frost" => Some(WeatherSevereType::Frost),
            "fire_weather" => Some(WeatherSevereType::FireWeather),
            "flood" => Some(WeatherSevereType::Flood),
            "rip_tide" => Some(WeatherSevereType::RipTide),
            "high_surf" => Some(WeatherSevereType::HighSurf),
            "smog" => Some(WeatherSevereType::Smog),
            "air_quality" => Some(WeatherSevereType::AirQuality),
            "brisk_wind" => Some(WeatherSevereType::BriskWind),
            "air_stagnation" => Some(WeatherSevereType::AirStagnation),
            "low_water" => Some(WeatherSevereType::LowWater),
            "hydrological" => Some(WeatherSevereType::Hydrological),
            "special_weather" => Some(WeatherSevereType::SpecialWeather),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum StrokeType {
    NoEvent = 0,
    Other = 1,
    Serve = 2,
    Forehand = 3,
    Backhand = 4,
    Smash = 5,
}

impl StrokeType {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            StrokeType::NoEvent => "no_event",
            StrokeType::Other => "other",
            StrokeType::Serve => "serve",
            StrokeType::Forehand => "forehand",
            StrokeType::Backhand => "backhand",
            StrokeType::Smash => "smash",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(StrokeType::NoEvent),
            1 => Some(StrokeType::Other),
            2 => Some(StrokeType::Serve),
            3 => Some(StrokeType::Forehand),
            4 => Some(StrokeType::Backhand),
            5 => Some(StrokeType::Smash),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "no_event" => Some(StrokeType::NoEvent),
            "other" => Some(StrokeType::Other),
            "serve" => Some(StrokeType::Serve),
            "forehand" => Some(StrokeType::Forehand),
            "backhand" => Some(StrokeType::Backhand),
            "smash" => Some(StrokeType::Smash),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum BodyLocation {
    LeftLeg = 0,
    LeftCalf = 1,
    LeftShin = 2,
    LeftHamstring = 3,
    LeftQuad = 4,
    LeftGlute = 5,
    RightLeg = 6,
    RightCalf = 7,
    RightShin = 8,
    RightHamstring = 9,
    RightQuad = 10,
    RightGlute = 11,
    TorsoBack = 12,
    LeftLowerBack = 13,
    LeftUpperBack = 14,
    RightLowerBack = 15,
    RightUpperBack = 16,
    TorsoFront = 17,
    LeftAbdomen = 18,
    LeftChest = 19,
    RightAbdomen = 20,
    RightChest = 21,
    LeftArm = 22,
    LeftShoulder = 23,
    LeftBicep = 24,
    LeftTricep = 25,
    LeftBrachioradialis = 26,
    LeftForearmExtensors = 27,
    RightArm = 28,
    RightShoulder = 29,
    RightBicep = 30,
    RightTricep = 31,
    RightBrachioradialis = 32,
    RightForearmExtensors = 33,
    Neck = 34,
    Throat = 35,
    WaistMidBack = 36,
    WaistFront = 37,
    WaistLeft = 38,
    WaistRight = 39,
}

impl BodyLocation {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            BodyLocation::LeftLeg => "left_leg",
            BodyLocation::LeftCalf => "left_calf",
            BodyLocation::LeftShin => "left_shin",
            BodyLocation::LeftHamstring => "left_hamstring",
            BodyLocation::LeftQuad => "left_quad",
            BodyLocation::LeftGlute => "left_glute",
            BodyLocation::RightLeg => "right_leg",
            BodyLocation::RightCalf => "right_calf",
            BodyLocation::RightShin => "right_shin",
            BodyLocation::RightHamstring => "right_hamstring",
            BodyLocation::RightQuad => "right_quad",
            BodyLocation::RightGlute => "right_glute",
            BodyLocation::TorsoBack => "torso_back",
            BodyLocation::LeftLowerBack => "left_lower_back",
            BodyLocation::LeftUpperBack => "left_upper_back",
            BodyLocation::RightLowerBack => "right_lower_back",
            BodyLocation::RightUpperBack => "right_upper_back",
            BodyLocation::TorsoFront => "torso_front",
            BodyLocation::LeftAbdomen => "left_abdomen",
            BodyLocation::LeftChest => "left_chest",
            BodyLocation::RightAbdomen => "right_abdomen",
            BodyLocation::RightChest => "right_chest",
            BodyLocation::LeftArm => "left_arm",
            BodyLocation::LeftShoulder => "left_shoulder",
            BodyLocation::LeftBicep => "left_bicep",
            BodyLocation::LeftTricep => "left_tricep",
            BodyLocation::LeftBrachioradialis => "left_brachioradialis",
            BodyLocation::LeftForearmExtensors => "left_forearm_extensors",
            BodyLocation::RightArm => "right_arm",
            BodyLocation::RightShoulder => "right_shoulder",
            BodyLocation::RightBicep => "right_bicep",
            BodyLocation::RightTricep => "right_tricep",
            BodyLocation::RightBrachioradialis => "right_brachioradialis",
            BodyLocation::RightForearmExtensors => "right_forearm_extensors",
            BodyLocation::Neck => "neck",
            BodyLocation::Throat => "throat",
            BodyLocation::WaistMidBack => "waist_mid_back",
            BodyLocation::WaistFront => "waist_front",
            BodyLocation::WaistLeft => "waist_left",
            BodyLocation::WaistRight => "waist_right",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(BodyLocation::LeftLeg),
            1 => Some(BodyLocation::LeftCalf),
            2 => Some(BodyLocation::LeftShin),
            3 => Some(BodyLocation::LeftHamstring),
            4 => Some(BodyLocation::LeftQuad),
            5 => Some(BodyLocation::LeftGlute),
            6 => Some(BodyLocation::RightLeg),
            7 => Some(BodyLocation::RightCalf),
            8 => Some(BodyLocation::RightShin),
            9 => Some(BodyLocation::RightHamstring),
            10 => Some(BodyLocation::RightQuad),
            11 => Some(BodyLocation::RightGlute),
            12 => Some(BodyLocation::TorsoBack),
            13 => Some(BodyLocation::LeftLowerBack),
            14 => Some(BodyLocation::LeftUpperBack),
            15 => Some(BodyLocation::RightLowerBack),
            16 => Some(BodyLocation::RightUpperBack),
            17 => Some(BodyLocation::TorsoFront),
            18 => Some(BodyLocation::LeftAbdomen),
            19 => Some(BodyLocation::LeftChest),
            20 => Some(BodyLocation::RightAbdomen),
            21 => Some(BodyLocation::RightChest),
            22 => Some(BodyLocation::LeftArm),
            23 => Some(BodyLocation::LeftShoulder),
            24 => Some(BodyLocation::LeftBicep),
            25 => Some(BodyLocation::LeftTricep),
            26 => Some(BodyLocation::LeftBrachioradialis),
            27 => Some(BodyLocation::LeftForearmExtensors),
            28 => Some(BodyLocation::RightArm),
            29 => Some(BodyLocation::RightShoulder),
            30 => Some(BodyLocation::RightBicep),
            31 => Some(BodyLocation::RightTricep),
            32 => Some(BodyLocation::RightBrachioradialis),
            33 => Some(BodyLocation::RightForearmExtensors),
            34 => Some(BodyLocation::Neck),
            35 => Some(BodyLocation::Throat),
            36 => Some(BodyLocation::WaistMidBack),
            37 => Some(BodyLocation::WaistFront),
            38 => Some(BodyLocation::WaistLeft),
            39 => Some(BodyLocation::WaistRight),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "left_leg" => Some(BodyLocation::LeftLeg),
            "left_calf" => Some(BodyLocation::LeftCalf),
            "left_shin" => Some(BodyLocation::LeftShin),
            "left_hamstring" => Some(BodyLocation::LeftHamstring),
            "left_quad" => Some(BodyLocation::LeftQuad),
            "left_glute" => Some(BodyLocation::LeftGlute),
            "right_leg" => Some(BodyLocation::RightLeg),
            "right_calf" => Some(BodyLocation::RightCalf),
            "right_shin" => Some(BodyLocation::RightShin),
            "right_hamstring" => Some(BodyLocation::RightHamstring),
            "right_quad" => Some(BodyLocation::RightQuad),
            "right_glute" => Some(BodyLocation::RightGlute),
            "torso_back" => Some(BodyLocation::TorsoBack),
            "left_lower_back" => Some(BodyLocation::LeftLowerBack),
            "left_upper_back" => Some(BodyLocation::LeftUpperBack),
            "right_lower_back" => Some(BodyLocation::RightLowerBack),
            "right_upper_back" => Some(BodyLocation::RightUpperBack),
            "torso_front" => Some(BodyLocation::TorsoFront),
            "left_abdomen" => Some(BodyLocation::LeftAbdomen),
            "left_chest" => Some(BodyLocation::LeftChest),
            "right_abdomen" => Some(BodyLocation::RightAbdomen),
            "right_chest" => Some(BodyLocation::RightChest),
            "left_arm" => Some(BodyLocation::LeftArm),
            "left_shoulder" => Some(BodyLocation::LeftShoulder),
            "left_bicep" => Some(BodyLocation::LeftBicep),
            "left_tricep" => Some(BodyLocation::LeftTricep),
            "left_brachioradialis" => Some(BodyLocation::LeftBrachioradialis),
            "left_forearm_extensors" => Some(BodyLocation::LeftForearmExtensors),
            "right_arm" => Some(BodyLocation::RightArm),
            "right_shoulder" => Some(BodyLocation::RightShoulder),
            "right_bicep" => Some(BodyLocation::RightBicep),
            "right_tricep" => Some(BodyLocation::RightTricep),
            "right_brachioradialis" => Some(BodyLocation::RightBrachioradialis),
            "right_forearm_extensors" => Some(BodyLocation::RightForearmExtensors),
            "neck" => Some(BodyLocation::Neck),
            "throat" => Some(BodyLocation::Throat),
            "waist_mid_back" => Some(BodyLocation::WaistMidBack),
            "waist_front" => Some(BodyLocation::WaistFront),
            "waist_left" => Some(BodyLocation::WaistLeft),
            "waist_right" => Some(BodyLocation::WaistRight),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum SegmentLapStatus {
    End = 0,
    Fail = 1,
}

impl SegmentLapStatus {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            SegmentLapStatus::End => "end",
            SegmentLapStatus::Fail => "fail",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(SegmentLapStatus::End),
            1 => Some(SegmentLapStatus::Fail),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "end" => Some(SegmentLapStatus::End),
            "fail" => Some(SegmentLapStatus::Fail),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum SegmentLeaderboardType {
    Overall = 0,
    PersonalBest = 1,
    Connections = 2,
    Group = 3,
    Challenger = 4,
    Kom = 5,
    Qom = 6,
    Pr = 7,
    Goal = 8,
    Carrot = 9,
    ClubLeader = 10,
    Rival = 11,
    Last = 12,
    RecentBest = 13,
    CourseRecord = 14,
}

impl SegmentLeaderboardType {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            SegmentLeaderboardType::Overall => "overall",
            SegmentLeaderboardType::PersonalBest => "personal_best",
            SegmentLeaderboardType::Connections => "connections",
            SegmentLeaderboardType::Group => "group",
            SegmentLeaderboardType::Challenger => "challenger",
            SegmentLeaderboardType::Kom => "kom",
            SegmentLeaderboardType::Qom => "qom",
            SegmentLeaderboardType::Pr => "pr",
            SegmentLeaderboardType::Goal => "goal",
            SegmentLeaderboardType::Carrot => "carrot",
            SegmentLeaderboardType::ClubLeader => "club_leader",
            SegmentLeaderboardType::Rival => "rival",
            SegmentLeaderboardType::Last => "last",
            SegmentLeaderboardType::RecentBest => "recent_best",
            SegmentLeaderboardType::CourseRecord => "course_record",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(SegmentLeaderboardType::Overall),
            1 => Some(SegmentLeaderboardType::PersonalBest),
            2 => Some(SegmentLeaderboardType::Connections),
            3 => Some(SegmentLeaderboardType::Group),
            4 => Some(SegmentLeaderboardType::Challenger),
            5 => Some(SegmentLeaderboardType::Kom),
            6 => Some(SegmentLeaderboardType::Qom),
            7 => Some(SegmentLeaderboardType::Pr),
            8 => Some(SegmentLeaderboardType::Goal),
            9 => Some(SegmentLeaderboardType::Carrot),
            10 => Some(SegmentLeaderboardType::ClubLeader),
            11 => Some(SegmentLeaderboardType::Rival),
            12 => Some(SegmentLeaderboardType::Last),
            13 => Some(SegmentLeaderboardType::RecentBest),
            14 => Some(SegmentLeaderboardType::CourseRecord),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "overall" => Some(SegmentLeaderboardType::Overall),
            "personal_best" => Some(SegmentLeaderboardType::PersonalBest),
            "connections" => Some(SegmentLeaderboardType::Connections),
            "group" => Some(SegmentLeaderboardType::Group),
            "challenger" => Some(SegmentLeaderboardType::Challenger),
            "kom" => Some(SegmentLeaderboardType::Kom),
            "qom" => Some(SegmentLeaderboardType::Qom),
            "pr" => Some(SegmentLeaderboardType::Pr),
            "goal" => Some(SegmentLeaderboardType::Goal),
            "carrot" => Some(SegmentLeaderboardType::Carrot),
            "club_leader" => Some(SegmentLeaderboardType::ClubLeader),
            "rival" => Some(SegmentLeaderboardType::Rival),
            "last" => Some(SegmentLeaderboardType::Last),
            "recent_best" => Some(SegmentLeaderboardType::RecentBest),
            "course_record" => Some(SegmentLeaderboardType::CourseRecord),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum SegmentDeleteStatus {
    DoNotDelete = 0,
    DeleteOne = 1,
    DeleteAll = 2,
}

impl SegmentDeleteStatus {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            SegmentDeleteStatus::DoNotDelete => "do_not_delete",
            SegmentDeleteStatus::DeleteOne => "delete_one",
            SegmentDeleteStatus::DeleteAll => "delete_all",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(SegmentDeleteStatus::DoNotDelete),
            1 => Some(SegmentDeleteStatus::DeleteOne),
            2 => Some(SegmentDeleteStatus::DeleteAll),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "do_not_delete" => Some(SegmentDeleteStatus::DoNotDelete),
            "delete_one" => Some(SegmentDeleteStatus::DeleteOne),
            "delete_all" => Some(SegmentDeleteStatus::DeleteAll),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum SegmentSelectionType {
    Starred = 0,
    Suggested = 1,
}

impl SegmentSelectionType {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            SegmentSelectionType::Starred => "starred",
            SegmentSelectionType::Suggested => "suggested",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(SegmentSelectionType::Starred),
            1 => Some(SegmentSelectionType::Suggested),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "starred" => Some(SegmentSelectionType::Starred),
            "suggested" => Some(SegmentSelectionType::Suggested),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum SourceType {
    Ant = 0,
    Antplus = 1,
    Bluetooth = 2,
    BluetoothLowEnergy = 3,
    Wifi = 4,
    Local = 5,
}

impl SourceType {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            SourceType::Ant => "ant",
            SourceType::Antplus => "antplus",
            SourceType::Bluetooth => "bluetooth",
            SourceType::BluetoothLowEnergy => "bluetooth_low_energy",
            SourceType::Wifi => "wifi",
            SourceType::Local => "local",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(SourceType::Ant),
            1 => Some(SourceType::Antplus),
            2 => Some(SourceType::Bluetooth),
            3 => Some(SourceType::BluetoothLowEnergy),
            4 => Some(SourceType::Wifi),
            5 => Some(SourceType::Local),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "ant" => Some(SourceType::Ant),
            "antplus" => Some(SourceType::Antplus),
            "bluetooth" => Some(SourceType::Bluetooth),
            "bluetooth_low_energy" => Some(SourceType::BluetoothLowEnergy),
            "wifi" => Some(SourceType::Wifi),
            "local" => Some(SourceType::Local),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum LocalDeviceType {
    Gps = 0,
    Glonass = 1,
    GpsGlonass = 2,
    Accelerometer = 3,
    Barometer = 4,
    Temperature = 5,
    Whr = 10,
    SensorHub = 12,
}

impl LocalDeviceType {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            LocalDeviceType::Gps => "gps",
            LocalDeviceType::Glonass => "glonass",
            LocalDeviceType::GpsGlonass => "gps_glonass",
            LocalDeviceType::Accelerometer => "accelerometer",
            LocalDeviceType::Barometer => "barometer",
            LocalDeviceType::Temperature => "temperature",
            LocalDeviceType::Whr => "whr",
            LocalDeviceType::SensorHub => "sensor_hub",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(LocalDeviceType::Gps),
            1 => Some(LocalDeviceType::Glonass),
            2 => Some(LocalDeviceType::GpsGlonass),
            3 => Some(LocalDeviceType::Accelerometer),
            4 => Some(LocalDeviceType::Barometer),
            5 => Some(LocalDeviceType::Temperature),
            10 => Some(LocalDeviceType::Whr),
            12 => Some(LocalDeviceType::SensorHub),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "gps" => Some(LocalDeviceType::Gps),
            "glonass" => Some(LocalDeviceType::Glonass),
            "gps_glonass" => Some(LocalDeviceType::GpsGlonass),
            "accelerometer" => Some(LocalDeviceType::Accelerometer),
            "barometer" => Some(LocalDeviceType::Barometer),
            "temperature" => Some(LocalDeviceType::Temperature),
            "whr" => Some(LocalDeviceType::Whr),
            "sensor_hub" => Some(LocalDeviceType::SensorHub),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum BleDeviceType {
    ConnectedGps = 0,
    HeartRate = 1,
    BikePower = 2,
    BikeSpeedCadence = 3,
    BikeSpeed = 4,
    BikeCadence = 5,
    Footpod = 6,
    BikeTrainer = 7,
}

impl BleDeviceType {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            BleDeviceType::ConnectedGps => "connected_gps",
            BleDeviceType::HeartRate => "heart_rate",
            BleDeviceType::BikePower => "bike_power",
            BleDeviceType::BikeSpeedCadence => "bike_speed_cadence",
            BleDeviceType::BikeSpeed => "bike_speed",
            BleDeviceType::BikeCadence => "bike_cadence",
            BleDeviceType::Footpod => "footpod",
            BleDeviceType::BikeTrainer => "bike_trainer",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(BleDeviceType::ConnectedGps),
            1 => Some(BleDeviceType::HeartRate),
            2 => Some(BleDeviceType::BikePower),
            3 => Some(BleDeviceType::BikeSpeedCadence),
            4 => Some(BleDeviceType::BikeSpeed),
            5 => Some(BleDeviceType::BikeCadence),
            6 => Some(BleDeviceType::Footpod),
            7 => Some(BleDeviceType::BikeTrainer),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "connected_gps" => Some(BleDeviceType::ConnectedGps),
            "heart_rate" => Some(BleDeviceType::HeartRate),
            "bike_power" => Some(BleDeviceType::BikePower),
            "bike_speed_cadence" => Some(BleDeviceType::BikeSpeedCadence),
            "bike_speed" => Some(BleDeviceType::BikeSpeed),
            "bike_cadence" => Some(BleDeviceType::BikeCadence),
            "footpod" => Some(BleDeviceType::Footpod),
            "bike_trainer" => Some(BleDeviceType::BikeTrainer),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u32)]
#[non_exhaustive]
pub enum AntChannelId {
    AntExtendedDeviceNumberUpperNibble = 4026531840,
    AntTransmissionTypeLowerNibble = 251658240,
    AntDeviceType = 16711680,
    AntDeviceNumber = 65535,
}

impl AntChannelId {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            AntChannelId::AntExtendedDeviceNumberUpperNibble => {
                "ant_extended_device_number_upper_nibble"
            }
            AntChannelId::AntTransmissionTypeLowerNibble => "ant_transmission_type_lower_nibble",
            AntChannelId::AntDeviceType => "ant_device_type",
            AntChannelId::AntDeviceNumber => "ant_device_number",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u32) -> Option<Self> {
        match value {
            4026531840 => Some(AntChannelId::AntExtendedDeviceNumberUpperNibble),
            251658240 => Some(AntChannelId::AntTransmissionTypeLowerNibble),
            16711680 => Some(AntChannelId::AntDeviceType),
            65535 => Some(AntChannelId::AntDeviceNumber),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "ant_extended_device_number_upper_nibble" => {
                Some(AntChannelId::AntExtendedDeviceNumberUpperNibble)
            }
            "ant_transmission_type_lower_nibble" => {
                Some(AntChannelId::AntTransmissionTypeLowerNibble)
            }
            "ant_device_type" => Some(AntChannelId::AntDeviceType),
            "ant_device_number" => Some(AntChannelId::AntDeviceNumber),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum DisplayOrientation {
    Auto = 0,
    Portrait = 1,
    Landscape = 2,
    PortraitFlipped = 3,
    LandscapeFlipped = 4,
}

impl DisplayOrientation {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            DisplayOrientation::Auto => "auto",
            DisplayOrientation::Portrait => "portrait",
            DisplayOrientation::Landscape => "landscape",
            DisplayOrientation::PortraitFlipped => "portrait_flipped",
            DisplayOrientation::LandscapeFlipped => "landscape_flipped",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(DisplayOrientation::Auto),
            1 => Some(DisplayOrientation::Portrait),
            2 => Some(DisplayOrientation::Landscape),
            3 => Some(DisplayOrientation::PortraitFlipped),
            4 => Some(DisplayOrientation::LandscapeFlipped),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "auto" => Some(DisplayOrientation::Auto),
            "portrait" => Some(DisplayOrientation::Portrait),
            "landscape" => Some(DisplayOrientation::Landscape),
            "portrait_flipped" => Some(DisplayOrientation::PortraitFlipped),
            "landscape_flipped" => Some(DisplayOrientation::LandscapeFlipped),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum WorkoutEquipment {
    None = 0,
    SwimFins = 1,
    SwimKickboard = 2,
    SwimPaddles = 3,
    SwimPullBuoy = 4,
    SwimSnorkel = 5,
}

impl WorkoutEquipment {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            WorkoutEquipment::None => "none",
            WorkoutEquipment::SwimFins => "swim_fins",
            WorkoutEquipment::SwimKickboard => "swim_kickboard",
            WorkoutEquipment::SwimPaddles => "swim_paddles",
            WorkoutEquipment::SwimPullBuoy => "swim_pull_buoy",
            WorkoutEquipment::SwimSnorkel => "swim_snorkel",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(WorkoutEquipment::None),
            1 => Some(WorkoutEquipment::SwimFins),
            2 => Some(WorkoutEquipment::SwimKickboard),
            3 => Some(WorkoutEquipment::SwimPaddles),
            4 => Some(WorkoutEquipment::SwimPullBuoy),
            5 => Some(WorkoutEquipment::SwimSnorkel),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "none" => Some(WorkoutEquipment::None),
            "swim_fins" => Some(WorkoutEquipment::SwimFins),
            "swim_kickboard" => Some(WorkoutEquipment::SwimKickboard),
            "swim_paddles" => Some(WorkoutEquipment::SwimPaddles),
            "swim_pull_buoy" => Some(WorkoutEquipment::SwimPullBuoy),
            "swim_snorkel" => Some(WorkoutEquipment::SwimSnorkel),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum WatchfaceMode {
    Digital = 0,
    Analog = 1,
    ConnectIq = 2,
    Disabled = 3,
}

impl WatchfaceMode {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            WatchfaceMode::Digital => "digital",
            WatchfaceMode::Analog => "analog",
            WatchfaceMode::ConnectIq => "connect_iq",
            WatchfaceMode::Disabled => "disabled",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(WatchfaceMode::Digital),
            1 => Some(WatchfaceMode::Analog),
            2 => Some(WatchfaceMode::ConnectIq),
            3 => Some(WatchfaceMode::Disabled),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "digital" => Some(WatchfaceMode::Digital),
            "analog" => Some(WatchfaceMode::Analog),
            "connect_iq" => Some(WatchfaceMode::ConnectIq),
            "disabled" => Some(WatchfaceMode::Disabled),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum DigitalWatchfaceLayout {
    Traditional = 0,
    Modern = 1,
    Bold = 2,
}

impl DigitalWatchfaceLayout {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            DigitalWatchfaceLayout::Traditional => "traditional",
            DigitalWatchfaceLayout::Modern => "modern",
            DigitalWatchfaceLayout::Bold => "bold",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(DigitalWatchfaceLayout::Traditional),
            1 => Some(DigitalWatchfaceLayout::Modern),
            2 => Some(DigitalWatchfaceLayout::Bold),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "traditional" => Some(DigitalWatchfaceLayout::Traditional),
            "modern" => Some(DigitalWatchfaceLayout::Modern),
            "bold" => Some(DigitalWatchfaceLayout::Bold),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum AnalogWatchfaceLayout {
    Minimal = 0,
    Traditional = 1,
    Modern = 2,
}

impl AnalogWatchfaceLayout {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            AnalogWatchfaceLayout::Minimal => "minimal",
            AnalogWatchfaceLayout::Traditional => "traditional",
            AnalogWatchfaceLayout::Modern => "modern",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(AnalogWatchfaceLayout::Minimal),
            1 => Some(AnalogWatchfaceLayout::Traditional),
            2 => Some(AnalogWatchfaceLayout::Modern),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "minimal" => Some(AnalogWatchfaceLayout::Minimal),
            "traditional" => Some(AnalogWatchfaceLayout::Traditional),
            "modern" => Some(AnalogWatchfaceLayout::Modern),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum RiderPositionType {
    Seated = 0,
    Standing = 1,
    TransitionToSeated = 2,
    TransitionToStanding = 3,
}

impl RiderPositionType {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            RiderPositionType::Seated => "seated",
            RiderPositionType::Standing => "standing",
            RiderPositionType::TransitionToSeated => "transition_to_seated",
            RiderPositionType::TransitionToStanding => "transition_to_standing",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(RiderPositionType::Seated),
            1 => Some(RiderPositionType::Standing),
            2 => Some(RiderPositionType::TransitionToSeated),
            3 => Some(RiderPositionType::TransitionToStanding),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "seated" => Some(RiderPositionType::Seated),
            "standing" => Some(RiderPositionType::Standing),
            "transition_to_seated" => Some(RiderPositionType::TransitionToSeated),
            "transition_to_standing" => Some(RiderPositionType::TransitionToStanding),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum PowerPhaseType {
    PowerPhaseStartAngle = 0,
    PowerPhaseEndAngle = 1,
    PowerPhaseArcLength = 2,
    PowerPhaseCenter = 3,
}

impl PowerPhaseType {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            PowerPhaseType::PowerPhaseStartAngle => "power_phase_start_angle",
            PowerPhaseType::PowerPhaseEndAngle => "power_phase_end_angle",
            PowerPhaseType::PowerPhaseArcLength => "power_phase_arc_length",
            PowerPhaseType::PowerPhaseCenter => "power_phase_center",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(PowerPhaseType::PowerPhaseStartAngle),
            1 => Some(PowerPhaseType::PowerPhaseEndAngle),
            2 => Some(PowerPhaseType::PowerPhaseArcLength),
            3 => Some(PowerPhaseType::PowerPhaseCenter),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "power_phase_start_angle" => Some(PowerPhaseType::PowerPhaseStartAngle),
            "power_phase_end_angle" => Some(PowerPhaseType::PowerPhaseEndAngle),
            "power_phase_arc_length" => Some(PowerPhaseType::PowerPhaseArcLength),
            "power_phase_center" => Some(PowerPhaseType::PowerPhaseCenter),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum CameraEventType {
    VideoStart = 0,
    VideoSplit = 1,
    VideoEnd = 2,
    PhotoTaken = 3,
    VideoSecondStreamStart = 4,
    VideoSecondStreamSplit = 5,
    VideoSecondStreamEnd = 6,
    VideoSplitStart = 7,
    VideoSecondStreamSplitStart = 8,
    VideoPause = 11,
    VideoSecondStreamPause = 12,
    VideoResume = 13,
    VideoSecondStreamResume = 14,
}

impl CameraEventType {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            CameraEventType::VideoStart => "video_start",
            CameraEventType::VideoSplit => "video_split",
            CameraEventType::VideoEnd => "video_end",
            CameraEventType::PhotoTaken => "photo_taken",
            CameraEventType::VideoSecondStreamStart => "video_second_stream_start",
            CameraEventType::VideoSecondStreamSplit => "video_second_stream_split",
            CameraEventType::VideoSecondStreamEnd => "video_second_stream_end",
            CameraEventType::VideoSplitStart => "video_split_start",
            CameraEventType::VideoSecondStreamSplitStart => "video_second_stream_split_start",
            CameraEventType::VideoPause => "video_pause",
            CameraEventType::VideoSecondStreamPause => "video_second_stream_pause",
            CameraEventType::VideoResume => "video_resume",
            CameraEventType::VideoSecondStreamResume => "video_second_stream_resume",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(CameraEventType::VideoStart),
            1 => Some(CameraEventType::VideoSplit),
            2 => Some(CameraEventType::VideoEnd),
            3 => Some(CameraEventType::PhotoTaken),
            4 => Some(CameraEventType::VideoSecondStreamStart),
            5 => Some(CameraEventType::VideoSecondStreamSplit),
            6 => Some(CameraEventType::VideoSecondStreamEnd),
            7 => Some(CameraEventType::VideoSplitStart),
            8 => Some(CameraEventType::VideoSecondStreamSplitStart),
            11 => Some(CameraEventType::VideoPause),
            12 => Some(CameraEventType::VideoSecondStreamPause),
            13 => Some(CameraEventType::VideoResume),
            14 => Some(CameraEventType::VideoSecondStreamResume),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "video_start" => Some(CameraEventType::VideoStart),
            "video_split" => Some(CameraEventType::VideoSplit),
            "video_end" => Some(CameraEventType::VideoEnd),
            "photo_taken" => Some(CameraEventType::PhotoTaken),
            "video_second_stream_start" => Some(CameraEventType::VideoSecondStreamStart),
            "video_second_stream_split" => Some(CameraEventType::VideoSecondStreamSplit),
            "video_second_stream_end" => Some(CameraEventType::VideoSecondStreamEnd),
            "video_split_start" => Some(CameraEventType::VideoSplitStart),
            "video_second_stream_split_start" => Some(CameraEventType::VideoSecondStreamSplitStart),
            "video_pause" => Some(CameraEventType::VideoPause),
            "video_second_stream_pause" => Some(CameraEventType::VideoSecondStreamPause),
            "video_resume" => Some(CameraEventType::VideoResume),
            "video_second_stream_resume" => Some(CameraEventType::VideoSecondStreamResume),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum SensorType {
    Accelerometer = 0,
    Gyroscope = 1,
    Compass = 2,
    Barometer = 3,
}

impl SensorType {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            SensorType::Accelerometer => "accelerometer",
            SensorType::Gyroscope => "gyroscope",
            SensorType::Compass => "compass",
            SensorType::Barometer => "barometer",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(SensorType::Accelerometer),
            1 => Some(SensorType::Gyroscope),
            2 => Some(SensorType::Compass),
            3 => Some(SensorType::Barometer),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "accelerometer" => Some(SensorType::Accelerometer),
            "gyroscope" => Some(SensorType::Gyroscope),
            "compass" => Some(SensorType::Compass),
            "barometer" => Some(SensorType::Barometer),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum BikeLightNetworkConfigType {
    Auto = 0,
    Individual = 4,
    HighVisibility = 5,
    Trail = 6,
}

impl BikeLightNetworkConfigType {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            BikeLightNetworkConfigType::Auto => "auto",
            BikeLightNetworkConfigType::Individual => "individual",
            BikeLightNetworkConfigType::HighVisibility => "high_visibility",
            BikeLightNetworkConfigType::Trail => "trail",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(BikeLightNetworkConfigType::Auto),
            4 => Some(BikeLightNetworkConfigType::Individual),
            5 => Some(BikeLightNetworkConfigType::HighVisibility),
            6 => Some(BikeLightNetworkConfigType::Trail),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "auto" => Some(BikeLightNetworkConfigType::Auto),
            "individual" => Some(BikeLightNetworkConfigType::Individual),
            "high_visibility" => Some(BikeLightNetworkConfigType::HighVisibility),
            "trail" => Some(BikeLightNetworkConfigType::Trail),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum CommTimeoutType {
    WildcardPairingTimeout = 0,
    PairingTimeout = 1,
    ConnectionLost = 2,
    ConnectionTimeout = 3,
}

impl CommTimeoutType {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            CommTimeoutType::WildcardPairingTimeout => "wildcard_pairing_timeout",
            CommTimeoutType::PairingTimeout => "pairing_timeout",
            CommTimeoutType::ConnectionLost => "connection_lost",
            CommTimeoutType::ConnectionTimeout => "connection_timeout",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(CommTimeoutType::WildcardPairingTimeout),
            1 => Some(CommTimeoutType::PairingTimeout),
            2 => Some(CommTimeoutType::ConnectionLost),
            3 => Some(CommTimeoutType::ConnectionTimeout),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "wildcard_pairing_timeout" => Some(CommTimeoutType::WildcardPairingTimeout),
            "pairing_timeout" => Some(CommTimeoutType::PairingTimeout),
            "connection_lost" => Some(CommTimeoutType::ConnectionLost),
            "connection_timeout" => Some(CommTimeoutType::ConnectionTimeout),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum CameraOrientationType {
    CameraOrientation0 = 0,
    CameraOrientation90 = 1,
    CameraOrientation180 = 2,
    CameraOrientation270 = 3,
}

impl CameraOrientationType {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            CameraOrientationType::CameraOrientation0 => "camera_orientation_0",
            CameraOrientationType::CameraOrientation90 => "camera_orientation_90",
            CameraOrientationType::CameraOrientation180 => "camera_orientation_180",
            CameraOrientationType::CameraOrientation270 => "camera_orientation_270",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(CameraOrientationType::CameraOrientation0),
            1 => Some(CameraOrientationType::CameraOrientation90),
            2 => Some(CameraOrientationType::CameraOrientation180),
            3 => Some(CameraOrientationType::CameraOrientation270),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "camera_orientation_0" => Some(CameraOrientationType::CameraOrientation0),
            "camera_orientation_90" => Some(CameraOrientationType::CameraOrientation90),
            "camera_orientation_180" => Some(CameraOrientationType::CameraOrientation180),
            "camera_orientation_270" => Some(CameraOrientationType::CameraOrientation270),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum AttitudeStage {
    Failed = 0,
    Aligning = 1,
    Degraded = 2,
    Valid = 3,
}

impl AttitudeStage {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            AttitudeStage::Failed => "failed",
            AttitudeStage::Aligning => "aligning",
            AttitudeStage::Degraded => "degraded",
            AttitudeStage::Valid => "valid",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(AttitudeStage::Failed),
            1 => Some(AttitudeStage::Aligning),
            2 => Some(AttitudeStage::Degraded),
            3 => Some(AttitudeStage::Valid),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "failed" => Some(AttitudeStage::Failed),
            "aligning" => Some(AttitudeStage::Aligning),
            "degraded" => Some(AttitudeStage::Degraded),
            "valid" => Some(AttitudeStage::Valid),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum AttitudeValidity {
    TrackAngleHeadingValid = 1,
    PitchValid = 2,
    RollValid = 4,
    LateralBodyAccelValid = 8,
    NormalBodyAccelValid = 16,
    TurnRateValid = 32,
    HwFail = 64,
    MagInvalid = 128,
    NoGps = 256,
    GpsInvalid = 512,
    SolutionCoasting = 1024,
    TrueTrackAngle = 2048,
    MagneticHeading = 4096,
}

impl AttitudeValidity {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            AttitudeValidity::TrackAngleHeadingValid => "track_angle_heading_valid",
            AttitudeValidity::PitchValid => "pitch_valid",
            AttitudeValidity::RollValid => "roll_valid",
            AttitudeValidity::LateralBodyAccelValid => "lateral_body_accel_valid",
            AttitudeValidity::NormalBodyAccelValid => "normal_body_accel_valid",
            AttitudeValidity::TurnRateValid => "turn_rate_valid",
            AttitudeValidity::HwFail => "hw_fail",
            AttitudeValidity::MagInvalid => "mag_invalid",
            AttitudeValidity::NoGps => "no_gps",
            AttitudeValidity::GpsInvalid => "gps_invalid",
            AttitudeValidity::SolutionCoasting => "solution_coasting",
            AttitudeValidity::TrueTrackAngle => "true_track_angle",
            AttitudeValidity::MagneticHeading => "magnetic_heading",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            1 => Some(AttitudeValidity::TrackAngleHeadingValid),
            2 => Some(AttitudeValidity::PitchValid),
            4 => Some(AttitudeValidity::RollValid),
            8 => Some(AttitudeValidity::LateralBodyAccelValid),
            16 => Some(AttitudeValidity::NormalBodyAccelValid),
            32 => Some(AttitudeValidity::TurnRateValid),
            64 => Some(AttitudeValidity::HwFail),
            128 => Some(AttitudeValidity::MagInvalid),
            256 => Some(AttitudeValidity::NoGps),
            512 => Some(AttitudeValidity::GpsInvalid),
            1024 => Some(AttitudeValidity::SolutionCoasting),
            2048 => Some(AttitudeValidity::TrueTrackAngle),
            4096 => Some(AttitudeValidity::MagneticHeading),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "track_angle_heading_valid" => Some(AttitudeValidity::TrackAngleHeadingValid),
            "pitch_valid" => Some(AttitudeValidity::PitchValid),
            "roll_valid" => Some(AttitudeValidity::RollValid),
            "lateral_body_accel_valid" => Some(AttitudeValidity::LateralBodyAccelValid),
            "normal_body_accel_valid" => Some(AttitudeValidity::NormalBodyAccelValid),
            "turn_rate_valid" => Some(AttitudeValidity::TurnRateValid),
            "hw_fail" => Some(AttitudeValidity::HwFail),
            "mag_invalid" => Some(AttitudeValidity::MagInvalid),
            "no_gps" => Some(AttitudeValidity::NoGps),
            "gps_invalid" => Some(AttitudeValidity::GpsInvalid),
            "solution_coasting" => Some(AttitudeValidity::SolutionCoasting),
            "true_track_angle" => Some(AttitudeValidity::TrueTrackAngle),
            "magnetic_heading" => Some(AttitudeValidity::MagneticHeading),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum AutoSyncFrequency {
    Never = 0,
    Occasionally = 1,
    Frequent = 2,
    OnceADay = 3,
    Remote = 4,
}

impl AutoSyncFrequency {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            AutoSyncFrequency::Never => "never",
            AutoSyncFrequency::Occasionally => "occasionally",
            AutoSyncFrequency::Frequent => "frequent",
            AutoSyncFrequency::OnceADay => "once_a_day",
            AutoSyncFrequency::Remote => "remote",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(AutoSyncFrequency::Never),
            1 => Some(AutoSyncFrequency::Occasionally),
            2 => Some(AutoSyncFrequency::Frequent),
            3 => Some(AutoSyncFrequency::OnceADay),
            4 => Some(AutoSyncFrequency::Remote),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "never" => Some(AutoSyncFrequency::Never),
            "occasionally" => Some(AutoSyncFrequency::Occasionally),
            "frequent" => Some(AutoSyncFrequency::Frequent),
            "once_a_day" => Some(AutoSyncFrequency::OnceADay),
            "remote" => Some(AutoSyncFrequency::Remote),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum ExdLayout {
    FullScreen = 0,
    HalfVertical = 1,
    HalfHorizontal = 2,
    HalfVerticalRightSplit = 3,
    HalfHorizontalBottomSplit = 4,
    FullQuarterSplit = 5,
    HalfVerticalLeftSplit = 6,
    HalfHorizontalTopSplit = 7,
    Dynamic = 8,
}

impl ExdLayout {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            ExdLayout::FullScreen => "full_screen",
            ExdLayout::HalfVertical => "half_vertical",
            ExdLayout::HalfHorizontal => "half_horizontal",
            ExdLayout::HalfVerticalRightSplit => "half_vertical_right_split",
            ExdLayout::HalfHorizontalBottomSplit => "half_horizontal_bottom_split",
            ExdLayout::FullQuarterSplit => "full_quarter_split",
            ExdLayout::HalfVerticalLeftSplit => "half_vertical_left_split",
            ExdLayout::HalfHorizontalTopSplit => "half_horizontal_top_split",
            ExdLayout::Dynamic => "dynamic",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(ExdLayout::FullScreen),
            1 => Some(ExdLayout::HalfVertical),
            2 => Some(ExdLayout::HalfHorizontal),
            3 => Some(ExdLayout::HalfVerticalRightSplit),
            4 => Some(ExdLayout::HalfHorizontalBottomSplit),
            5 => Some(ExdLayout::FullQuarterSplit),
            6 => Some(ExdLayout::HalfVerticalLeftSplit),
            7 => Some(ExdLayout::HalfHorizontalTopSplit),
            8 => Some(ExdLayout::Dynamic),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "full_screen" => Some(ExdLayout::FullScreen),
            "half_vertical" => Some(ExdLayout::HalfVertical),
            "half_horizontal" => Some(ExdLayout::HalfHorizontal),
            "half_vertical_right_split" => Some(ExdLayout::HalfVerticalRightSplit),
            "half_horizontal_bottom_split" => Some(ExdLayout::HalfHorizontalBottomSplit),
            "full_quarter_split" => Some(ExdLayout::FullQuarterSplit),
            "half_vertical_left_split" => Some(ExdLayout::HalfVerticalLeftSplit),
            "half_horizontal_top_split" => Some(ExdLayout::HalfHorizontalTopSplit),
            "dynamic" => Some(ExdLayout::Dynamic),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum ExdDisplayType {
    Numerical = 0,
    Simple = 1,
    Graph = 2,
    Bar = 3,
    CircleGraph = 4,
    VirtualPartner = 5,
    Balance = 6,
    StringList = 7,
    String = 8,
    SimpleDynamicIcon = 9,
    Gauge = 10,
}

impl ExdDisplayType {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            ExdDisplayType::Numerical => "numerical",
            ExdDisplayType::Simple => "simple",
            ExdDisplayType::Graph => "graph",
            ExdDisplayType::Bar => "bar",
            ExdDisplayType::CircleGraph => "circle_graph",
            ExdDisplayType::VirtualPartner => "virtual_partner",
            ExdDisplayType::Balance => "balance",
            ExdDisplayType::StringList => "string_list",
            ExdDisplayType::String => "string",
            ExdDisplayType::SimpleDynamicIcon => "simple_dynamic_icon",
            ExdDisplayType::Gauge => "gauge",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(ExdDisplayType::Numerical),
            1 => Some(ExdDisplayType::Simple),
            2 => Some(ExdDisplayType::Graph),
            3 => Some(ExdDisplayType::Bar),
            4 => Some(ExdDisplayType::CircleGraph),
            5 => Some(ExdDisplayType::VirtualPartner),
            6 => Some(ExdDisplayType::Balance),
            7 => Some(ExdDisplayType::StringList),
            8 => Some(ExdDisplayType::String),
            9 => Some(ExdDisplayType::SimpleDynamicIcon),
            10 => Some(ExdDisplayType::Gauge),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "numerical" => Some(ExdDisplayType::Numerical),
            "simple" => Some(ExdDisplayType::Simple),
            "graph" => Some(ExdDisplayType::Graph),
            "bar" => Some(ExdDisplayType::Bar),
            "circle_graph" => Some(ExdDisplayType::CircleGraph),
            "virtual_partner" => Some(ExdDisplayType::VirtualPartner),
            "balance" => Some(ExdDisplayType::Balance),
            "string_list" => Some(ExdDisplayType::StringList),
            "string" => Some(ExdDisplayType::String),
            "simple_dynamic_icon" => Some(ExdDisplayType::SimpleDynamicIcon),
            "gauge" => Some(ExdDisplayType::Gauge),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum ExdDataUnits {
    NoUnits = 0,
    Laps = 1,
    MilesPerHour = 2,
    KilometersPerHour = 3,
    FeetPerHour = 4,
    MetersPerHour = 5,
    DegreesCelsius = 6,
    DegreesFarenheit = 7,
    Zone = 8,
    Gear = 9,
    Rpm = 10,
    Bpm = 11,
    Degrees = 12,
    Millimeters = 13,
    Meters = 14,
    Kilometers = 15,
    Feet = 16,
    Yards = 17,
    Kilofeet = 18,
    Miles = 19,
    Time = 20,
    EnumTurnType = 21,
    Percent = 22,
    Watts = 23,
    WattsPerKilogram = 24,
    EnumBatteryStatus = 25,
    EnumBikeLightBeamAngleMode = 26,
    EnumBikeLightBatteryStatus = 27,
    EnumBikeLightNetworkConfigType = 28,
    Lights = 29,
    Seconds = 30,
    Minutes = 31,
    Hours = 32,
    Calories = 33,
    Kilojoules = 34,
    Milliseconds = 35,
    SecondPerMile = 36,
    SecondPerKilometer = 37,
    Centimeter = 38,
    EnumCoursePoint = 39,
    Bradians = 40,
    EnumSport = 41,
    InchesHg = 42,
    MmHg = 43,
    Mbars = 44,
    HectoPascals = 45,
    FeetPerMin = 46,
    MetersPerMin = 47,
    MetersPerSec = 48,
    EightCardinal = 49,
}

impl ExdDataUnits {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            ExdDataUnits::NoUnits => "no_units",
            ExdDataUnits::Laps => "laps",
            ExdDataUnits::MilesPerHour => "miles_per_hour",
            ExdDataUnits::KilometersPerHour => "kilometers_per_hour",
            ExdDataUnits::FeetPerHour => "feet_per_hour",
            ExdDataUnits::MetersPerHour => "meters_per_hour",
            ExdDataUnits::DegreesCelsius => "degrees_celsius",
            ExdDataUnits::DegreesFarenheit => "degrees_farenheit",
            ExdDataUnits::Zone => "zone",
            ExdDataUnits::Gear => "gear",
            ExdDataUnits::Rpm => "rpm",
            ExdDataUnits::Bpm => "bpm",
            ExdDataUnits::Degrees => "degrees",
            ExdDataUnits::Millimeters => "millimeters",
            ExdDataUnits::Meters => "meters",
            ExdDataUnits::Kilometers => "kilometers",
            ExdDataUnits::Feet => "feet",
            ExdDataUnits::Yards => "yards",
            ExdDataUnits::Kilofeet => "kilofeet",
            ExdDataUnits::Miles => "miles",
            ExdDataUnits::Time => "time",
            ExdDataUnits::EnumTurnType => "enum_turn_type",
            ExdDataUnits::Percent => "percent",
            ExdDataUnits::Watts => "watts",
            ExdDataUnits::WattsPerKilogram => "watts_per_kilogram",
            ExdDataUnits::EnumBatteryStatus => "enum_battery_status",
            ExdDataUnits::EnumBikeLightBeamAngleMode => "enum_bike_light_beam_angle_mode",
            ExdDataUnits::EnumBikeLightBatteryStatus => "enum_bike_light_battery_status",
            ExdDataUnits::EnumBikeLightNetworkConfigType => "enum_bike_light_network_config_type",
            ExdDataUnits::Lights => "lights",
            ExdDataUnits::Seconds => "seconds",
            ExdDataUnits::Minutes => "minutes",
            ExdDataUnits::Hours => "hours",
            ExdDataUnits::Calories => "calories",
            ExdDataUnits::Kilojoules => "kilojoules",
            ExdDataUnits::Milliseconds => "milliseconds",
            ExdDataUnits::SecondPerMile => "second_per_mile",
            ExdDataUnits::SecondPerKilometer => "second_per_kilometer",
            ExdDataUnits::Centimeter => "centimeter",
            ExdDataUnits::EnumCoursePoint => "enum_course_point",
            ExdDataUnits::Bradians => "bradians",
            ExdDataUnits::EnumSport => "enum_sport",
            ExdDataUnits::InchesHg => "inches_hg",
            ExdDataUnits::MmHg => "mm_hg",
            ExdDataUnits::Mbars => "mbars",
            ExdDataUnits::HectoPascals => "hecto_pascals",
            ExdDataUnits::FeetPerMin => "feet_per_min",
            ExdDataUnits::MetersPerMin => "meters_per_min",
            ExdDataUnits::MetersPerSec => "meters_per_sec",
            ExdDataUnits::EightCardinal => "eight_cardinal",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(ExdDataUnits::NoUnits),
            1 => Some(ExdDataUnits::Laps),
            2 => Some(ExdDataUnits::MilesPerHour),
            3 => Some(ExdDataUnits::KilometersPerHour),
            4 => Some(ExdDataUnits::FeetPerHour),
            5 => Some(ExdDataUnits::MetersPerHour),
            6 => Some(ExdDataUnits::DegreesCelsius),
            7 => Some(ExdDataUnits::DegreesFarenheit),
            8 => Some(ExdDataUnits::Zone),
            9 => Some(ExdDataUnits::Gear),
            10 => Some(ExdDataUnits::Rpm),
            11 => Some(ExdDataUnits::Bpm),
            12 => Some(ExdDataUnits::Degrees),
            13 => Some(ExdDataUnits::Millimeters),
            14 => Some(ExdDataUnits::Meters),
            15 => Some(ExdDataUnits::Kilometers),
            16 => Some(ExdDataUnits::Feet),
            17 => Some(ExdDataUnits::Yards),
            18 => Some(ExdDataUnits::Kilofeet),
            19 => Some(ExdDataUnits::Miles),
            20 => Some(ExdDataUnits::Time),
            21 => Some(ExdDataUnits::EnumTurnType),
            22 => Some(ExdDataUnits::Percent),
            23 => Some(ExdDataUnits::Watts),
            24 => Some(ExdDataUnits::WattsPerKilogram),
            25 => Some(ExdDataUnits::EnumBatteryStatus),
            26 => Some(ExdDataUnits::EnumBikeLightBeamAngleMode),
            27 => Some(ExdDataUnits::EnumBikeLightBatteryStatus),
            28 => Some(ExdDataUnits::EnumBikeLightNetworkConfigType),
            29 => Some(ExdDataUnits::Lights),
            30 => Some(ExdDataUnits::Seconds),
            31 => Some(ExdDataUnits::Minutes),
            32 => Some(ExdDataUnits::Hours),
            33 => Some(ExdDataUnits::Calories),
            34 => Some(ExdDataUnits::Kilojoules),
            35 => Some(ExdDataUnits::Milliseconds),
            36 => Some(ExdDataUnits::SecondPerMile),
            37 => Some(ExdDataUnits::SecondPerKilometer),
            38 => Some(ExdDataUnits::Centimeter),
            39 => Some(ExdDataUnits::EnumCoursePoint),
            40 => Some(ExdDataUnits::Bradians),
            41 => Some(ExdDataUnits::EnumSport),
            42 => Some(ExdDataUnits::InchesHg),
            43 => Some(ExdDataUnits::MmHg),
            44 => Some(ExdDataUnits::Mbars),
            45 => Some(ExdDataUnits::HectoPascals),
            46 => Some(ExdDataUnits::FeetPerMin),
            47 => Some(ExdDataUnits::MetersPerMin),
            48 => Some(ExdDataUnits::MetersPerSec),
            49 => Some(ExdDataUnits::EightCardinal),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "no_units" => Some(ExdDataUnits::NoUnits),
            "laps" => Some(ExdDataUnits::Laps),
            "miles_per_hour" => Some(ExdDataUnits::MilesPerHour),
            "kilometers_per_hour" => Some(ExdDataUnits::KilometersPerHour),
            "feet_per_hour" => Some(ExdDataUnits::FeetPerHour),
            "meters_per_hour" => Some(ExdDataUnits::MetersPerHour),
            "degrees_celsius" => Some(ExdDataUnits::DegreesCelsius),
            "degrees_farenheit" => Some(ExdDataUnits::DegreesFarenheit),
            "zone" => Some(ExdDataUnits::Zone),
            "gear" => Some(ExdDataUnits::Gear),
            "rpm" => Some(ExdDataUnits::Rpm),
            "bpm" => Some(ExdDataUnits::Bpm),
            "degrees" => Some(ExdDataUnits::Degrees),
            "millimeters" => Some(ExdDataUnits::Millimeters),
            "meters" => Some(ExdDataUnits::Meters),
            "kilometers" => Some(ExdDataUnits::Kilometers),
            "feet" => Some(ExdDataUnits::Feet),
            "yards" => Some(ExdDataUnits::Yards),
            "kilofeet" => Some(ExdDataUnits::Kilofeet),
            "miles" => Some(ExdDataUnits::Miles),
            "time" => Some(ExdDataUnits::Time),
            "enum_turn_type" => Some(ExdDataUnits::EnumTurnType),
            "percent" => Some(ExdDataUnits::Percent),
            "watts" => Some(ExdDataUnits::Watts),
            "watts_per_kilogram" => Some(ExdDataUnits::WattsPerKilogram),
            "enum_battery_status" => Some(ExdDataUnits::EnumBatteryStatus),
            "enum_bike_light_beam_angle_mode" => Some(ExdDataUnits::EnumBikeLightBeamAngleMode),
            "enum_bike_light_battery_status" => Some(ExdDataUnits::EnumBikeLightBatteryStatus),
            "enum_bike_light_network_config_type" => {
                Some(ExdDataUnits::EnumBikeLightNetworkConfigType)
            }
            "lights" => Some(ExdDataUnits::Lights),
            "seconds" => Some(ExdDataUnits::Seconds),
            "minutes" => Some(ExdDataUnits::Minutes),
            "hours" => Some(ExdDataUnits::Hours),
            "calories" => Some(ExdDataUnits::Calories),
            "kilojoules" => Some(ExdDataUnits::Kilojoules),
            "milliseconds" => Some(ExdDataUnits::Milliseconds),
            "second_per_mile" => Some(ExdDataUnits::SecondPerMile),
            "second_per_kilometer" => Some(ExdDataUnits::SecondPerKilometer),
            "centimeter" => Some(ExdDataUnits::Centimeter),
            "enum_course_point" => Some(ExdDataUnits::EnumCoursePoint),
            "bradians" => Some(ExdDataUnits::Bradians),
            "enum_sport" => Some(ExdDataUnits::EnumSport),
            "inches_hg" => Some(ExdDataUnits::InchesHg),
            "mm_hg" => Some(ExdDataUnits::MmHg),
            "mbars" => Some(ExdDataUnits::Mbars),
            "hecto_pascals" => Some(ExdDataUnits::HectoPascals),
            "feet_per_min" => Some(ExdDataUnits::FeetPerMin),
            "meters_per_min" => Some(ExdDataUnits::MetersPerMin),
            "meters_per_sec" => Some(ExdDataUnits::MetersPerSec),
            "eight_cardinal" => Some(ExdDataUnits::EightCardinal),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum ExdQualifiers {
    NoQualifier = 0,
    Instantaneous = 1,
    Average = 2,
    Lap = 3,
    Maximum = 4,
    MaximumAverage = 5,
    MaximumLap = 6,
    LastLap = 7,
    AverageLap = 8,
    ToDestination = 9,
    ToGo = 10,
    ToNext = 11,
    NextCoursePoint = 12,
    Total = 13,
    ThreeSecondAverage = 14,
    TenSecondAverage = 15,
    ThirtySecondAverage = 16,
    PercentMaximum = 17,
    PercentMaximumAverage = 18,
    LapPercentMaximum = 19,
    Elapsed = 20,
    Sunrise = 21,
    Sunset = 22,
    ComparedToVirtualPartner = 23,
    Maximum24h = 24,
    Minimum24h = 25,
    Minimum = 26,
    First = 27,
    Second = 28,
    Third = 29,
    Shifter = 30,
    LastSport = 31,
    Moving = 32,
    Stopped = 33,
    EstimatedTotal = 34,
    Zone9 = 242,
    Zone8 = 243,
    Zone7 = 244,
    Zone6 = 245,
    Zone5 = 246,
    Zone4 = 247,
    Zone3 = 248,
    Zone2 = 249,
    Zone1 = 250,
}

impl ExdQualifiers {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            ExdQualifiers::NoQualifier => "no_qualifier",
            ExdQualifiers::Instantaneous => "instantaneous",
            ExdQualifiers::Average => "average",
            ExdQualifiers::Lap => "lap",
            ExdQualifiers::Maximum => "maximum",
            ExdQualifiers::MaximumAverage => "maximum_average",
            ExdQualifiers::MaximumLap => "maximum_lap",
            ExdQualifiers::LastLap => "last_lap",
            ExdQualifiers::AverageLap => "average_lap",
            ExdQualifiers::ToDestination => "to_destination",
            ExdQualifiers::ToGo => "to_go",
            ExdQualifiers::ToNext => "to_next",
            ExdQualifiers::NextCoursePoint => "next_course_point",
            ExdQualifiers::Total => "total",
            ExdQualifiers::ThreeSecondAverage => "three_second_average",
            ExdQualifiers::TenSecondAverage => "ten_second_average",
            ExdQualifiers::ThirtySecondAverage => "thirty_second_average",
            ExdQualifiers::PercentMaximum => "percent_maximum",
            ExdQualifiers::PercentMaximumAverage => "percent_maximum_average",
            ExdQualifiers::LapPercentMaximum => "lap_percent_maximum",
            ExdQualifiers::Elapsed => "elapsed",
            ExdQualifiers::Sunrise => "sunrise",
            ExdQualifiers::Sunset => "sunset",
            ExdQualifiers::ComparedToVirtualPartner => "compared_to_virtual_partner",
            ExdQualifiers::Maximum24h => "maximum_24h",
            ExdQualifiers::Minimum24h => "minimum_24h",
            ExdQualifiers::Minimum => "minimum",
            ExdQualifiers::First => "first",
            ExdQualifiers::Second => "second",
            ExdQualifiers::Third => "third",
            ExdQualifiers::Shifter => "shifter",
            ExdQualifiers::LastSport => "last_sport",
            ExdQualifiers::Moving => "moving",
            ExdQualifiers::Stopped => "stopped",
            ExdQualifiers::EstimatedTotal => "estimated_total",
            ExdQualifiers::Zone9 => "zone_9",
            ExdQualifiers::Zone8 => "zone_8",
            ExdQualifiers::Zone7 => "zone_7",
            ExdQualifiers::Zone6 => "zone_6",
            ExdQualifiers::Zone5 => "zone_5",
            ExdQualifiers::Zone4 => "zone_4",
            ExdQualifiers::Zone3 => "zone_3",
            ExdQualifiers::Zone2 => "zone_2",
            ExdQualifiers::Zone1 => "zone_1",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(ExdQualifiers::NoQualifier),
            1 => Some(ExdQualifiers::Instantaneous),
            2 => Some(ExdQualifiers::Average),
            3 => Some(ExdQualifiers::Lap),
            4 => Some(ExdQualifiers::Maximum),
            5 => Some(ExdQualifiers::MaximumAverage),
            6 => Some(ExdQualifiers::MaximumLap),
            7 => Some(ExdQualifiers::LastLap),
            8 => Some(ExdQualifiers::AverageLap),
            9 => Some(ExdQualifiers::ToDestination),
            10 => Some(ExdQualifiers::ToGo),
            11 => Some(ExdQualifiers::ToNext),
            12 => Some(ExdQualifiers::NextCoursePoint),
            13 => Some(ExdQualifiers::Total),
            14 => Some(ExdQualifiers::ThreeSecondAverage),
            15 => Some(ExdQualifiers::TenSecondAverage),
            16 => Some(ExdQualifiers::ThirtySecondAverage),
            17 => Some(ExdQualifiers::PercentMaximum),
            18 => Some(ExdQualifiers::PercentMaximumAverage),
            19 => Some(ExdQualifiers::LapPercentMaximum),
            20 => Some(ExdQualifiers::Elapsed),
            21 => Some(ExdQualifiers::Sunrise),
            22 => Some(ExdQualifiers::Sunset),
            23 => Some(ExdQualifiers::ComparedToVirtualPartner),
            24 => Some(ExdQualifiers::Maximum24h),
            25 => Some(ExdQualifiers::Minimum24h),
            26 => Some(ExdQualifiers::Minimum),
            27 => Some(ExdQualifiers::First),
            28 => Some(ExdQualifiers::Second),
            29 => Some(ExdQualifiers::Third),
            30 => Some(ExdQualifiers::Shifter),
            31 => Some(ExdQualifiers::LastSport),
            32 => Some(ExdQualifiers::Moving),
            33 => Some(ExdQualifiers::Stopped),
            34 => Some(ExdQualifiers::EstimatedTotal),
            242 => Some(ExdQualifiers::Zone9),
            243 => Some(ExdQualifiers::Zone8),
            244 => Some(ExdQualifiers::Zone7),
            245 => Some(ExdQualifiers::Zone6),
            246 => Some(ExdQualifiers::Zone5),
            247 => Some(ExdQualifiers::Zone4),
            248 => Some(ExdQualifiers::Zone3),
            249 => Some(ExdQualifiers::Zone2),
            250 => Some(ExdQualifiers::Zone1),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "no_qualifier" => Some(ExdQualifiers::NoQualifier),
            "instantaneous" => Some(ExdQualifiers::Instantaneous),
            "average" => Some(ExdQualifiers::Average),
            "lap" => Some(ExdQualifiers::Lap),
            "maximum" => Some(ExdQualifiers::Maximum),
            "maximum_average" => Some(ExdQualifiers::MaximumAverage),
            "maximum_lap" => Some(ExdQualifiers::MaximumLap),
            "last_lap" => Some(ExdQualifiers::LastLap),
            "average_lap" => Some(ExdQualifiers::AverageLap),
            "to_destination" => Some(ExdQualifiers::ToDestination),
            "to_go" => Some(ExdQualifiers::ToGo),
            "to_next" => Some(ExdQualifiers::ToNext),
            "next_course_point" => Some(ExdQualifiers::NextCoursePoint),
            "total" => Some(ExdQualifiers::Total),
            "three_second_average" => Some(ExdQualifiers::ThreeSecondAverage),
            "ten_second_average" => Some(ExdQualifiers::TenSecondAverage),
            "thirty_second_average" => Some(ExdQualifiers::ThirtySecondAverage),
            "percent_maximum" => Some(ExdQualifiers::PercentMaximum),
            "percent_maximum_average" => Some(ExdQualifiers::PercentMaximumAverage),
            "lap_percent_maximum" => Some(ExdQualifiers::LapPercentMaximum),
            "elapsed" => Some(ExdQualifiers::Elapsed),
            "sunrise" => Some(ExdQualifiers::Sunrise),
            "sunset" => Some(ExdQualifiers::Sunset),
            "compared_to_virtual_partner" => Some(ExdQualifiers::ComparedToVirtualPartner),
            "maximum_24h" => Some(ExdQualifiers::Maximum24h),
            "minimum_24h" => Some(ExdQualifiers::Minimum24h),
            "minimum" => Some(ExdQualifiers::Minimum),
            "first" => Some(ExdQualifiers::First),
            "second" => Some(ExdQualifiers::Second),
            "third" => Some(ExdQualifiers::Third),
            "shifter" => Some(ExdQualifiers::Shifter),
            "last_sport" => Some(ExdQualifiers::LastSport),
            "moving" => Some(ExdQualifiers::Moving),
            "stopped" => Some(ExdQualifiers::Stopped),
            "estimated_total" => Some(ExdQualifiers::EstimatedTotal),
            "zone_9" => Some(ExdQualifiers::Zone9),
            "zone_8" => Some(ExdQualifiers::Zone8),
            "zone_7" => Some(ExdQualifiers::Zone7),
            "zone_6" => Some(ExdQualifiers::Zone6),
            "zone_5" => Some(ExdQualifiers::Zone5),
            "zone_4" => Some(ExdQualifiers::Zone4),
            "zone_3" => Some(ExdQualifiers::Zone3),
            "zone_2" => Some(ExdQualifiers::Zone2),
            "zone_1" => Some(ExdQualifiers::Zone1),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum ExdDescriptors {
    BikeLightBatteryStatus = 0,
    BeamAngleStatus = 1,
    BateryLevel = 2,
    LightNetworkMode = 3,
    NumberLightsConnected = 4,
    Cadence = 5,
    Distance = 6,
    EstimatedTimeOfArrival = 7,
    Heading = 8,
    Time = 9,
    BatteryLevel = 10,
    TrainerResistance = 11,
    TrainerTargetPower = 12,
    TimeSeated = 13,
    TimeStanding = 14,
    Elevation = 15,
    Grade = 16,
    Ascent = 17,
    Descent = 18,
    VerticalSpeed = 19,
    Di2BatteryLevel = 20,
    FrontGear = 21,
    RearGear = 22,
    GearRatio = 23,
    HeartRate = 24,
    HeartRateZone = 25,
    TimeInHeartRateZone = 26,
    HeartRateReserve = 27,
    Calories = 28,
    GpsAccuracy = 29,
    GpsSignalStrength = 30,
    Temperature = 31,
    TimeOfDay = 32,
    Balance = 33,
    PedalSmoothness = 34,
    Power = 35,
    FunctionalThresholdPower = 36,
    IntensityFactor = 37,
    Work = 38,
    PowerRatio = 39,
    NormalizedPower = 40,
    TrainingStressScore = 41,
    TimeOnZone = 42,
    Speed = 43,
    Laps = 44,
    Reps = 45,
    WorkoutStep = 46,
    CourseDistance = 47,
    NavigationDistance = 48,
    CourseEstimatedTimeOfArrival = 49,
    NavigationEstimatedTimeOfArrival = 50,
    CourseTime = 51,
    NavigationTime = 52,
    CourseHeading = 53,
    NavigationHeading = 54,
    PowerZone = 55,
    TorqueEffectiveness = 56,
    TimerTime = 57,
    PowerWeightRatio = 58,
    LeftPlatformCenterOffset = 59,
    RightPlatformCenterOffset = 60,
    LeftPowerPhaseStartAngle = 61,
    RightPowerPhaseStartAngle = 62,
    LeftPowerPhaseFinishAngle = 63,
    RightPowerPhaseFinishAngle = 64,
    Gears = 65,
    Pace = 66,
    TrainingEffect = 67,
    VerticalOscillation = 68,
    VerticalRatio = 69,
    GroundContactTime = 70,
    LeftGroundContactTimeBalance = 71,
    RightGroundContactTimeBalance = 72,
    StrideLength = 73,
    RunningCadence = 74,
    PerformanceCondition = 75,
    CourseType = 76,
    TimeInPowerZone = 77,
    NavigationTurn = 78,
    CourseLocation = 79,
    NavigationLocation = 80,
    Compass = 81,
    GearCombo = 82,
    MuscleOxygen = 83,
    Icon = 84,
    CompassHeading = 85,
    GpsHeading = 86,
    GpsElevation = 87,
    AnaerobicTrainingEffect = 88,
    Course = 89,
    OffCourse = 90,
    GlideRatio = 91,
    VerticalDistance = 92,
    Vmg = 93,
    AmbientPressure = 94,
    Pressure = 95,
    Vam = 96,
}

impl ExdDescriptors {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            ExdDescriptors::BikeLightBatteryStatus => "bike_light_battery_status",
            ExdDescriptors::BeamAngleStatus => "beam_angle_status",
            ExdDescriptors::BateryLevel => "batery_level",
            ExdDescriptors::LightNetworkMode => "light_network_mode",
            ExdDescriptors::NumberLightsConnected => "number_lights_connected",
            ExdDescriptors::Cadence => "cadence",
            ExdDescriptors::Distance => "distance",
            ExdDescriptors::EstimatedTimeOfArrival => "estimated_time_of_arrival",
            ExdDescriptors::Heading => "heading",
            ExdDescriptors::Time => "time",
            ExdDescriptors::BatteryLevel => "battery_level",
            ExdDescriptors::TrainerResistance => "trainer_resistance",
            ExdDescriptors::TrainerTargetPower => "trainer_target_power",
            ExdDescriptors::TimeSeated => "time_seated",
            ExdDescriptors::TimeStanding => "time_standing",
            ExdDescriptors::Elevation => "elevation",
            ExdDescriptors::Grade => "grade",
            ExdDescriptors::Ascent => "ascent",
            ExdDescriptors::Descent => "descent",
            ExdDescriptors::VerticalSpeed => "vertical_speed",
            ExdDescriptors::Di2BatteryLevel => "di2_battery_level",
            ExdDescriptors::FrontGear => "front_gear",
            ExdDescriptors::RearGear => "rear_gear",
            ExdDescriptors::GearRatio => "gear_ratio",
            ExdDescriptors::HeartRate => "heart_rate",
            ExdDescriptors::HeartRateZone => "heart_rate_zone",
            ExdDescriptors::TimeInHeartRateZone => "time_in_heart_rate_zone",
            ExdDescriptors::HeartRateReserve => "heart_rate_reserve",
            ExdDescriptors::Calories => "calories",
            ExdDescriptors::GpsAccuracy => "gps_accuracy",
            ExdDescriptors::GpsSignalStrength => "gps_signal_strength",
            ExdDescriptors::Temperature => "temperature",
            ExdDescriptors::TimeOfDay => "time_of_day",
            ExdDescriptors::Balance => "balance",
            ExdDescriptors::PedalSmoothness => "pedal_smoothness",
            ExdDescriptors::Power => "power",
            ExdDescriptors::FunctionalThresholdPower => "functional_threshold_power",
            ExdDescriptors::IntensityFactor => "intensity_factor",
            ExdDescriptors::Work => "work",
            ExdDescriptors::PowerRatio => "power_ratio",
            ExdDescriptors::NormalizedPower => "normalized_power",
            ExdDescriptors::TrainingStressScore => "training_stress_Score",
            ExdDescriptors::TimeOnZone => "time_on_zone",
            ExdDescriptors::Speed => "speed",
            ExdDescriptors::Laps => "laps",
            ExdDescriptors::Reps => "reps",
            ExdDescriptors::WorkoutStep => "workout_step",
            ExdDescriptors::CourseDistance => "course_distance",
            ExdDescriptors::NavigationDistance => "navigation_distance",
            ExdDescriptors::CourseEstimatedTimeOfArrival => "course_estimated_time_of_arrival",
            ExdDescriptors::NavigationEstimatedTimeOfArrival => {
                "navigation_estimated_time_of_arrival"
            }
            ExdDescriptors::CourseTime => "course_time",
            ExdDescriptors::NavigationTime => "navigation_time",
            ExdDescriptors::CourseHeading => "course_heading",
            ExdDescriptors::NavigationHeading => "navigation_heading",
            ExdDescriptors::PowerZone => "power_zone",
            ExdDescriptors::TorqueEffectiveness => "torque_effectiveness",
            ExdDescriptors::TimerTime => "timer_time",
            ExdDescriptors::PowerWeightRatio => "power_weight_ratio",
            ExdDescriptors::LeftPlatformCenterOffset => "left_platform_center_offset",
            ExdDescriptors::RightPlatformCenterOffset => "right_platform_center_offset",
            ExdDescriptors::LeftPowerPhaseStartAngle => "left_power_phase_start_angle",
            ExdDescriptors::RightPowerPhaseStartAngle => "right_power_phase_start_angle",
            ExdDescriptors::LeftPowerPhaseFinishAngle => "left_power_phase_finish_angle",
            ExdDescriptors::RightPowerPhaseFinishAngle => "right_power_phase_finish_angle",
            ExdDescriptors::Gears => "gears",
            ExdDescriptors::Pace => "pace",
            ExdDescriptors::TrainingEffect => "training_effect",
            ExdDescriptors::VerticalOscillation => "vertical_oscillation",
            ExdDescriptors::VerticalRatio => "vertical_ratio",
            ExdDescriptors::GroundContactTime => "ground_contact_time",
            ExdDescriptors::LeftGroundContactTimeBalance => "left_ground_contact_time_balance",
            ExdDescriptors::RightGroundContactTimeBalance => "right_ground_contact_time_balance",
            ExdDescriptors::StrideLength => "stride_length",
            ExdDescriptors::RunningCadence => "running_cadence",
            ExdDescriptors::PerformanceCondition => "performance_condition",
            ExdDescriptors::CourseType => "course_type",
            ExdDescriptors::TimeInPowerZone => "time_in_power_zone",
            ExdDescriptors::NavigationTurn => "navigation_turn",
            ExdDescriptors::CourseLocation => "course_location",
            ExdDescriptors::NavigationLocation => "navigation_location",
            ExdDescriptors::Compass => "compass",
            ExdDescriptors::GearCombo => "gear_combo",
            ExdDescriptors::MuscleOxygen => "muscle_oxygen",
            ExdDescriptors::Icon => "icon",
            ExdDescriptors::CompassHeading => "compass_heading",
            ExdDescriptors::GpsHeading => "gps_heading",
            ExdDescriptors::GpsElevation => "gps_elevation",
            ExdDescriptors::AnaerobicTrainingEffect => "anaerobic_training_effect",
            ExdDescriptors::Course => "course",
            ExdDescriptors::OffCourse => "off_course",
            ExdDescriptors::GlideRatio => "glide_ratio",
            ExdDescriptors::VerticalDistance => "vertical_distance",
            ExdDescriptors::Vmg => "vmg",
            ExdDescriptors::AmbientPressure => "ambient_pressure",
            ExdDescriptors::Pressure => "pressure",
            ExdDescriptors::Vam => "vam",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(ExdDescriptors::BikeLightBatteryStatus),
            1 => Some(ExdDescriptors::BeamAngleStatus),
            2 => Some(ExdDescriptors::BateryLevel),
            3 => Some(ExdDescriptors::LightNetworkMode),
            4 => Some(ExdDescriptors::NumberLightsConnected),
            5 => Some(ExdDescriptors::Cadence),
            6 => Some(ExdDescriptors::Distance),
            7 => Some(ExdDescriptors::EstimatedTimeOfArrival),
            8 => Some(ExdDescriptors::Heading),
            9 => Some(ExdDescriptors::Time),
            10 => Some(ExdDescriptors::BatteryLevel),
            11 => Some(ExdDescriptors::TrainerResistance),
            12 => Some(ExdDescriptors::TrainerTargetPower),
            13 => Some(ExdDescriptors::TimeSeated),
            14 => Some(ExdDescriptors::TimeStanding),
            15 => Some(ExdDescriptors::Elevation),
            16 => Some(ExdDescriptors::Grade),
            17 => Some(ExdDescriptors::Ascent),
            18 => Some(ExdDescriptors::Descent),
            19 => Some(ExdDescriptors::VerticalSpeed),
            20 => Some(ExdDescriptors::Di2BatteryLevel),
            21 => Some(ExdDescriptors::FrontGear),
            22 => Some(ExdDescriptors::RearGear),
            23 => Some(ExdDescriptors::GearRatio),
            24 => Some(ExdDescriptors::HeartRate),
            25 => Some(ExdDescriptors::HeartRateZone),
            26 => Some(ExdDescriptors::TimeInHeartRateZone),
            27 => Some(ExdDescriptors::HeartRateReserve),
            28 => Some(ExdDescriptors::Calories),
            29 => Some(ExdDescriptors::GpsAccuracy),
            30 => Some(ExdDescriptors::GpsSignalStrength),
            31 => Some(ExdDescriptors::Temperature),
            32 => Some(ExdDescriptors::TimeOfDay),
            33 => Some(ExdDescriptors::Balance),
            34 => Some(ExdDescriptors::PedalSmoothness),
            35 => Some(ExdDescriptors::Power),
            36 => Some(ExdDescriptors::FunctionalThresholdPower),
            37 => Some(ExdDescriptors::IntensityFactor),
            38 => Some(ExdDescriptors::Work),
            39 => Some(ExdDescriptors::PowerRatio),
            40 => Some(ExdDescriptors::NormalizedPower),
            41 => Some(ExdDescriptors::TrainingStressScore),
            42 => Some(ExdDescriptors::TimeOnZone),
            43 => Some(ExdDescriptors::Speed),
            44 => Some(ExdDescriptors::Laps),
            45 => Some(ExdDescriptors::Reps),
            46 => Some(ExdDescriptors::WorkoutStep),
            47 => Some(ExdDescriptors::CourseDistance),
            48 => Some(ExdDescriptors::NavigationDistance),
            49 => Some(ExdDescriptors::CourseEstimatedTimeOfArrival),
            50 => Some(ExdDescriptors::NavigationEstimatedTimeOfArrival),
            51 => Some(ExdDescriptors::CourseTime),
            52 => Some(ExdDescriptors::NavigationTime),
            53 => Some(ExdDescriptors::CourseHeading),
            54 => Some(ExdDescriptors::NavigationHeading),
            55 => Some(ExdDescriptors::PowerZone),
            56 => Some(ExdDescriptors::TorqueEffectiveness),
            57 => Some(ExdDescriptors::TimerTime),
            58 => Some(ExdDescriptors::PowerWeightRatio),
            59 => Some(ExdDescriptors::LeftPlatformCenterOffset),
            60 => Some(ExdDescriptors::RightPlatformCenterOffset),
            61 => Some(ExdDescriptors::LeftPowerPhaseStartAngle),
            62 => Some(ExdDescriptors::RightPowerPhaseStartAngle),
            63 => Some(ExdDescriptors::LeftPowerPhaseFinishAngle),
            64 => Some(ExdDescriptors::RightPowerPhaseFinishAngle),
            65 => Some(ExdDescriptors::Gears),
            66 => Some(ExdDescriptors::Pace),
            67 => Some(ExdDescriptors::TrainingEffect),
            68 => Some(ExdDescriptors::VerticalOscillation),
            69 => Some(ExdDescriptors::VerticalRatio),
            70 => Some(ExdDescriptors::GroundContactTime),
            71 => Some(ExdDescriptors::LeftGroundContactTimeBalance),
            72 => Some(ExdDescriptors::RightGroundContactTimeBalance),
            73 => Some(ExdDescriptors::StrideLength),
            74 => Some(ExdDescriptors::RunningCadence),
            75 => Some(ExdDescriptors::PerformanceCondition),
            76 => Some(ExdDescriptors::CourseType),
            77 => Some(ExdDescriptors::TimeInPowerZone),
            78 => Some(ExdDescriptors::NavigationTurn),
            79 => Some(ExdDescriptors::CourseLocation),
            80 => Some(ExdDescriptors::NavigationLocation),
            81 => Some(ExdDescriptors::Compass),
            82 => Some(ExdDescriptors::GearCombo),
            83 => Some(ExdDescriptors::MuscleOxygen),
            84 => Some(ExdDescriptors::Icon),
            85 => Some(ExdDescriptors::CompassHeading),
            86 => Some(ExdDescriptors::GpsHeading),
            87 => Some(ExdDescriptors::GpsElevation),
            88 => Some(ExdDescriptors::AnaerobicTrainingEffect),
            89 => Some(ExdDescriptors::Course),
            90 => Some(ExdDescriptors::OffCourse),
            91 => Some(ExdDescriptors::GlideRatio),
            92 => Some(ExdDescriptors::VerticalDistance),
            93 => Some(ExdDescriptors::Vmg),
            94 => Some(ExdDescriptors::AmbientPressure),
            95 => Some(ExdDescriptors::Pressure),
            96 => Some(ExdDescriptors::Vam),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "bike_light_battery_status" => Some(ExdDescriptors::BikeLightBatteryStatus),
            "beam_angle_status" => Some(ExdDescriptors::BeamAngleStatus),
            "batery_level" => Some(ExdDescriptors::BateryLevel),
            "light_network_mode" => Some(ExdDescriptors::LightNetworkMode),
            "number_lights_connected" => Some(ExdDescriptors::NumberLightsConnected),
            "cadence" => Some(ExdDescriptors::Cadence),
            "distance" => Some(ExdDescriptors::Distance),
            "estimated_time_of_arrival" => Some(ExdDescriptors::EstimatedTimeOfArrival),
            "heading" => Some(ExdDescriptors::Heading),
            "time" => Some(ExdDescriptors::Time),
            "battery_level" => Some(ExdDescriptors::BatteryLevel),
            "trainer_resistance" => Some(ExdDescriptors::TrainerResistance),
            "trainer_target_power" => Some(ExdDescriptors::TrainerTargetPower),
            "time_seated" => Some(ExdDescriptors::TimeSeated),
            "time_standing" => Some(ExdDescriptors::TimeStanding),
            "elevation" => Some(ExdDescriptors::Elevation),
            "grade" => Some(ExdDescriptors::Grade),
            "ascent" => Some(ExdDescriptors::Ascent),
            "descent" => Some(ExdDescriptors::Descent),
            "vertical_speed" => Some(ExdDescriptors::VerticalSpeed),
            "di2_battery_level" => Some(ExdDescriptors::Di2BatteryLevel),
            "front_gear" => Some(ExdDescriptors::FrontGear),
            "rear_gear" => Some(ExdDescriptors::RearGear),
            "gear_ratio" => Some(ExdDescriptors::GearRatio),
            "heart_rate" => Some(ExdDescriptors::HeartRate),
            "heart_rate_zone" => Some(ExdDescriptors::HeartRateZone),
            "time_in_heart_rate_zone" => Some(ExdDescriptors::TimeInHeartRateZone),
            "heart_rate_reserve" => Some(ExdDescriptors::HeartRateReserve),
            "calories" => Some(ExdDescriptors::Calories),
            "gps_accuracy" => Some(ExdDescriptors::GpsAccuracy),
            "gps_signal_strength" => Some(ExdDescriptors::GpsSignalStrength),
            "temperature" => Some(ExdDescriptors::Temperature),
            "time_of_day" => Some(ExdDescriptors::TimeOfDay),
            "balance" => Some(ExdDescriptors::Balance),
            "pedal_smoothness" => Some(ExdDescriptors::PedalSmoothness),
            "power" => Some(ExdDescriptors::Power),
            "functional_threshold_power" => Some(ExdDescriptors::FunctionalThresholdPower),
            "intensity_factor" => Some(ExdDescriptors::IntensityFactor),
            "work" => Some(ExdDescriptors::Work),
            "power_ratio" => Some(ExdDescriptors::PowerRatio),
            "normalized_power" => Some(ExdDescriptors::NormalizedPower),
            "training_stress_Score" => Some(ExdDescriptors::TrainingStressScore),
            "time_on_zone" => Some(ExdDescriptors::TimeOnZone),
            "speed" => Some(ExdDescriptors::Speed),
            "laps" => Some(ExdDescriptors::Laps),
            "reps" => Some(ExdDescriptors::Reps),
            "workout_step" => Some(ExdDescriptors::WorkoutStep),
            "course_distance" => Some(ExdDescriptors::CourseDistance),
            "navigation_distance" => Some(ExdDescriptors::NavigationDistance),
            "course_estimated_time_of_arrival" => {
                Some(ExdDescriptors::CourseEstimatedTimeOfArrival)
            }
            "navigation_estimated_time_of_arrival" => {
                Some(ExdDescriptors::NavigationEstimatedTimeOfArrival)
            }
            "course_time" => Some(ExdDescriptors::CourseTime),
            "navigation_time" => Some(ExdDescriptors::NavigationTime),
            "course_heading" => Some(ExdDescriptors::CourseHeading),
            "navigation_heading" => Some(ExdDescriptors::NavigationHeading),
            "power_zone" => Some(ExdDescriptors::PowerZone),
            "torque_effectiveness" => Some(ExdDescriptors::TorqueEffectiveness),
            "timer_time" => Some(ExdDescriptors::TimerTime),
            "power_weight_ratio" => Some(ExdDescriptors::PowerWeightRatio),
            "left_platform_center_offset" => Some(ExdDescriptors::LeftPlatformCenterOffset),
            "right_platform_center_offset" => Some(ExdDescriptors::RightPlatformCenterOffset),
            "left_power_phase_start_angle" => Some(ExdDescriptors::LeftPowerPhaseStartAngle),
            "right_power_phase_start_angle" => Some(ExdDescriptors::RightPowerPhaseStartAngle),
            "left_power_phase_finish_angle" => Some(ExdDescriptors::LeftPowerPhaseFinishAngle),
            "right_power_phase_finish_angle" => Some(ExdDescriptors::RightPowerPhaseFinishAngle),
            "gears" => Some(ExdDescriptors::Gears),
            "pace" => Some(ExdDescriptors::Pace),
            "training_effect" => Some(ExdDescriptors::TrainingEffect),
            "vertical_oscillation" => Some(ExdDescriptors::VerticalOscillation),
            "vertical_ratio" => Some(ExdDescriptors::VerticalRatio),
            "ground_contact_time" => Some(ExdDescriptors::GroundContactTime),
            "left_ground_contact_time_balance" => {
                Some(ExdDescriptors::LeftGroundContactTimeBalance)
            }
            "right_ground_contact_time_balance" => {
                Some(ExdDescriptors::RightGroundContactTimeBalance)
            }
            "stride_length" => Some(ExdDescriptors::StrideLength),
            "running_cadence" => Some(ExdDescriptors::RunningCadence),
            "performance_condition" => Some(ExdDescriptors::PerformanceCondition),
            "course_type" => Some(ExdDescriptors::CourseType),
            "time_in_power_zone" => Some(ExdDescriptors::TimeInPowerZone),
            "navigation_turn" => Some(ExdDescriptors::NavigationTurn),
            "course_location" => Some(ExdDescriptors::CourseLocation),
            "navigation_location" => Some(ExdDescriptors::NavigationLocation),
            "compass" => Some(ExdDescriptors::Compass),
            "gear_combo" => Some(ExdDescriptors::GearCombo),
            "muscle_oxygen" => Some(ExdDescriptors::MuscleOxygen),
            "icon" => Some(ExdDescriptors::Icon),
            "compass_heading" => Some(ExdDescriptors::CompassHeading),
            "gps_heading" => Some(ExdDescriptors::GpsHeading),
            "gps_elevation" => Some(ExdDescriptors::GpsElevation),
            "anaerobic_training_effect" => Some(ExdDescriptors::AnaerobicTrainingEffect),
            "course" => Some(ExdDescriptors::Course),
            "off_course" => Some(ExdDescriptors::OffCourse),
            "glide_ratio" => Some(ExdDescriptors::GlideRatio),
            "vertical_distance" => Some(ExdDescriptors::VerticalDistance),
            "vmg" => Some(ExdDescriptors::Vmg),
            "ambient_pressure" => Some(ExdDescriptors::AmbientPressure),
            "pressure" => Some(ExdDescriptors::Pressure),
            "vam" => Some(ExdDescriptors::Vam),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u32)]
#[non_exhaustive]
pub enum AutoActivityDetect {
    None = 0,
    Running = 1,
    Cycling = 2,
    Swimming = 4,
    Walking = 8,
    Elliptical = 32,
    Sedentary = 1024,
}

impl AutoActivityDetect {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            AutoActivityDetect::None => "none",
            AutoActivityDetect::Running => "running",
            AutoActivityDetect::Cycling => "cycling",
            AutoActivityDetect::Swimming => "swimming",
            AutoActivityDetect::Walking => "walking",
            AutoActivityDetect::Elliptical => "elliptical",
            AutoActivityDetect::Sedentary => "sedentary",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u32) -> Option<Self> {
        match value {
            0 => Some(AutoActivityDetect::None),
            1 => Some(AutoActivityDetect::Running),
            2 => Some(AutoActivityDetect::Cycling),
            4 => Some(AutoActivityDetect::Swimming),
            8 => Some(AutoActivityDetect::Walking),
            32 => Some(AutoActivityDetect::Elliptical),
            1024 => Some(AutoActivityDetect::Sedentary),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "none" => Some(AutoActivityDetect::None),
            "running" => Some(AutoActivityDetect::Running),
            "cycling" => Some(AutoActivityDetect::Cycling),
            "swimming" => Some(AutoActivityDetect::Swimming),
            "walking" => Some(AutoActivityDetect::Walking),
            "elliptical" => Some(AutoActivityDetect::Elliptical),
            "sedentary" => Some(AutoActivityDetect::Sedentary),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u32)]
#[non_exhaustive]
pub enum SupportedExdScreenLayouts {
    FullScreen = 1,
    HalfVertical = 2,
    HalfHorizontal = 4,
    HalfVerticalRightSplit = 8,
    HalfHorizontalBottomSplit = 16,
    FullQuarterSplit = 32,
    HalfVerticalLeftSplit = 64,
    HalfHorizontalTopSplit = 128,
}

impl SupportedExdScreenLayouts {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            SupportedExdScreenLayouts::FullScreen => "full_screen",
            SupportedExdScreenLayouts::HalfVertical => "half_vertical",
            SupportedExdScreenLayouts::HalfHorizontal => "half_horizontal",
            SupportedExdScreenLayouts::HalfVerticalRightSplit => "half_vertical_right_split",
            SupportedExdScreenLayouts::HalfHorizontalBottomSplit => "half_horizontal_bottom_split",
            SupportedExdScreenLayouts::FullQuarterSplit => "full_quarter_split",
            SupportedExdScreenLayouts::HalfVerticalLeftSplit => "half_vertical_left_split",
            SupportedExdScreenLayouts::HalfHorizontalTopSplit => "half_horizontal_top_split",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u32) -> Option<Self> {
        match value {
            1 => Some(SupportedExdScreenLayouts::FullScreen),
            2 => Some(SupportedExdScreenLayouts::HalfVertical),
            4 => Some(SupportedExdScreenLayouts::HalfHorizontal),
            8 => Some(SupportedExdScreenLayouts::HalfVerticalRightSplit),
            16 => Some(SupportedExdScreenLayouts::HalfHorizontalBottomSplit),
            32 => Some(SupportedExdScreenLayouts::FullQuarterSplit),
            64 => Some(SupportedExdScreenLayouts::HalfVerticalLeftSplit),
            128 => Some(SupportedExdScreenLayouts::HalfHorizontalTopSplit),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "full_screen" => Some(SupportedExdScreenLayouts::FullScreen),
            "half_vertical" => Some(SupportedExdScreenLayouts::HalfVertical),
            "half_horizontal" => Some(SupportedExdScreenLayouts::HalfHorizontal),
            "half_vertical_right_split" => Some(SupportedExdScreenLayouts::HalfVerticalRightSplit),
            "half_horizontal_bottom_split" => {
                Some(SupportedExdScreenLayouts::HalfHorizontalBottomSplit)
            }
            "full_quarter_split" => Some(SupportedExdScreenLayouts::FullQuarterSplit),
            "half_vertical_left_split" => Some(SupportedExdScreenLayouts::HalfVerticalLeftSplit),
            "half_horizontal_top_split" => Some(SupportedExdScreenLayouts::HalfHorizontalTopSplit),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum FitBaseType {
    Enum = 0,
    Sint8 = 1,
    Uint8 = 2,
    Sint16 = 131,
    Uint16 = 132,
    Sint32 = 133,
    Uint32 = 134,
    String = 7,
    Float32 = 136,
    Float64 = 137,
    Uint8z = 10,
    Uint16z = 139,
    Uint32z = 140,
    Byte = 13,
    Sint64 = 142,
    Uint64 = 143,
    Uint64z = 144,
}

impl FitBaseType {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            FitBaseType::Enum => "enum",
            FitBaseType::Sint8 => "sint8",
            FitBaseType::Uint8 => "uint8",
            FitBaseType::Sint16 => "sint16",
            FitBaseType::Uint16 => "uint16",
            FitBaseType::Sint32 => "sint32",
            FitBaseType::Uint32 => "uint32",
            FitBaseType::String => "string",
            FitBaseType::Float32 => "float32",
            FitBaseType::Float64 => "float64",
            FitBaseType::Uint8z => "uint8z",
            FitBaseType::Uint16z => "uint16z",
            FitBaseType::Uint32z => "uint32z",
            FitBaseType::Byte => "byte",
            FitBaseType::Sint64 => "sint64",
            FitBaseType::Uint64 => "uint64",
            FitBaseType::Uint64z => "uint64z",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(FitBaseType::Enum),
            1 => Some(FitBaseType::Sint8),
            2 => Some(FitBaseType::Uint8),
            131 => Some(FitBaseType::Sint16),
            132 => Some(FitBaseType::Uint16),
            133 => Some(FitBaseType::Sint32),
            134 => Some(FitBaseType::Uint32),
            7 => Some(FitBaseType::String),
            136 => Some(FitBaseType::Float32),
            137 => Some(FitBaseType::Float64),
            10 => Some(FitBaseType::Uint8z),
            139 => Some(FitBaseType::Uint16z),
            140 => Some(FitBaseType::Uint32z),
            13 => Some(FitBaseType::Byte),
            142 => Some(FitBaseType::Sint64),
            143 => Some(FitBaseType::Uint64),
            144 => Some(FitBaseType::Uint64z),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "enum" => Some(FitBaseType::Enum),
            "sint8" => Some(FitBaseType::Sint8),
            "uint8" => Some(FitBaseType::Uint8),
            "sint16" => Some(FitBaseType::Sint16),
            "uint16" => Some(FitBaseType::Uint16),
            "sint32" => Some(FitBaseType::Sint32),
            "uint32" => Some(FitBaseType::Uint32),
            "string" => Some(FitBaseType::String),
            "float32" => Some(FitBaseType::Float32),
            "float64" => Some(FitBaseType::Float64),
            "uint8z" => Some(FitBaseType::Uint8z),
            "uint16z" => Some(FitBaseType::Uint16z),
            "uint32z" => Some(FitBaseType::Uint32z),
            "byte" => Some(FitBaseType::Byte),
            "sint64" => Some(FitBaseType::Sint64),
            "uint64" => Some(FitBaseType::Uint64),
            "uint64z" => Some(FitBaseType::Uint64z),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum TurnType {
    ArrivingIdx = 0,
    ArrivingLeftIdx = 1,
    ArrivingRightIdx = 2,
    ArrivingViaIdx = 3,
    ArrivingViaLeftIdx = 4,
    ArrivingViaRightIdx = 5,
    BearKeepLeftIdx = 6,
    BearKeepRightIdx = 7,
    ContinueIdx = 8,
    ExitLeftIdx = 9,
    ExitRightIdx = 10,
    FerryIdx = 11,
    Roundabout45Idx = 12,
    Roundabout90Idx = 13,
    Roundabout135Idx = 14,
    Roundabout180Idx = 15,
    Roundabout225Idx = 16,
    Roundabout270Idx = 17,
    Roundabout315Idx = 18,
    Roundabout360Idx = 19,
    RoundaboutNeg45Idx = 20,
    RoundaboutNeg90Idx = 21,
    RoundaboutNeg135Idx = 22,
    RoundaboutNeg180Idx = 23,
    RoundaboutNeg225Idx = 24,
    RoundaboutNeg270Idx = 25,
    RoundaboutNeg315Idx = 26,
    RoundaboutNeg360Idx = 27,
    RoundaboutGenericIdx = 28,
    RoundaboutNegGenericIdx = 29,
    SharpTurnLeftIdx = 30,
    SharpTurnRightIdx = 31,
    TurnLeftIdx = 32,
    TurnRightIdx = 33,
    UturnLeftIdx = 34,
    UturnRightIdx = 35,
    IconInvIdx = 36,
    IconIdxCnt = 37,
}

impl TurnType {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            TurnType::ArrivingIdx => "arriving_idx",
            TurnType::ArrivingLeftIdx => "arriving_left_idx",
            TurnType::ArrivingRightIdx => "arriving_right_idx",
            TurnType::ArrivingViaIdx => "arriving_via_idx",
            TurnType::ArrivingViaLeftIdx => "arriving_via_left_idx",
            TurnType::ArrivingViaRightIdx => "arriving_via_right_idx",
            TurnType::BearKeepLeftIdx => "bear_keep_left_idx",
            TurnType::BearKeepRightIdx => "bear_keep_right_idx",
            TurnType::ContinueIdx => "continue_idx",
            TurnType::ExitLeftIdx => "exit_left_idx",
            TurnType::ExitRightIdx => "exit_right_idx",
            TurnType::FerryIdx => "ferry_idx",
            TurnType::Roundabout45Idx => "roundabout_45_idx",
            TurnType::Roundabout90Idx => "roundabout_90_idx",
            TurnType::Roundabout135Idx => "roundabout_135_idx",
            TurnType::Roundabout180Idx => "roundabout_180_idx",
            TurnType::Roundabout225Idx => "roundabout_225_idx",
            TurnType::Roundabout270Idx => "roundabout_270_idx",
            TurnType::Roundabout315Idx => "roundabout_315_idx",
            TurnType::Roundabout360Idx => "roundabout_360_idx",
            TurnType::RoundaboutNeg45Idx => "roundabout_neg_45_idx",
            TurnType::RoundaboutNeg90Idx => "roundabout_neg_90_idx",
            TurnType::RoundaboutNeg135Idx => "roundabout_neg_135_idx",
            TurnType::RoundaboutNeg180Idx => "roundabout_neg_180_idx",
            TurnType::RoundaboutNeg225Idx => "roundabout_neg_225_idx",
            TurnType::RoundaboutNeg270Idx => "roundabout_neg_270_idx",
            TurnType::RoundaboutNeg315Idx => "roundabout_neg_315_idx",
            TurnType::RoundaboutNeg360Idx => "roundabout_neg_360_idx",
            TurnType::RoundaboutGenericIdx => "roundabout_generic_idx",
            TurnType::RoundaboutNegGenericIdx => "roundabout_neg_generic_idx",
            TurnType::SharpTurnLeftIdx => "sharp_turn_left_idx",
            TurnType::SharpTurnRightIdx => "sharp_turn_right_idx",
            TurnType::TurnLeftIdx => "turn_left_idx",
            TurnType::TurnRightIdx => "turn_right_idx",
            TurnType::UturnLeftIdx => "uturn_left_idx",
            TurnType::UturnRightIdx => "uturn_right_idx",
            TurnType::IconInvIdx => "icon_inv_idx",
            TurnType::IconIdxCnt => "icon_idx_cnt",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(TurnType::ArrivingIdx),
            1 => Some(TurnType::ArrivingLeftIdx),
            2 => Some(TurnType::ArrivingRightIdx),
            3 => Some(TurnType::ArrivingViaIdx),
            4 => Some(TurnType::ArrivingViaLeftIdx),
            5 => Some(TurnType::ArrivingViaRightIdx),
            6 => Some(TurnType::BearKeepLeftIdx),
            7 => Some(TurnType::BearKeepRightIdx),
            8 => Some(TurnType::ContinueIdx),
            9 => Some(TurnType::ExitLeftIdx),
            10 => Some(TurnType::ExitRightIdx),
            11 => Some(TurnType::FerryIdx),
            12 => Some(TurnType::Roundabout45Idx),
            13 => Some(TurnType::Roundabout90Idx),
            14 => Some(TurnType::Roundabout135Idx),
            15 => Some(TurnType::Roundabout180Idx),
            16 => Some(TurnType::Roundabout225Idx),
            17 => Some(TurnType::Roundabout270Idx),
            18 => Some(TurnType::Roundabout315Idx),
            19 => Some(TurnType::Roundabout360Idx),
            20 => Some(TurnType::RoundaboutNeg45Idx),
            21 => Some(TurnType::RoundaboutNeg90Idx),
            22 => Some(TurnType::RoundaboutNeg135Idx),
            23 => Some(TurnType::RoundaboutNeg180Idx),
            24 => Some(TurnType::RoundaboutNeg225Idx),
            25 => Some(TurnType::RoundaboutNeg270Idx),
            26 => Some(TurnType::RoundaboutNeg315Idx),
            27 => Some(TurnType::RoundaboutNeg360Idx),
            28 => Some(TurnType::RoundaboutGenericIdx),
            29 => Some(TurnType::RoundaboutNegGenericIdx),
            30 => Some(TurnType::SharpTurnLeftIdx),
            31 => Some(TurnType::SharpTurnRightIdx),
            32 => Some(TurnType::TurnLeftIdx),
            33 => Some(TurnType::TurnRightIdx),
            34 => Some(TurnType::UturnLeftIdx),
            35 => Some(TurnType::UturnRightIdx),
            36 => Some(TurnType::IconInvIdx),
            37 => Some(TurnType::IconIdxCnt),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "arriving_idx" => Some(TurnType::ArrivingIdx),
            "arriving_left_idx" => Some(TurnType::ArrivingLeftIdx),
            "arriving_right_idx" => Some(TurnType::ArrivingRightIdx),
            "arriving_via_idx" => Some(TurnType::ArrivingViaIdx),
            "arriving_via_left_idx" => Some(TurnType::ArrivingViaLeftIdx),
            "arriving_via_right_idx" => Some(TurnType::ArrivingViaRightIdx),
            "bear_keep_left_idx" => Some(TurnType::BearKeepLeftIdx),
            "bear_keep_right_idx" => Some(TurnType::BearKeepRightIdx),
            "continue_idx" => Some(TurnType::ContinueIdx),
            "exit_left_idx" => Some(TurnType::ExitLeftIdx),
            "exit_right_idx" => Some(TurnType::ExitRightIdx),
            "ferry_idx" => Some(TurnType::FerryIdx),
            "roundabout_45_idx" => Some(TurnType::Roundabout45Idx),
            "roundabout_90_idx" => Some(TurnType::Roundabout90Idx),
            "roundabout_135_idx" => Some(TurnType::Roundabout135Idx),
            "roundabout_180_idx" => Some(TurnType::Roundabout180Idx),
            "roundabout_225_idx" => Some(TurnType::Roundabout225Idx),
            "roundabout_270_idx" => Some(TurnType::Roundabout270Idx),
            "roundabout_315_idx" => Some(TurnType::Roundabout315Idx),
            "roundabout_360_idx" => Some(TurnType::Roundabout360Idx),
            "roundabout_neg_45_idx" => Some(TurnType::RoundaboutNeg45Idx),
            "roundabout_neg_90_idx" => Some(TurnType::RoundaboutNeg90Idx),
            "roundabout_neg_135_idx" => Some(TurnType::RoundaboutNeg135Idx),
            "roundabout_neg_180_idx" => Some(TurnType::RoundaboutNeg180Idx),
            "roundabout_neg_225_idx" => Some(TurnType::RoundaboutNeg225Idx),
            "roundabout_neg_270_idx" => Some(TurnType::RoundaboutNeg270Idx),
            "roundabout_neg_315_idx" => Some(TurnType::RoundaboutNeg315Idx),
            "roundabout_neg_360_idx" => Some(TurnType::RoundaboutNeg360Idx),
            "roundabout_generic_idx" => Some(TurnType::RoundaboutGenericIdx),
            "roundabout_neg_generic_idx" => Some(TurnType::RoundaboutNegGenericIdx),
            "sharp_turn_left_idx" => Some(TurnType::SharpTurnLeftIdx),
            "sharp_turn_right_idx" => Some(TurnType::SharpTurnRightIdx),
            "turn_left_idx" => Some(TurnType::TurnLeftIdx),
            "turn_right_idx" => Some(TurnType::TurnRightIdx),
            "uturn_left_idx" => Some(TurnType::UturnLeftIdx),
            "uturn_right_idx" => Some(TurnType::UturnRightIdx),
            "icon_inv_idx" => Some(TurnType::IconInvIdx),
            "icon_idx_cnt" => Some(TurnType::IconIdxCnt),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum BikeLightBeamAngleMode {
    Manual = 0,
    Auto = 1,
}

impl BikeLightBeamAngleMode {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            BikeLightBeamAngleMode::Manual => "manual",
            BikeLightBeamAngleMode::Auto => "auto",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(BikeLightBeamAngleMode::Manual),
            1 => Some(BikeLightBeamAngleMode::Auto),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "manual" => Some(BikeLightBeamAngleMode::Manual),
            "auto" => Some(BikeLightBeamAngleMode::Auto),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum FitBaseUnit {
    Other = 0,
    Kilogram = 1,
    Pound = 2,
}

impl FitBaseUnit {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            FitBaseUnit::Other => "other",
            FitBaseUnit::Kilogram => "kilogram",
            FitBaseUnit::Pound => "pound",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(FitBaseUnit::Other),
            1 => Some(FitBaseUnit::Kilogram),
            2 => Some(FitBaseUnit::Pound),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "other" => Some(FitBaseUnit::Other),
            "kilogram" => Some(FitBaseUnit::Kilogram),
            "pound" => Some(FitBaseUnit::Pound),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum SetType {
    Rest = 0,
    Active = 1,
}

impl SetType {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            SetType::Rest => "rest",
            SetType::Active => "active",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(SetType::Rest),
            1 => Some(SetType::Active),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "rest" => Some(SetType::Rest),
            "active" => Some(SetType::Active),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum MaxMetCategory {
    Generic = 0,
    Cycling = 1,
}

impl MaxMetCategory {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            MaxMetCategory::Generic => "generic",
            MaxMetCategory::Cycling => "cycling",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(MaxMetCategory::Generic),
            1 => Some(MaxMetCategory::Cycling),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "generic" => Some(MaxMetCategory::Generic),
            "cycling" => Some(MaxMetCategory::Cycling),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum ExerciseCategory {
    BenchPress = 0,
    CalfRaise = 1,
    Cardio = 2,
    Carry = 3,
    Chop = 4,
    Core = 5,
    Crunch = 6,
    Curl = 7,
    Deadlift = 8,
    Flye = 9,
    HipRaise = 10,
    HipStability = 11,
    HipSwing = 12,
    Hyperextension = 13,
    LateralRaise = 14,
    LegCurl = 15,
    LegRaise = 16,
    Lunge = 17,
    OlympicLift = 18,
    Plank = 19,
    Plyo = 20,
    PullUp = 21,
    PushUp = 22,
    Row = 23,
    ShoulderPress = 24,
    ShoulderStability = 25,
    Shrug = 26,
    SitUp = 27,
    Squat = 28,
    TotalBody = 29,
    TricepsExtension = 30,
    WarmUp = 31,
    Run = 32,
    Bike = 33,
    CardioSensors = 34,
    Move = 35,
    Pose = 36,
    BandedExercises = 37,
    BattleRope = 38,
    Elliptical = 39,
    FloorClimb = 40,
    IndoorBike = 41,
    IndoorRow = 42,
    Ladder = 43,
    Sandbag = 44,
    Sled = 45,
    SledgeHammer = 46,
    StairStepper = 47,
    Suspension = 49,
    Tire = 50,
    RunIndoor = 52,
    BikeOutdoor = 53,
    Unknown = 65534,
}

impl ExerciseCategory {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            ExerciseCategory::BenchPress => "bench_press",
            ExerciseCategory::CalfRaise => "calf_raise",
            ExerciseCategory::Cardio => "cardio",
            ExerciseCategory::Carry => "carry",
            ExerciseCategory::Chop => "chop",
            ExerciseCategory::Core => "core",
            ExerciseCategory::Crunch => "crunch",
            ExerciseCategory::Curl => "curl",
            ExerciseCategory::Deadlift => "deadlift",
            ExerciseCategory::Flye => "flye",
            ExerciseCategory::HipRaise => "hip_raise",
            ExerciseCategory::HipStability => "hip_stability",
            ExerciseCategory::HipSwing => "hip_swing",
            ExerciseCategory::Hyperextension => "hyperextension",
            ExerciseCategory::LateralRaise => "lateral_raise",
            ExerciseCategory::LegCurl => "leg_curl",
            ExerciseCategory::LegRaise => "leg_raise",
            ExerciseCategory::Lunge => "lunge",
            ExerciseCategory::OlympicLift => "olympic_lift",
            ExerciseCategory::Plank => "plank",
            ExerciseCategory::Plyo => "plyo",
            ExerciseCategory::PullUp => "pull_up",
            ExerciseCategory::PushUp => "push_up",
            ExerciseCategory::Row => "row",
            ExerciseCategory::ShoulderPress => "shoulder_press",
            ExerciseCategory::ShoulderStability => "shoulder_stability",
            ExerciseCategory::Shrug => "shrug",
            ExerciseCategory::SitUp => "sit_up",
            ExerciseCategory::Squat => "squat",
            ExerciseCategory::TotalBody => "total_body",
            ExerciseCategory::TricepsExtension => "triceps_extension",
            ExerciseCategory::WarmUp => "warm_up",
            ExerciseCategory::Run => "run",
            ExerciseCategory::Bike => "bike",
            ExerciseCategory::CardioSensors => "cardio_sensors",
            ExerciseCategory::Move => "move",
            ExerciseCategory::Pose => "pose",
            ExerciseCategory::BandedExercises => "banded_exercises",
            ExerciseCategory::BattleRope => "battle_rope",
            ExerciseCategory::Elliptical => "elliptical",
            ExerciseCategory::FloorClimb => "floor_climb",
            ExerciseCategory::IndoorBike => "indoor_bike",
            ExerciseCategory::IndoorRow => "indoor_row",
            ExerciseCategory::Ladder => "ladder",
            ExerciseCategory::Sandbag => "sandbag",
            ExerciseCategory::Sled => "sled",
            ExerciseCategory::SledgeHammer => "sledge_hammer",
            ExerciseCategory::StairStepper => "stair_stepper",
            ExerciseCategory::Suspension => "suspension",
            ExerciseCategory::Tire => "tire",
            ExerciseCategory::RunIndoor => "run_indoor",
            ExerciseCategory::BikeOutdoor => "bike_outdoor",
            ExerciseCategory::Unknown => "unknown",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(ExerciseCategory::BenchPress),
            1 => Some(ExerciseCategory::CalfRaise),
            2 => Some(ExerciseCategory::Cardio),
            3 => Some(ExerciseCategory::Carry),
            4 => Some(ExerciseCategory::Chop),
            5 => Some(ExerciseCategory::Core),
            6 => Some(ExerciseCategory::Crunch),
            7 => Some(ExerciseCategory::Curl),
            8 => Some(ExerciseCategory::Deadlift),
            9 => Some(ExerciseCategory::Flye),
            10 => Some(ExerciseCategory::HipRaise),
            11 => Some(ExerciseCategory::HipStability),
            12 => Some(ExerciseCategory::HipSwing),
            13 => Some(ExerciseCategory::Hyperextension),
            14 => Some(ExerciseCategory::LateralRaise),
            15 => Some(ExerciseCategory::LegCurl),
            16 => Some(ExerciseCategory::LegRaise),
            17 => Some(ExerciseCategory::Lunge),
            18 => Some(ExerciseCategory::OlympicLift),
            19 => Some(ExerciseCategory::Plank),
            20 => Some(ExerciseCategory::Plyo),
            21 => Some(ExerciseCategory::PullUp),
            22 => Some(ExerciseCategory::PushUp),
            23 => Some(ExerciseCategory::Row),
            24 => Some(ExerciseCategory::ShoulderPress),
            25 => Some(ExerciseCategory::ShoulderStability),
            26 => Some(ExerciseCategory::Shrug),
            27 => Some(ExerciseCategory::SitUp),
            28 => Some(ExerciseCategory::Squat),
            29 => Some(ExerciseCategory::TotalBody),
            30 => Some(ExerciseCategory::TricepsExtension),
            31 => Some(ExerciseCategory::WarmUp),
            32 => Some(ExerciseCategory::Run),
            33 => Some(ExerciseCategory::Bike),
            34 => Some(ExerciseCategory::CardioSensors),
            35 => Some(ExerciseCategory::Move),
            36 => Some(ExerciseCategory::Pose),
            37 => Some(ExerciseCategory::BandedExercises),
            38 => Some(ExerciseCategory::BattleRope),
            39 => Some(ExerciseCategory::Elliptical),
            40 => Some(ExerciseCategory::FloorClimb),
            41 => Some(ExerciseCategory::IndoorBike),
            42 => Some(ExerciseCategory::IndoorRow),
            43 => Some(ExerciseCategory::Ladder),
            44 => Some(ExerciseCategory::Sandbag),
            45 => Some(ExerciseCategory::Sled),
            46 => Some(ExerciseCategory::SledgeHammer),
            47 => Some(ExerciseCategory::StairStepper),
            49 => Some(ExerciseCategory::Suspension),
            50 => Some(ExerciseCategory::Tire),
            52 => Some(ExerciseCategory::RunIndoor),
            53 => Some(ExerciseCategory::BikeOutdoor),
            65534 => Some(ExerciseCategory::Unknown),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "bench_press" => Some(ExerciseCategory::BenchPress),
            "calf_raise" => Some(ExerciseCategory::CalfRaise),
            "cardio" => Some(ExerciseCategory::Cardio),
            "carry" => Some(ExerciseCategory::Carry),
            "chop" => Some(ExerciseCategory::Chop),
            "core" => Some(ExerciseCategory::Core),
            "crunch" => Some(ExerciseCategory::Crunch),
            "curl" => Some(ExerciseCategory::Curl),
            "deadlift" => Some(ExerciseCategory::Deadlift),
            "flye" => Some(ExerciseCategory::Flye),
            "hip_raise" => Some(ExerciseCategory::HipRaise),
            "hip_stability" => Some(ExerciseCategory::HipStability),
            "hip_swing" => Some(ExerciseCategory::HipSwing),
            "hyperextension" => Some(ExerciseCategory::Hyperextension),
            "lateral_raise" => Some(ExerciseCategory::LateralRaise),
            "leg_curl" => Some(ExerciseCategory::LegCurl),
            "leg_raise" => Some(ExerciseCategory::LegRaise),
            "lunge" => Some(ExerciseCategory::Lunge),
            "olympic_lift" => Some(ExerciseCategory::OlympicLift),
            "plank" => Some(ExerciseCategory::Plank),
            "plyo" => Some(ExerciseCategory::Plyo),
            "pull_up" => Some(ExerciseCategory::PullUp),
            "push_up" => Some(ExerciseCategory::PushUp),
            "row" => Some(ExerciseCategory::Row),
            "shoulder_press" => Some(ExerciseCategory::ShoulderPress),
            "shoulder_stability" => Some(ExerciseCategory::ShoulderStability),
            "shrug" => Some(ExerciseCategory::Shrug),
            "sit_up" => Some(ExerciseCategory::SitUp),
            "squat" => Some(ExerciseCategory::Squat),
            "total_body" => Some(ExerciseCategory::TotalBody),
            "triceps_extension" => Some(ExerciseCategory::TricepsExtension),
            "warm_up" => Some(ExerciseCategory::WarmUp),
            "run" => Some(ExerciseCategory::Run),
            "bike" => Some(ExerciseCategory::Bike),
            "cardio_sensors" => Some(ExerciseCategory::CardioSensors),
            "move" => Some(ExerciseCategory::Move),
            "pose" => Some(ExerciseCategory::Pose),
            "banded_exercises" => Some(ExerciseCategory::BandedExercises),
            "battle_rope" => Some(ExerciseCategory::BattleRope),
            "elliptical" => Some(ExerciseCategory::Elliptical),
            "floor_climb" => Some(ExerciseCategory::FloorClimb),
            "indoor_bike" => Some(ExerciseCategory::IndoorBike),
            "indoor_row" => Some(ExerciseCategory::IndoorRow),
            "ladder" => Some(ExerciseCategory::Ladder),
            "sandbag" => Some(ExerciseCategory::Sandbag),
            "sled" => Some(ExerciseCategory::Sled),
            "sledge_hammer" => Some(ExerciseCategory::SledgeHammer),
            "stair_stepper" => Some(ExerciseCategory::StairStepper),
            "suspension" => Some(ExerciseCategory::Suspension),
            "tire" => Some(ExerciseCategory::Tire),
            "run_indoor" => Some(ExerciseCategory::RunIndoor),
            "bike_outdoor" => Some(ExerciseCategory::BikeOutdoor),
            "unknown" => Some(ExerciseCategory::Unknown),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum BenchPressExerciseName {
    AlternatingDumbbellChestPressOnSwissBall = 0,
    BarbellBenchPress = 1,
    BarbellBoardBenchPress = 2,
    BarbellFloorPress = 3,
    CloseGripBarbellBenchPress = 4,
    DeclineDumbbellBenchPress = 5,
    DumbbellBenchPress = 6,
    DumbbellFloorPress = 7,
    InclineBarbellBenchPress = 8,
    InclineDumbbellBenchPress = 9,
    InclineSmithMachineBenchPress = 10,
    IsometricBarbellBenchPress = 11,
    KettlebellChestPress = 12,
    NeutralGripDumbbellBenchPress = 13,
    NeutralGripDumbbellInclineBenchPress = 14,
    OneArmFloorPress = 15,
    WeightedOneArmFloorPress = 16,
    PartialLockout = 17,
    ReverseGripBarbellBenchPress = 18,
    ReverseGripInclineBenchPress = 19,
    SingleArmCableChestPress = 20,
    SingleArmDumbbellBenchPress = 21,
    SmithMachineBenchPress = 22,
    SwissBallDumbbellChestPress = 23,
    TripleStopBarbellBenchPress = 24,
    WideGripBarbellBenchPress = 25,
    AlternatingDumbbellChestPress = 26,
}

impl BenchPressExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            BenchPressExerciseName::AlternatingDumbbellChestPressOnSwissBall => {
                "alternating_dumbbell_chest_press_on_swiss_ball"
            }
            BenchPressExerciseName::BarbellBenchPress => "barbell_bench_press",
            BenchPressExerciseName::BarbellBoardBenchPress => "barbell_board_bench_press",
            BenchPressExerciseName::BarbellFloorPress => "barbell_floor_press",
            BenchPressExerciseName::CloseGripBarbellBenchPress => "close_grip_barbell_bench_press",
            BenchPressExerciseName::DeclineDumbbellBenchPress => "decline_dumbbell_bench_press",
            BenchPressExerciseName::DumbbellBenchPress => "dumbbell_bench_press",
            BenchPressExerciseName::DumbbellFloorPress => "dumbbell_floor_press",
            BenchPressExerciseName::InclineBarbellBenchPress => "incline_barbell_bench_press",
            BenchPressExerciseName::InclineDumbbellBenchPress => "incline_dumbbell_bench_press",
            BenchPressExerciseName::InclineSmithMachineBenchPress => {
                "incline_smith_machine_bench_press"
            }
            BenchPressExerciseName::IsometricBarbellBenchPress => "isometric_barbell_bench_press",
            BenchPressExerciseName::KettlebellChestPress => "kettlebell_chest_press",
            BenchPressExerciseName::NeutralGripDumbbellBenchPress => {
                "neutral_grip_dumbbell_bench_press"
            }
            BenchPressExerciseName::NeutralGripDumbbellInclineBenchPress => {
                "neutral_grip_dumbbell_incline_bench_press"
            }
            BenchPressExerciseName::OneArmFloorPress => "one_arm_floor_press",
            BenchPressExerciseName::WeightedOneArmFloorPress => "weighted_one_arm_floor_press",
            BenchPressExerciseName::PartialLockout => "partial_lockout",
            BenchPressExerciseName::ReverseGripBarbellBenchPress => {
                "reverse_grip_barbell_bench_press"
            }
            BenchPressExerciseName::ReverseGripInclineBenchPress => {
                "reverse_grip_incline_bench_press"
            }
            BenchPressExerciseName::SingleArmCableChestPress => "single_arm_cable_chest_press",
            BenchPressExerciseName::SingleArmDumbbellBenchPress => {
                "single_arm_dumbbell_bench_press"
            }
            BenchPressExerciseName::SmithMachineBenchPress => "smith_machine_bench_press",
            BenchPressExerciseName::SwissBallDumbbellChestPress => {
                "swiss_ball_dumbbell_chest_press"
            }
            BenchPressExerciseName::TripleStopBarbellBenchPress => {
                "triple_stop_barbell_bench_press"
            }
            BenchPressExerciseName::WideGripBarbellBenchPress => "wide_grip_barbell_bench_press",
            BenchPressExerciseName::AlternatingDumbbellChestPress => {
                "alternating_dumbbell_chest_press"
            }
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(BenchPressExerciseName::AlternatingDumbbellChestPressOnSwissBall),
            1 => Some(BenchPressExerciseName::BarbellBenchPress),
            2 => Some(BenchPressExerciseName::BarbellBoardBenchPress),
            3 => Some(BenchPressExerciseName::BarbellFloorPress),
            4 => Some(BenchPressExerciseName::CloseGripBarbellBenchPress),
            5 => Some(BenchPressExerciseName::DeclineDumbbellBenchPress),
            6 => Some(BenchPressExerciseName::DumbbellBenchPress),
            7 => Some(BenchPressExerciseName::DumbbellFloorPress),
            8 => Some(BenchPressExerciseName::InclineBarbellBenchPress),
            9 => Some(BenchPressExerciseName::InclineDumbbellBenchPress),
            10 => Some(BenchPressExerciseName::InclineSmithMachineBenchPress),
            11 => Some(BenchPressExerciseName::IsometricBarbellBenchPress),
            12 => Some(BenchPressExerciseName::KettlebellChestPress),
            13 => Some(BenchPressExerciseName::NeutralGripDumbbellBenchPress),
            14 => Some(BenchPressExerciseName::NeutralGripDumbbellInclineBenchPress),
            15 => Some(BenchPressExerciseName::OneArmFloorPress),
            16 => Some(BenchPressExerciseName::WeightedOneArmFloorPress),
            17 => Some(BenchPressExerciseName::PartialLockout),
            18 => Some(BenchPressExerciseName::ReverseGripBarbellBenchPress),
            19 => Some(BenchPressExerciseName::ReverseGripInclineBenchPress),
            20 => Some(BenchPressExerciseName::SingleArmCableChestPress),
            21 => Some(BenchPressExerciseName::SingleArmDumbbellBenchPress),
            22 => Some(BenchPressExerciseName::SmithMachineBenchPress),
            23 => Some(BenchPressExerciseName::SwissBallDumbbellChestPress),
            24 => Some(BenchPressExerciseName::TripleStopBarbellBenchPress),
            25 => Some(BenchPressExerciseName::WideGripBarbellBenchPress),
            26 => Some(BenchPressExerciseName::AlternatingDumbbellChestPress),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "alternating_dumbbell_chest_press_on_swiss_ball" => {
                Some(BenchPressExerciseName::AlternatingDumbbellChestPressOnSwissBall)
            }
            "barbell_bench_press" => Some(BenchPressExerciseName::BarbellBenchPress),
            "barbell_board_bench_press" => Some(BenchPressExerciseName::BarbellBoardBenchPress),
            "barbell_floor_press" => Some(BenchPressExerciseName::BarbellFloorPress),
            "close_grip_barbell_bench_press" => {
                Some(BenchPressExerciseName::CloseGripBarbellBenchPress)
            }
            "decline_dumbbell_bench_press" => {
                Some(BenchPressExerciseName::DeclineDumbbellBenchPress)
            }
            "dumbbell_bench_press" => Some(BenchPressExerciseName::DumbbellBenchPress),
            "dumbbell_floor_press" => Some(BenchPressExerciseName::DumbbellFloorPress),
            "incline_barbell_bench_press" => Some(BenchPressExerciseName::InclineBarbellBenchPress),
            "incline_dumbbell_bench_press" => {
                Some(BenchPressExerciseName::InclineDumbbellBenchPress)
            }
            "incline_smith_machine_bench_press" => {
                Some(BenchPressExerciseName::InclineSmithMachineBenchPress)
            }
            "isometric_barbell_bench_press" => {
                Some(BenchPressExerciseName::IsometricBarbellBenchPress)
            }
            "kettlebell_chest_press" => Some(BenchPressExerciseName::KettlebellChestPress),
            "neutral_grip_dumbbell_bench_press" => {
                Some(BenchPressExerciseName::NeutralGripDumbbellBenchPress)
            }
            "neutral_grip_dumbbell_incline_bench_press" => {
                Some(BenchPressExerciseName::NeutralGripDumbbellInclineBenchPress)
            }
            "one_arm_floor_press" => Some(BenchPressExerciseName::OneArmFloorPress),
            "weighted_one_arm_floor_press" => {
                Some(BenchPressExerciseName::WeightedOneArmFloorPress)
            }
            "partial_lockout" => Some(BenchPressExerciseName::PartialLockout),
            "reverse_grip_barbell_bench_press" => {
                Some(BenchPressExerciseName::ReverseGripBarbellBenchPress)
            }
            "reverse_grip_incline_bench_press" => {
                Some(BenchPressExerciseName::ReverseGripInclineBenchPress)
            }
            "single_arm_cable_chest_press" => {
                Some(BenchPressExerciseName::SingleArmCableChestPress)
            }
            "single_arm_dumbbell_bench_press" => {
                Some(BenchPressExerciseName::SingleArmDumbbellBenchPress)
            }
            "smith_machine_bench_press" => Some(BenchPressExerciseName::SmithMachineBenchPress),
            "swiss_ball_dumbbell_chest_press" => {
                Some(BenchPressExerciseName::SwissBallDumbbellChestPress)
            }
            "triple_stop_barbell_bench_press" => {
                Some(BenchPressExerciseName::TripleStopBarbellBenchPress)
            }
            "wide_grip_barbell_bench_press" => {
                Some(BenchPressExerciseName::WideGripBarbellBenchPress)
            }
            "alternating_dumbbell_chest_press" => {
                Some(BenchPressExerciseName::AlternatingDumbbellChestPress)
            }
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum CalfRaiseExerciseName {
    _3WayCalfRaise = 0,
    _3WayWeightedCalfRaise = 1,
    _3WaySingleLegCalfRaise = 2,
    _3WayWeightedSingleLegCalfRaise = 3,
    DonkeyCalfRaise = 4,
    WeightedDonkeyCalfRaise = 5,
    SeatedCalfRaise = 6,
    WeightedSeatedCalfRaise = 7,
    SeatedDumbbellToeRaise = 8,
    SingleLegBentKneeCalfRaise = 9,
    WeightedSingleLegBentKneeCalfRaise = 10,
    SingleLegDeclinePushUp = 11,
    SingleLegDonkeyCalfRaise = 12,
    WeightedSingleLegDonkeyCalfRaise = 13,
    SingleLegHipRaiseWithKneeHold = 14,
    SingleLegStandingCalfRaise = 15,
    SingleLegStandingDumbbellCalfRaise = 16,
    StandingBarbellCalfRaise = 17,
    StandingCalfRaise = 18,
    WeightedStandingCalfRaise = 19,
    StandingDumbbellCalfRaise = 20,
}

impl CalfRaiseExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            CalfRaiseExerciseName::_3WayCalfRaise => "3_way_calf_raise",
            CalfRaiseExerciseName::_3WayWeightedCalfRaise => "3_way_weighted_calf_raise",
            CalfRaiseExerciseName::_3WaySingleLegCalfRaise => "3_way_single_leg_calf_raise",
            CalfRaiseExerciseName::_3WayWeightedSingleLegCalfRaise => {
                "3_way_weighted_single_leg_calf_raise"
            }
            CalfRaiseExerciseName::DonkeyCalfRaise => "donkey_calf_raise",
            CalfRaiseExerciseName::WeightedDonkeyCalfRaise => "weighted_donkey_calf_raise",
            CalfRaiseExerciseName::SeatedCalfRaise => "seated_calf_raise",
            CalfRaiseExerciseName::WeightedSeatedCalfRaise => "weighted_seated_calf_raise",
            CalfRaiseExerciseName::SeatedDumbbellToeRaise => "seated_dumbbell_toe_raise",
            CalfRaiseExerciseName::SingleLegBentKneeCalfRaise => "single_leg_bent_knee_calf_raise",
            CalfRaiseExerciseName::WeightedSingleLegBentKneeCalfRaise => {
                "weighted_single_leg_bent_knee_calf_raise"
            }
            CalfRaiseExerciseName::SingleLegDeclinePushUp => "single_leg_decline_push_up",
            CalfRaiseExerciseName::SingleLegDonkeyCalfRaise => "single_leg_donkey_calf_raise",
            CalfRaiseExerciseName::WeightedSingleLegDonkeyCalfRaise => {
                "weighted_single_leg_donkey_calf_raise"
            }
            CalfRaiseExerciseName::SingleLegHipRaiseWithKneeHold => {
                "single_leg_hip_raise_with_knee_hold"
            }
            CalfRaiseExerciseName::SingleLegStandingCalfRaise => "single_leg_standing_calf_raise",
            CalfRaiseExerciseName::SingleLegStandingDumbbellCalfRaise => {
                "single_leg_standing_dumbbell_calf_raise"
            }
            CalfRaiseExerciseName::StandingBarbellCalfRaise => "standing_barbell_calf_raise",
            CalfRaiseExerciseName::StandingCalfRaise => "standing_calf_raise",
            CalfRaiseExerciseName::WeightedStandingCalfRaise => "weighted_standing_calf_raise",
            CalfRaiseExerciseName::StandingDumbbellCalfRaise => "standing_dumbbell_calf_raise",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(CalfRaiseExerciseName::_3WayCalfRaise),
            1 => Some(CalfRaiseExerciseName::_3WayWeightedCalfRaise),
            2 => Some(CalfRaiseExerciseName::_3WaySingleLegCalfRaise),
            3 => Some(CalfRaiseExerciseName::_3WayWeightedSingleLegCalfRaise),
            4 => Some(CalfRaiseExerciseName::DonkeyCalfRaise),
            5 => Some(CalfRaiseExerciseName::WeightedDonkeyCalfRaise),
            6 => Some(CalfRaiseExerciseName::SeatedCalfRaise),
            7 => Some(CalfRaiseExerciseName::WeightedSeatedCalfRaise),
            8 => Some(CalfRaiseExerciseName::SeatedDumbbellToeRaise),
            9 => Some(CalfRaiseExerciseName::SingleLegBentKneeCalfRaise),
            10 => Some(CalfRaiseExerciseName::WeightedSingleLegBentKneeCalfRaise),
            11 => Some(CalfRaiseExerciseName::SingleLegDeclinePushUp),
            12 => Some(CalfRaiseExerciseName::SingleLegDonkeyCalfRaise),
            13 => Some(CalfRaiseExerciseName::WeightedSingleLegDonkeyCalfRaise),
            14 => Some(CalfRaiseExerciseName::SingleLegHipRaiseWithKneeHold),
            15 => Some(CalfRaiseExerciseName::SingleLegStandingCalfRaise),
            16 => Some(CalfRaiseExerciseName::SingleLegStandingDumbbellCalfRaise),
            17 => Some(CalfRaiseExerciseName::StandingBarbellCalfRaise),
            18 => Some(CalfRaiseExerciseName::StandingCalfRaise),
            19 => Some(CalfRaiseExerciseName::WeightedStandingCalfRaise),
            20 => Some(CalfRaiseExerciseName::StandingDumbbellCalfRaise),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "3_way_calf_raise" => Some(CalfRaiseExerciseName::_3WayCalfRaise),
            "3_way_weighted_calf_raise" => Some(CalfRaiseExerciseName::_3WayWeightedCalfRaise),
            "3_way_single_leg_calf_raise" => Some(CalfRaiseExerciseName::_3WaySingleLegCalfRaise),
            "3_way_weighted_single_leg_calf_raise" => {
                Some(CalfRaiseExerciseName::_3WayWeightedSingleLegCalfRaise)
            }
            "donkey_calf_raise" => Some(CalfRaiseExerciseName::DonkeyCalfRaise),
            "weighted_donkey_calf_raise" => Some(CalfRaiseExerciseName::WeightedDonkeyCalfRaise),
            "seated_calf_raise" => Some(CalfRaiseExerciseName::SeatedCalfRaise),
            "weighted_seated_calf_raise" => Some(CalfRaiseExerciseName::WeightedSeatedCalfRaise),
            "seated_dumbbell_toe_raise" => Some(CalfRaiseExerciseName::SeatedDumbbellToeRaise),
            "single_leg_bent_knee_calf_raise" => {
                Some(CalfRaiseExerciseName::SingleLegBentKneeCalfRaise)
            }
            "weighted_single_leg_bent_knee_calf_raise" => {
                Some(CalfRaiseExerciseName::WeightedSingleLegBentKneeCalfRaise)
            }
            "single_leg_decline_push_up" => Some(CalfRaiseExerciseName::SingleLegDeclinePushUp),
            "single_leg_donkey_calf_raise" => Some(CalfRaiseExerciseName::SingleLegDonkeyCalfRaise),
            "weighted_single_leg_donkey_calf_raise" => {
                Some(CalfRaiseExerciseName::WeightedSingleLegDonkeyCalfRaise)
            }
            "single_leg_hip_raise_with_knee_hold" => {
                Some(CalfRaiseExerciseName::SingleLegHipRaiseWithKneeHold)
            }
            "single_leg_standing_calf_raise" => {
                Some(CalfRaiseExerciseName::SingleLegStandingCalfRaise)
            }
            "single_leg_standing_dumbbell_calf_raise" => {
                Some(CalfRaiseExerciseName::SingleLegStandingDumbbellCalfRaise)
            }
            "standing_barbell_calf_raise" => Some(CalfRaiseExerciseName::StandingBarbellCalfRaise),
            "standing_calf_raise" => Some(CalfRaiseExerciseName::StandingCalfRaise),
            "weighted_standing_calf_raise" => {
                Some(CalfRaiseExerciseName::WeightedStandingCalfRaise)
            }
            "standing_dumbbell_calf_raise" => {
                Some(CalfRaiseExerciseName::StandingDumbbellCalfRaise)
            }
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum CardioExerciseName {
    BobAndWeaveCircle = 0,
    WeightedBobAndWeaveCircle = 1,
    CardioCoreCrawl = 2,
    WeightedCardioCoreCrawl = 3,
    DoubleUnder = 4,
    WeightedDoubleUnder = 5,
    JumpRope = 6,
    WeightedJumpRope = 7,
    JumpRopeCrossover = 8,
    WeightedJumpRopeCrossover = 9,
    JumpRopeJog = 10,
    WeightedJumpRopeJog = 11,
    JumpingJacks = 12,
    WeightedJumpingJacks = 13,
    SkiMoguls = 14,
    WeightedSkiMoguls = 15,
    SplitJacks = 16,
    WeightedSplitJacks = 17,
    SquatJacks = 18,
    WeightedSquatJacks = 19,
    TripleUnder = 20,
    WeightedTripleUnder = 21,
    Elliptical = 22,
    Spinning = 23,
    PolePaddleForwardWheelchair = 24,
    PolePaddleBackwardWheelchair = 25,
    PoleHandcycleForwardWheelchair = 26,
    PoleHandcycleBackwardWheelchair = 27,
    PoleRainbowWheelchair = 28,
    DoublePunchForwardWheelchair = 29,
    DoublePunchDownWheelchair = 30,
    DoublePunchSidewaysWheelchair = 31,
    DoublePunchUpWheelchair = 32,
    SitSkiWheelchair = 33,
    SittingJacksWheelchair = 34,
    PunchForwardWheelchair = 35,
    PunchDownWheelchair = 36,
    PunchSidewaysWheelchair = 37,
    PunchUpWheelchair = 38,
    PunchBagWheelchair = 39,
    PoleDdFfUuWheelchair = 40,
    ButterflyArmsWheelchair = 41,
    Punch = 42,
}

impl CardioExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            CardioExerciseName::BobAndWeaveCircle => "bob_and_weave_circle",
            CardioExerciseName::WeightedBobAndWeaveCircle => "weighted_bob_and_weave_circle",
            CardioExerciseName::CardioCoreCrawl => "cardio_core_crawl",
            CardioExerciseName::WeightedCardioCoreCrawl => "weighted_cardio_core_crawl",
            CardioExerciseName::DoubleUnder => "double_under",
            CardioExerciseName::WeightedDoubleUnder => "weighted_double_under",
            CardioExerciseName::JumpRope => "jump_rope",
            CardioExerciseName::WeightedJumpRope => "weighted_jump_rope",
            CardioExerciseName::JumpRopeCrossover => "jump_rope_crossover",
            CardioExerciseName::WeightedJumpRopeCrossover => "weighted_jump_rope_crossover",
            CardioExerciseName::JumpRopeJog => "jump_rope_jog",
            CardioExerciseName::WeightedJumpRopeJog => "weighted_jump_rope_jog",
            CardioExerciseName::JumpingJacks => "jumping_jacks",
            CardioExerciseName::WeightedJumpingJacks => "weighted_jumping_jacks",
            CardioExerciseName::SkiMoguls => "ski_moguls",
            CardioExerciseName::WeightedSkiMoguls => "weighted_ski_moguls",
            CardioExerciseName::SplitJacks => "split_jacks",
            CardioExerciseName::WeightedSplitJacks => "weighted_split_jacks",
            CardioExerciseName::SquatJacks => "squat_jacks",
            CardioExerciseName::WeightedSquatJacks => "weighted_squat_jacks",
            CardioExerciseName::TripleUnder => "triple_under",
            CardioExerciseName::WeightedTripleUnder => "weighted_triple_under",
            CardioExerciseName::Elliptical => "elliptical",
            CardioExerciseName::Spinning => "spinning",
            CardioExerciseName::PolePaddleForwardWheelchair => "pole_paddle_forward_wheelchair",
            CardioExerciseName::PolePaddleBackwardWheelchair => "pole_paddle_backward_wheelchair",
            CardioExerciseName::PoleHandcycleForwardWheelchair => {
                "pole_handcycle_forward_wheelchair"
            }
            CardioExerciseName::PoleHandcycleBackwardWheelchair => {
                "pole_handcycle_backward_wheelchair"
            }
            CardioExerciseName::PoleRainbowWheelchair => "pole_rainbow_wheelchair",
            CardioExerciseName::DoublePunchForwardWheelchair => "double_punch_forward_wheelchair",
            CardioExerciseName::DoublePunchDownWheelchair => "double_punch_down_wheelchair",
            CardioExerciseName::DoublePunchSidewaysWheelchair => "double_punch_sideways_wheelchair",
            CardioExerciseName::DoublePunchUpWheelchair => "double_punch_up_wheelchair",
            CardioExerciseName::SitSkiWheelchair => "sit_ski_wheelchair",
            CardioExerciseName::SittingJacksWheelchair => "sitting_jacks_wheelchair",
            CardioExerciseName::PunchForwardWheelchair => "punch_forward_wheelchair",
            CardioExerciseName::PunchDownWheelchair => "punch_down_wheelchair",
            CardioExerciseName::PunchSidewaysWheelchair => "punch_sideways_wheelchair",
            CardioExerciseName::PunchUpWheelchair => "punch_up_wheelchair",
            CardioExerciseName::PunchBagWheelchair => "punch_bag_wheelchair",
            CardioExerciseName::PoleDdFfUuWheelchair => "pole_dd_ff_uu_wheelchair",
            CardioExerciseName::ButterflyArmsWheelchair => "butterfly_arms_wheelchair",
            CardioExerciseName::Punch => "punch",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(CardioExerciseName::BobAndWeaveCircle),
            1 => Some(CardioExerciseName::WeightedBobAndWeaveCircle),
            2 => Some(CardioExerciseName::CardioCoreCrawl),
            3 => Some(CardioExerciseName::WeightedCardioCoreCrawl),
            4 => Some(CardioExerciseName::DoubleUnder),
            5 => Some(CardioExerciseName::WeightedDoubleUnder),
            6 => Some(CardioExerciseName::JumpRope),
            7 => Some(CardioExerciseName::WeightedJumpRope),
            8 => Some(CardioExerciseName::JumpRopeCrossover),
            9 => Some(CardioExerciseName::WeightedJumpRopeCrossover),
            10 => Some(CardioExerciseName::JumpRopeJog),
            11 => Some(CardioExerciseName::WeightedJumpRopeJog),
            12 => Some(CardioExerciseName::JumpingJacks),
            13 => Some(CardioExerciseName::WeightedJumpingJacks),
            14 => Some(CardioExerciseName::SkiMoguls),
            15 => Some(CardioExerciseName::WeightedSkiMoguls),
            16 => Some(CardioExerciseName::SplitJacks),
            17 => Some(CardioExerciseName::WeightedSplitJacks),
            18 => Some(CardioExerciseName::SquatJacks),
            19 => Some(CardioExerciseName::WeightedSquatJacks),
            20 => Some(CardioExerciseName::TripleUnder),
            21 => Some(CardioExerciseName::WeightedTripleUnder),
            22 => Some(CardioExerciseName::Elliptical),
            23 => Some(CardioExerciseName::Spinning),
            24 => Some(CardioExerciseName::PolePaddleForwardWheelchair),
            25 => Some(CardioExerciseName::PolePaddleBackwardWheelchair),
            26 => Some(CardioExerciseName::PoleHandcycleForwardWheelchair),
            27 => Some(CardioExerciseName::PoleHandcycleBackwardWheelchair),
            28 => Some(CardioExerciseName::PoleRainbowWheelchair),
            29 => Some(CardioExerciseName::DoublePunchForwardWheelchair),
            30 => Some(CardioExerciseName::DoublePunchDownWheelchair),
            31 => Some(CardioExerciseName::DoublePunchSidewaysWheelchair),
            32 => Some(CardioExerciseName::DoublePunchUpWheelchair),
            33 => Some(CardioExerciseName::SitSkiWheelchair),
            34 => Some(CardioExerciseName::SittingJacksWheelchair),
            35 => Some(CardioExerciseName::PunchForwardWheelchair),
            36 => Some(CardioExerciseName::PunchDownWheelchair),
            37 => Some(CardioExerciseName::PunchSidewaysWheelchair),
            38 => Some(CardioExerciseName::PunchUpWheelchair),
            39 => Some(CardioExerciseName::PunchBagWheelchair),
            40 => Some(CardioExerciseName::PoleDdFfUuWheelchair),
            41 => Some(CardioExerciseName::ButterflyArmsWheelchair),
            42 => Some(CardioExerciseName::Punch),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "bob_and_weave_circle" => Some(CardioExerciseName::BobAndWeaveCircle),
            "weighted_bob_and_weave_circle" => Some(CardioExerciseName::WeightedBobAndWeaveCircle),
            "cardio_core_crawl" => Some(CardioExerciseName::CardioCoreCrawl),
            "weighted_cardio_core_crawl" => Some(CardioExerciseName::WeightedCardioCoreCrawl),
            "double_under" => Some(CardioExerciseName::DoubleUnder),
            "weighted_double_under" => Some(CardioExerciseName::WeightedDoubleUnder),
            "jump_rope" => Some(CardioExerciseName::JumpRope),
            "weighted_jump_rope" => Some(CardioExerciseName::WeightedJumpRope),
            "jump_rope_crossover" => Some(CardioExerciseName::JumpRopeCrossover),
            "weighted_jump_rope_crossover" => Some(CardioExerciseName::WeightedJumpRopeCrossover),
            "jump_rope_jog" => Some(CardioExerciseName::JumpRopeJog),
            "weighted_jump_rope_jog" => Some(CardioExerciseName::WeightedJumpRopeJog),
            "jumping_jacks" => Some(CardioExerciseName::JumpingJacks),
            "weighted_jumping_jacks" => Some(CardioExerciseName::WeightedJumpingJacks),
            "ski_moguls" => Some(CardioExerciseName::SkiMoguls),
            "weighted_ski_moguls" => Some(CardioExerciseName::WeightedSkiMoguls),
            "split_jacks" => Some(CardioExerciseName::SplitJacks),
            "weighted_split_jacks" => Some(CardioExerciseName::WeightedSplitJacks),
            "squat_jacks" => Some(CardioExerciseName::SquatJacks),
            "weighted_squat_jacks" => Some(CardioExerciseName::WeightedSquatJacks),
            "triple_under" => Some(CardioExerciseName::TripleUnder),
            "weighted_triple_under" => Some(CardioExerciseName::WeightedTripleUnder),
            "elliptical" => Some(CardioExerciseName::Elliptical),
            "spinning" => Some(CardioExerciseName::Spinning),
            "pole_paddle_forward_wheelchair" => {
                Some(CardioExerciseName::PolePaddleForwardWheelchair)
            }
            "pole_paddle_backward_wheelchair" => {
                Some(CardioExerciseName::PolePaddleBackwardWheelchair)
            }
            "pole_handcycle_forward_wheelchair" => {
                Some(CardioExerciseName::PoleHandcycleForwardWheelchair)
            }
            "pole_handcycle_backward_wheelchair" => {
                Some(CardioExerciseName::PoleHandcycleBackwardWheelchair)
            }
            "pole_rainbow_wheelchair" => Some(CardioExerciseName::PoleRainbowWheelchair),
            "double_punch_forward_wheelchair" => {
                Some(CardioExerciseName::DoublePunchForwardWheelchair)
            }
            "double_punch_down_wheelchair" => Some(CardioExerciseName::DoublePunchDownWheelchair),
            "double_punch_sideways_wheelchair" => {
                Some(CardioExerciseName::DoublePunchSidewaysWheelchair)
            }
            "double_punch_up_wheelchair" => Some(CardioExerciseName::DoublePunchUpWheelchair),
            "sit_ski_wheelchair" => Some(CardioExerciseName::SitSkiWheelchair),
            "sitting_jacks_wheelchair" => Some(CardioExerciseName::SittingJacksWheelchair),
            "punch_forward_wheelchair" => Some(CardioExerciseName::PunchForwardWheelchair),
            "punch_down_wheelchair" => Some(CardioExerciseName::PunchDownWheelchair),
            "punch_sideways_wheelchair" => Some(CardioExerciseName::PunchSidewaysWheelchair),
            "punch_up_wheelchair" => Some(CardioExerciseName::PunchUpWheelchair),
            "punch_bag_wheelchair" => Some(CardioExerciseName::PunchBagWheelchair),
            "pole_dd_ff_uu_wheelchair" => Some(CardioExerciseName::PoleDdFfUuWheelchair),
            "butterfly_arms_wheelchair" => Some(CardioExerciseName::ButterflyArmsWheelchair),
            "punch" => Some(CardioExerciseName::Punch),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum CarryExerciseName {
    BarHolds = 0,
    FarmersWalk = 1,
    FarmersWalkOnToes = 2,
    HexDumbbellHold = 3,
    OverheadCarry = 4,
    DumbbellWaiterCarry = 5,
    FarmersCarryWalkLunge = 6,
    FarmersCarry = 7,
    FarmersCarryOnToes = 8,
}

impl CarryExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            CarryExerciseName::BarHolds => "bar_holds",
            CarryExerciseName::FarmersWalk => "farmers_walk",
            CarryExerciseName::FarmersWalkOnToes => "farmers_walk_on_toes",
            CarryExerciseName::HexDumbbellHold => "hex_dumbbell_hold",
            CarryExerciseName::OverheadCarry => "overhead_carry",
            CarryExerciseName::DumbbellWaiterCarry => "dumbbell_waiter_carry",
            CarryExerciseName::FarmersCarryWalkLunge => "farmers_carry_walk_lunge",
            CarryExerciseName::FarmersCarry => "farmers_carry",
            CarryExerciseName::FarmersCarryOnToes => "farmers_carry_on_toes",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(CarryExerciseName::BarHolds),
            1 => Some(CarryExerciseName::FarmersWalk),
            2 => Some(CarryExerciseName::FarmersWalkOnToes),
            3 => Some(CarryExerciseName::HexDumbbellHold),
            4 => Some(CarryExerciseName::OverheadCarry),
            5 => Some(CarryExerciseName::DumbbellWaiterCarry),
            6 => Some(CarryExerciseName::FarmersCarryWalkLunge),
            7 => Some(CarryExerciseName::FarmersCarry),
            8 => Some(CarryExerciseName::FarmersCarryOnToes),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "bar_holds" => Some(CarryExerciseName::BarHolds),
            "farmers_walk" => Some(CarryExerciseName::FarmersWalk),
            "farmers_walk_on_toes" => Some(CarryExerciseName::FarmersWalkOnToes),
            "hex_dumbbell_hold" => Some(CarryExerciseName::HexDumbbellHold),
            "overhead_carry" => Some(CarryExerciseName::OverheadCarry),
            "dumbbell_waiter_carry" => Some(CarryExerciseName::DumbbellWaiterCarry),
            "farmers_carry_walk_lunge" => Some(CarryExerciseName::FarmersCarryWalkLunge),
            "farmers_carry" => Some(CarryExerciseName::FarmersCarry),
            "farmers_carry_on_toes" => Some(CarryExerciseName::FarmersCarryOnToes),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum ChopExerciseName {
    CablePullThrough = 0,
    CableRotationalLift = 1,
    CableWoodchop = 2,
    CrossChopToKnee = 3,
    WeightedCrossChopToKnee = 4,
    DumbbellChop = 5,
    HalfKneelingRotation = 6,
    WeightedHalfKneelingRotation = 7,
    HalfKneelingRotationalChop = 8,
    HalfKneelingRotationalReverseChop = 9,
    HalfKneelingStabilityChop = 10,
    HalfKneelingStabilityReverseChop = 11,
    KneelingRotationalChop = 12,
    KneelingRotationalReverseChop = 13,
    KneelingStabilityChop = 14,
    KneelingWoodchopper = 15,
    MedicineBallWoodChops = 16,
    PowerSquatChops = 17,
    WeightedPowerSquatChops = 18,
    StandingRotationalChop = 19,
    StandingSplitRotationalChop = 20,
    StandingSplitRotationalReverseChop = 21,
    StandingStabilityReverseChop = 22,
}

impl ChopExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            ChopExerciseName::CablePullThrough => "cable_pull_through",
            ChopExerciseName::CableRotationalLift => "cable_rotational_lift",
            ChopExerciseName::CableWoodchop => "cable_woodchop",
            ChopExerciseName::CrossChopToKnee => "cross_chop_to_knee",
            ChopExerciseName::WeightedCrossChopToKnee => "weighted_cross_chop_to_knee",
            ChopExerciseName::DumbbellChop => "dumbbell_chop",
            ChopExerciseName::HalfKneelingRotation => "half_kneeling_rotation",
            ChopExerciseName::WeightedHalfKneelingRotation => "weighted_half_kneeling_rotation",
            ChopExerciseName::HalfKneelingRotationalChop => "half_kneeling_rotational_chop",
            ChopExerciseName::HalfKneelingRotationalReverseChop => {
                "half_kneeling_rotational_reverse_chop"
            }
            ChopExerciseName::HalfKneelingStabilityChop => "half_kneeling_stability_chop",
            ChopExerciseName::HalfKneelingStabilityReverseChop => {
                "half_kneeling_stability_reverse_chop"
            }
            ChopExerciseName::KneelingRotationalChop => "kneeling_rotational_chop",
            ChopExerciseName::KneelingRotationalReverseChop => "kneeling_rotational_reverse_chop",
            ChopExerciseName::KneelingStabilityChop => "kneeling_stability_chop",
            ChopExerciseName::KneelingWoodchopper => "kneeling_woodchopper",
            ChopExerciseName::MedicineBallWoodChops => "medicine_ball_wood_chops",
            ChopExerciseName::PowerSquatChops => "power_squat_chops",
            ChopExerciseName::WeightedPowerSquatChops => "weighted_power_squat_chops",
            ChopExerciseName::StandingRotationalChop => "standing_rotational_chop",
            ChopExerciseName::StandingSplitRotationalChop => "standing_split_rotational_chop",
            ChopExerciseName::StandingSplitRotationalReverseChop => {
                "standing_split_rotational_reverse_chop"
            }
            ChopExerciseName::StandingStabilityReverseChop => "standing_stability_reverse_chop",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(ChopExerciseName::CablePullThrough),
            1 => Some(ChopExerciseName::CableRotationalLift),
            2 => Some(ChopExerciseName::CableWoodchop),
            3 => Some(ChopExerciseName::CrossChopToKnee),
            4 => Some(ChopExerciseName::WeightedCrossChopToKnee),
            5 => Some(ChopExerciseName::DumbbellChop),
            6 => Some(ChopExerciseName::HalfKneelingRotation),
            7 => Some(ChopExerciseName::WeightedHalfKneelingRotation),
            8 => Some(ChopExerciseName::HalfKneelingRotationalChop),
            9 => Some(ChopExerciseName::HalfKneelingRotationalReverseChop),
            10 => Some(ChopExerciseName::HalfKneelingStabilityChop),
            11 => Some(ChopExerciseName::HalfKneelingStabilityReverseChop),
            12 => Some(ChopExerciseName::KneelingRotationalChop),
            13 => Some(ChopExerciseName::KneelingRotationalReverseChop),
            14 => Some(ChopExerciseName::KneelingStabilityChop),
            15 => Some(ChopExerciseName::KneelingWoodchopper),
            16 => Some(ChopExerciseName::MedicineBallWoodChops),
            17 => Some(ChopExerciseName::PowerSquatChops),
            18 => Some(ChopExerciseName::WeightedPowerSquatChops),
            19 => Some(ChopExerciseName::StandingRotationalChop),
            20 => Some(ChopExerciseName::StandingSplitRotationalChop),
            21 => Some(ChopExerciseName::StandingSplitRotationalReverseChop),
            22 => Some(ChopExerciseName::StandingStabilityReverseChop),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "cable_pull_through" => Some(ChopExerciseName::CablePullThrough),
            "cable_rotational_lift" => Some(ChopExerciseName::CableRotationalLift),
            "cable_woodchop" => Some(ChopExerciseName::CableWoodchop),
            "cross_chop_to_knee" => Some(ChopExerciseName::CrossChopToKnee),
            "weighted_cross_chop_to_knee" => Some(ChopExerciseName::WeightedCrossChopToKnee),
            "dumbbell_chop" => Some(ChopExerciseName::DumbbellChop),
            "half_kneeling_rotation" => Some(ChopExerciseName::HalfKneelingRotation),
            "weighted_half_kneeling_rotation" => {
                Some(ChopExerciseName::WeightedHalfKneelingRotation)
            }
            "half_kneeling_rotational_chop" => Some(ChopExerciseName::HalfKneelingRotationalChop),
            "half_kneeling_rotational_reverse_chop" => {
                Some(ChopExerciseName::HalfKneelingRotationalReverseChop)
            }
            "half_kneeling_stability_chop" => Some(ChopExerciseName::HalfKneelingStabilityChop),
            "half_kneeling_stability_reverse_chop" => {
                Some(ChopExerciseName::HalfKneelingStabilityReverseChop)
            }
            "kneeling_rotational_chop" => Some(ChopExerciseName::KneelingRotationalChop),
            "kneeling_rotational_reverse_chop" => {
                Some(ChopExerciseName::KneelingRotationalReverseChop)
            }
            "kneeling_stability_chop" => Some(ChopExerciseName::KneelingStabilityChop),
            "kneeling_woodchopper" => Some(ChopExerciseName::KneelingWoodchopper),
            "medicine_ball_wood_chops" => Some(ChopExerciseName::MedicineBallWoodChops),
            "power_squat_chops" => Some(ChopExerciseName::PowerSquatChops),
            "weighted_power_squat_chops" => Some(ChopExerciseName::WeightedPowerSquatChops),
            "standing_rotational_chop" => Some(ChopExerciseName::StandingRotationalChop),
            "standing_split_rotational_chop" => Some(ChopExerciseName::StandingSplitRotationalChop),
            "standing_split_rotational_reverse_chop" => {
                Some(ChopExerciseName::StandingSplitRotationalReverseChop)
            }
            "standing_stability_reverse_chop" => {
                Some(ChopExerciseName::StandingStabilityReverseChop)
            }
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum CoreExerciseName {
    AbsJabs = 0,
    WeightedAbsJabs = 1,
    AlternatingPlateReach = 2,
    BarbellRollout = 3,
    WeightedBarbellRollout = 4,
    BodyBarObliqueTwist = 5,
    CableCorePress = 6,
    CableSideBend = 7,
    SideBend = 8,
    WeightedSideBend = 9,
    CrescentCircle = 10,
    WeightedCrescentCircle = 11,
    CyclingRussianTwist = 12,
    WeightedCyclingRussianTwist = 13,
    ElevatedFeetRussianTwist = 14,
    WeightedElevatedFeetRussianTwist = 15,
    HalfTurkishGetUp = 16,
    KettlebellWindmill = 17,
    KneelingAbWheel = 18,
    WeightedKneelingAbWheel = 19,
    ModifiedFrontLever = 20,
    OpenKneeTucks = 21,
    WeightedOpenKneeTucks = 22,
    SideAbsLegLift = 23,
    WeightedSideAbsLegLift = 24,
    SwissBallJackknife = 25,
    WeightedSwissBallJackknife = 26,
    SwissBallPike = 27,
    WeightedSwissBallPike = 28,
    SwissBallRollout = 29,
    WeightedSwissBallRollout = 30,
    TriangleHipPress = 31,
    WeightedTriangleHipPress = 32,
    TrxSuspendedJackknife = 33,
    WeightedTrxSuspendedJackknife = 34,
    UBoat = 35,
    WeightedUBoat = 36,
    WindmillSwitches = 37,
    WeightedWindmillSwitches = 38,
    AlternatingSlideOut = 39,
    WeightedAlternatingSlideOut = 40,
    GhdBackExtensions = 41,
    WeightedGhdBackExtensions = 42,
    OverheadWalk = 43,
    Inchworm = 44,
    WeightedModifiedFrontLever = 45,
    RussianTwist = 46,
    AbdominalLegRotations = 47,
    ArmAndLegExtensionOnKnees = 48,
    Bicycle = 49,
    BicepCurlWithLegExtension = 50,
    CatCow = 51,
    Corkscrew = 52,
    CrissCross = 53,
    CrissCrossWithBall = 54,
    DoubleLegStretch = 55,
    KneeFolds = 56,
    LowerLift = 57,
    NeckPull = 58,
    PelvicClocks = 59,
    RollOver = 60,
    RollUp = 61,
    Rolling = 62,
    Rowing1 = 63,
    Rowing2 = 64,
    Scissors = 65,
    SingleLegCircles = 66,
    SingleLegStretch = 67,
    SnakeTwist1And2 = 68,
    Swan = 69,
    Swimming = 70,
    Teaser = 71,
    TheHundred = 72,
    BicepCurlWithLegExtensionWithWeights = 73,
    HangingLSit = 75,
    LowerLiftWithWeights = 77,
    RingLSit = 79,
    Rowing1WithWeights = 80,
    Rowing2WithWeights = 81,
    ScissorsWithWeights = 82,
    SingleLegStretchWithWeights = 83,
    ToesToElbows = 84,
    WeightedCrissCross = 85,
    WeightedDoubleLegStretch = 86,
    WeightedTheHundred = 87,
    LSit = 88,
    TurkishGetUp = 89,
    WeightedRingLSit = 90,
    WeightedHangingLSit = 91,
    WeightedLSit = 92,
    SideBendLowWheelchair = 93,
    SideBendMidWheelchair = 94,
    SideBendHighWheelchair = 95,
    SeatedSideBend = 96,
}

impl CoreExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            CoreExerciseName::AbsJabs => "abs_jabs",
            CoreExerciseName::WeightedAbsJabs => "weighted_abs_jabs",
            CoreExerciseName::AlternatingPlateReach => "alternating_plate_reach",
            CoreExerciseName::BarbellRollout => "barbell_rollout",
            CoreExerciseName::WeightedBarbellRollout => "weighted_barbell_rollout",
            CoreExerciseName::BodyBarObliqueTwist => "body_bar_oblique_twist",
            CoreExerciseName::CableCorePress => "cable_core_press",
            CoreExerciseName::CableSideBend => "cable_side_bend",
            CoreExerciseName::SideBend => "side_bend",
            CoreExerciseName::WeightedSideBend => "weighted_side_bend",
            CoreExerciseName::CrescentCircle => "crescent_circle",
            CoreExerciseName::WeightedCrescentCircle => "weighted_crescent_circle",
            CoreExerciseName::CyclingRussianTwist => "cycling_russian_twist",
            CoreExerciseName::WeightedCyclingRussianTwist => "weighted_cycling_russian_twist",
            CoreExerciseName::ElevatedFeetRussianTwist => "elevated_feet_russian_twist",
            CoreExerciseName::WeightedElevatedFeetRussianTwist => {
                "weighted_elevated_feet_russian_twist"
            }
            CoreExerciseName::HalfTurkishGetUp => "half_turkish_get_up",
            CoreExerciseName::KettlebellWindmill => "kettlebell_windmill",
            CoreExerciseName::KneelingAbWheel => "kneeling_ab_wheel",
            CoreExerciseName::WeightedKneelingAbWheel => "weighted_kneeling_ab_wheel",
            CoreExerciseName::ModifiedFrontLever => "modified_front_lever",
            CoreExerciseName::OpenKneeTucks => "open_knee_tucks",
            CoreExerciseName::WeightedOpenKneeTucks => "weighted_open_knee_tucks",
            CoreExerciseName::SideAbsLegLift => "side_abs_leg_lift",
            CoreExerciseName::WeightedSideAbsLegLift => "weighted_side_abs_leg_lift",
            CoreExerciseName::SwissBallJackknife => "swiss_ball_jackknife",
            CoreExerciseName::WeightedSwissBallJackknife => "weighted_swiss_ball_jackknife",
            CoreExerciseName::SwissBallPike => "swiss_ball_pike",
            CoreExerciseName::WeightedSwissBallPike => "weighted_swiss_ball_pike",
            CoreExerciseName::SwissBallRollout => "swiss_ball_rollout",
            CoreExerciseName::WeightedSwissBallRollout => "weighted_swiss_ball_rollout",
            CoreExerciseName::TriangleHipPress => "triangle_hip_press",
            CoreExerciseName::WeightedTriangleHipPress => "weighted_triangle_hip_press",
            CoreExerciseName::TrxSuspendedJackknife => "trx_suspended_jackknife",
            CoreExerciseName::WeightedTrxSuspendedJackknife => "weighted_trx_suspended_jackknife",
            CoreExerciseName::UBoat => "u_boat",
            CoreExerciseName::WeightedUBoat => "weighted_u_boat",
            CoreExerciseName::WindmillSwitches => "windmill_switches",
            CoreExerciseName::WeightedWindmillSwitches => "weighted_windmill_switches",
            CoreExerciseName::AlternatingSlideOut => "alternating_slide_out",
            CoreExerciseName::WeightedAlternatingSlideOut => "weighted_alternating_slide_out",
            CoreExerciseName::GhdBackExtensions => "ghd_back_extensions",
            CoreExerciseName::WeightedGhdBackExtensions => "weighted_ghd_back_extensions",
            CoreExerciseName::OverheadWalk => "overhead_walk",
            CoreExerciseName::Inchworm => "inchworm",
            CoreExerciseName::WeightedModifiedFrontLever => "weighted_modified_front_lever",
            CoreExerciseName::RussianTwist => "russian_twist",
            CoreExerciseName::AbdominalLegRotations => "abdominal_leg_rotations",
            CoreExerciseName::ArmAndLegExtensionOnKnees => "arm_and_leg_extension_on_knees",
            CoreExerciseName::Bicycle => "bicycle",
            CoreExerciseName::BicepCurlWithLegExtension => "bicep_curl_with_leg_extension",
            CoreExerciseName::CatCow => "cat_cow",
            CoreExerciseName::Corkscrew => "corkscrew",
            CoreExerciseName::CrissCross => "criss_cross",
            CoreExerciseName::CrissCrossWithBall => "criss_cross_with_ball",
            CoreExerciseName::DoubleLegStretch => "double_leg_stretch",
            CoreExerciseName::KneeFolds => "knee_folds",
            CoreExerciseName::LowerLift => "lower_lift",
            CoreExerciseName::NeckPull => "neck_pull",
            CoreExerciseName::PelvicClocks => "pelvic_clocks",
            CoreExerciseName::RollOver => "roll_over",
            CoreExerciseName::RollUp => "roll_up",
            CoreExerciseName::Rolling => "rolling",
            CoreExerciseName::Rowing1 => "rowing_1",
            CoreExerciseName::Rowing2 => "rowing_2",
            CoreExerciseName::Scissors => "scissors",
            CoreExerciseName::SingleLegCircles => "single_leg_circles",
            CoreExerciseName::SingleLegStretch => "single_leg_stretch",
            CoreExerciseName::SnakeTwist1And2 => "snake_twist_1_and_2",
            CoreExerciseName::Swan => "swan",
            CoreExerciseName::Swimming => "swimming",
            CoreExerciseName::Teaser => "teaser",
            CoreExerciseName::TheHundred => "the_hundred",
            CoreExerciseName::BicepCurlWithLegExtensionWithWeights => {
                "bicep_curl_with_leg_extension_with_weights"
            }
            CoreExerciseName::HangingLSit => "hanging_l_sit",
            CoreExerciseName::LowerLiftWithWeights => "lower_lift_with_weights",
            CoreExerciseName::RingLSit => "ring_l_sit",
            CoreExerciseName::Rowing1WithWeights => "rowing_1_with_weights",
            CoreExerciseName::Rowing2WithWeights => "rowing_2_with_weights",
            CoreExerciseName::ScissorsWithWeights => "scissors_with_weights",
            CoreExerciseName::SingleLegStretchWithWeights => "single_leg_stretch_with_weights",
            CoreExerciseName::ToesToElbows => "toes_to_elbows",
            CoreExerciseName::WeightedCrissCross => "weighted_criss_cross",
            CoreExerciseName::WeightedDoubleLegStretch => "weighted_double_leg_stretch",
            CoreExerciseName::WeightedTheHundred => "weighted_the_hundred",
            CoreExerciseName::LSit => "l_sit",
            CoreExerciseName::TurkishGetUp => "turkish_get_up",
            CoreExerciseName::WeightedRingLSit => "weighted_ring_l_sit",
            CoreExerciseName::WeightedHangingLSit => "weighted_hanging_l_sit",
            CoreExerciseName::WeightedLSit => "weighted_l_sit",
            CoreExerciseName::SideBendLowWheelchair => "side_bend_low_wheelchair",
            CoreExerciseName::SideBendMidWheelchair => "side_bend_mid_wheelchair",
            CoreExerciseName::SideBendHighWheelchair => "side_bend_high_wheelchair",
            CoreExerciseName::SeatedSideBend => "seated_side_bend",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(CoreExerciseName::AbsJabs),
            1 => Some(CoreExerciseName::WeightedAbsJabs),
            2 => Some(CoreExerciseName::AlternatingPlateReach),
            3 => Some(CoreExerciseName::BarbellRollout),
            4 => Some(CoreExerciseName::WeightedBarbellRollout),
            5 => Some(CoreExerciseName::BodyBarObliqueTwist),
            6 => Some(CoreExerciseName::CableCorePress),
            7 => Some(CoreExerciseName::CableSideBend),
            8 => Some(CoreExerciseName::SideBend),
            9 => Some(CoreExerciseName::WeightedSideBend),
            10 => Some(CoreExerciseName::CrescentCircle),
            11 => Some(CoreExerciseName::WeightedCrescentCircle),
            12 => Some(CoreExerciseName::CyclingRussianTwist),
            13 => Some(CoreExerciseName::WeightedCyclingRussianTwist),
            14 => Some(CoreExerciseName::ElevatedFeetRussianTwist),
            15 => Some(CoreExerciseName::WeightedElevatedFeetRussianTwist),
            16 => Some(CoreExerciseName::HalfTurkishGetUp),
            17 => Some(CoreExerciseName::KettlebellWindmill),
            18 => Some(CoreExerciseName::KneelingAbWheel),
            19 => Some(CoreExerciseName::WeightedKneelingAbWheel),
            20 => Some(CoreExerciseName::ModifiedFrontLever),
            21 => Some(CoreExerciseName::OpenKneeTucks),
            22 => Some(CoreExerciseName::WeightedOpenKneeTucks),
            23 => Some(CoreExerciseName::SideAbsLegLift),
            24 => Some(CoreExerciseName::WeightedSideAbsLegLift),
            25 => Some(CoreExerciseName::SwissBallJackknife),
            26 => Some(CoreExerciseName::WeightedSwissBallJackknife),
            27 => Some(CoreExerciseName::SwissBallPike),
            28 => Some(CoreExerciseName::WeightedSwissBallPike),
            29 => Some(CoreExerciseName::SwissBallRollout),
            30 => Some(CoreExerciseName::WeightedSwissBallRollout),
            31 => Some(CoreExerciseName::TriangleHipPress),
            32 => Some(CoreExerciseName::WeightedTriangleHipPress),
            33 => Some(CoreExerciseName::TrxSuspendedJackknife),
            34 => Some(CoreExerciseName::WeightedTrxSuspendedJackknife),
            35 => Some(CoreExerciseName::UBoat),
            36 => Some(CoreExerciseName::WeightedUBoat),
            37 => Some(CoreExerciseName::WindmillSwitches),
            38 => Some(CoreExerciseName::WeightedWindmillSwitches),
            39 => Some(CoreExerciseName::AlternatingSlideOut),
            40 => Some(CoreExerciseName::WeightedAlternatingSlideOut),
            41 => Some(CoreExerciseName::GhdBackExtensions),
            42 => Some(CoreExerciseName::WeightedGhdBackExtensions),
            43 => Some(CoreExerciseName::OverheadWalk),
            44 => Some(CoreExerciseName::Inchworm),
            45 => Some(CoreExerciseName::WeightedModifiedFrontLever),
            46 => Some(CoreExerciseName::RussianTwist),
            47 => Some(CoreExerciseName::AbdominalLegRotations),
            48 => Some(CoreExerciseName::ArmAndLegExtensionOnKnees),
            49 => Some(CoreExerciseName::Bicycle),
            50 => Some(CoreExerciseName::BicepCurlWithLegExtension),
            51 => Some(CoreExerciseName::CatCow),
            52 => Some(CoreExerciseName::Corkscrew),
            53 => Some(CoreExerciseName::CrissCross),
            54 => Some(CoreExerciseName::CrissCrossWithBall),
            55 => Some(CoreExerciseName::DoubleLegStretch),
            56 => Some(CoreExerciseName::KneeFolds),
            57 => Some(CoreExerciseName::LowerLift),
            58 => Some(CoreExerciseName::NeckPull),
            59 => Some(CoreExerciseName::PelvicClocks),
            60 => Some(CoreExerciseName::RollOver),
            61 => Some(CoreExerciseName::RollUp),
            62 => Some(CoreExerciseName::Rolling),
            63 => Some(CoreExerciseName::Rowing1),
            64 => Some(CoreExerciseName::Rowing2),
            65 => Some(CoreExerciseName::Scissors),
            66 => Some(CoreExerciseName::SingleLegCircles),
            67 => Some(CoreExerciseName::SingleLegStretch),
            68 => Some(CoreExerciseName::SnakeTwist1And2),
            69 => Some(CoreExerciseName::Swan),
            70 => Some(CoreExerciseName::Swimming),
            71 => Some(CoreExerciseName::Teaser),
            72 => Some(CoreExerciseName::TheHundred),
            73 => Some(CoreExerciseName::BicepCurlWithLegExtensionWithWeights),
            75 => Some(CoreExerciseName::HangingLSit),
            77 => Some(CoreExerciseName::LowerLiftWithWeights),
            79 => Some(CoreExerciseName::RingLSit),
            80 => Some(CoreExerciseName::Rowing1WithWeights),
            81 => Some(CoreExerciseName::Rowing2WithWeights),
            82 => Some(CoreExerciseName::ScissorsWithWeights),
            83 => Some(CoreExerciseName::SingleLegStretchWithWeights),
            84 => Some(CoreExerciseName::ToesToElbows),
            85 => Some(CoreExerciseName::WeightedCrissCross),
            86 => Some(CoreExerciseName::WeightedDoubleLegStretch),
            87 => Some(CoreExerciseName::WeightedTheHundred),
            88 => Some(CoreExerciseName::LSit),
            89 => Some(CoreExerciseName::TurkishGetUp),
            90 => Some(CoreExerciseName::WeightedRingLSit),
            91 => Some(CoreExerciseName::WeightedHangingLSit),
            92 => Some(CoreExerciseName::WeightedLSit),
            93 => Some(CoreExerciseName::SideBendLowWheelchair),
            94 => Some(CoreExerciseName::SideBendMidWheelchair),
            95 => Some(CoreExerciseName::SideBendHighWheelchair),
            96 => Some(CoreExerciseName::SeatedSideBend),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "abs_jabs" => Some(CoreExerciseName::AbsJabs),
            "weighted_abs_jabs" => Some(CoreExerciseName::WeightedAbsJabs),
            "alternating_plate_reach" => Some(CoreExerciseName::AlternatingPlateReach),
            "barbell_rollout" => Some(CoreExerciseName::BarbellRollout),
            "weighted_barbell_rollout" => Some(CoreExerciseName::WeightedBarbellRollout),
            "body_bar_oblique_twist" => Some(CoreExerciseName::BodyBarObliqueTwist),
            "cable_core_press" => Some(CoreExerciseName::CableCorePress),
            "cable_side_bend" => Some(CoreExerciseName::CableSideBend),
            "side_bend" => Some(CoreExerciseName::SideBend),
            "weighted_side_bend" => Some(CoreExerciseName::WeightedSideBend),
            "crescent_circle" => Some(CoreExerciseName::CrescentCircle),
            "weighted_crescent_circle" => Some(CoreExerciseName::WeightedCrescentCircle),
            "cycling_russian_twist" => Some(CoreExerciseName::CyclingRussianTwist),
            "weighted_cycling_russian_twist" => Some(CoreExerciseName::WeightedCyclingRussianTwist),
            "elevated_feet_russian_twist" => Some(CoreExerciseName::ElevatedFeetRussianTwist),
            "weighted_elevated_feet_russian_twist" => {
                Some(CoreExerciseName::WeightedElevatedFeetRussianTwist)
            }
            "half_turkish_get_up" => Some(CoreExerciseName::HalfTurkishGetUp),
            "kettlebell_windmill" => Some(CoreExerciseName::KettlebellWindmill),
            "kneeling_ab_wheel" => Some(CoreExerciseName::KneelingAbWheel),
            "weighted_kneeling_ab_wheel" => Some(CoreExerciseName::WeightedKneelingAbWheel),
            "modified_front_lever" => Some(CoreExerciseName::ModifiedFrontLever),
            "open_knee_tucks" => Some(CoreExerciseName::OpenKneeTucks),
            "weighted_open_knee_tucks" => Some(CoreExerciseName::WeightedOpenKneeTucks),
            "side_abs_leg_lift" => Some(CoreExerciseName::SideAbsLegLift),
            "weighted_side_abs_leg_lift" => Some(CoreExerciseName::WeightedSideAbsLegLift),
            "swiss_ball_jackknife" => Some(CoreExerciseName::SwissBallJackknife),
            "weighted_swiss_ball_jackknife" => Some(CoreExerciseName::WeightedSwissBallJackknife),
            "swiss_ball_pike" => Some(CoreExerciseName::SwissBallPike),
            "weighted_swiss_ball_pike" => Some(CoreExerciseName::WeightedSwissBallPike),
            "swiss_ball_rollout" => Some(CoreExerciseName::SwissBallRollout),
            "weighted_swiss_ball_rollout" => Some(CoreExerciseName::WeightedSwissBallRollout),
            "triangle_hip_press" => Some(CoreExerciseName::TriangleHipPress),
            "weighted_triangle_hip_press" => Some(CoreExerciseName::WeightedTriangleHipPress),
            "trx_suspended_jackknife" => Some(CoreExerciseName::TrxSuspendedJackknife),
            "weighted_trx_suspended_jackknife" => {
                Some(CoreExerciseName::WeightedTrxSuspendedJackknife)
            }
            "u_boat" => Some(CoreExerciseName::UBoat),
            "weighted_u_boat" => Some(CoreExerciseName::WeightedUBoat),
            "windmill_switches" => Some(CoreExerciseName::WindmillSwitches),
            "weighted_windmill_switches" => Some(CoreExerciseName::WeightedWindmillSwitches),
            "alternating_slide_out" => Some(CoreExerciseName::AlternatingSlideOut),
            "weighted_alternating_slide_out" => Some(CoreExerciseName::WeightedAlternatingSlideOut),
            "ghd_back_extensions" => Some(CoreExerciseName::GhdBackExtensions),
            "weighted_ghd_back_extensions" => Some(CoreExerciseName::WeightedGhdBackExtensions),
            "overhead_walk" => Some(CoreExerciseName::OverheadWalk),
            "inchworm" => Some(CoreExerciseName::Inchworm),
            "weighted_modified_front_lever" => Some(CoreExerciseName::WeightedModifiedFrontLever),
            "russian_twist" => Some(CoreExerciseName::RussianTwist),
            "abdominal_leg_rotations" => Some(CoreExerciseName::AbdominalLegRotations),
            "arm_and_leg_extension_on_knees" => Some(CoreExerciseName::ArmAndLegExtensionOnKnees),
            "bicycle" => Some(CoreExerciseName::Bicycle),
            "bicep_curl_with_leg_extension" => Some(CoreExerciseName::BicepCurlWithLegExtension),
            "cat_cow" => Some(CoreExerciseName::CatCow),
            "corkscrew" => Some(CoreExerciseName::Corkscrew),
            "criss_cross" => Some(CoreExerciseName::CrissCross),
            "criss_cross_with_ball" => Some(CoreExerciseName::CrissCrossWithBall),
            "double_leg_stretch" => Some(CoreExerciseName::DoubleLegStretch),
            "knee_folds" => Some(CoreExerciseName::KneeFolds),
            "lower_lift" => Some(CoreExerciseName::LowerLift),
            "neck_pull" => Some(CoreExerciseName::NeckPull),
            "pelvic_clocks" => Some(CoreExerciseName::PelvicClocks),
            "roll_over" => Some(CoreExerciseName::RollOver),
            "roll_up" => Some(CoreExerciseName::RollUp),
            "rolling" => Some(CoreExerciseName::Rolling),
            "rowing_1" => Some(CoreExerciseName::Rowing1),
            "rowing_2" => Some(CoreExerciseName::Rowing2),
            "scissors" => Some(CoreExerciseName::Scissors),
            "single_leg_circles" => Some(CoreExerciseName::SingleLegCircles),
            "single_leg_stretch" => Some(CoreExerciseName::SingleLegStretch),
            "snake_twist_1_and_2" => Some(CoreExerciseName::SnakeTwist1And2),
            "swan" => Some(CoreExerciseName::Swan),
            "swimming" => Some(CoreExerciseName::Swimming),
            "teaser" => Some(CoreExerciseName::Teaser),
            "the_hundred" => Some(CoreExerciseName::TheHundred),
            "bicep_curl_with_leg_extension_with_weights" => {
                Some(CoreExerciseName::BicepCurlWithLegExtensionWithWeights)
            }
            "hanging_l_sit" => Some(CoreExerciseName::HangingLSit),
            "lower_lift_with_weights" => Some(CoreExerciseName::LowerLiftWithWeights),
            "ring_l_sit" => Some(CoreExerciseName::RingLSit),
            "rowing_1_with_weights" => Some(CoreExerciseName::Rowing1WithWeights),
            "rowing_2_with_weights" => Some(CoreExerciseName::Rowing2WithWeights),
            "scissors_with_weights" => Some(CoreExerciseName::ScissorsWithWeights),
            "single_leg_stretch_with_weights" => {
                Some(CoreExerciseName::SingleLegStretchWithWeights)
            }
            "toes_to_elbows" => Some(CoreExerciseName::ToesToElbows),
            "weighted_criss_cross" => Some(CoreExerciseName::WeightedCrissCross),
            "weighted_double_leg_stretch" => Some(CoreExerciseName::WeightedDoubleLegStretch),
            "weighted_the_hundred" => Some(CoreExerciseName::WeightedTheHundred),
            "l_sit" => Some(CoreExerciseName::LSit),
            "turkish_get_up" => Some(CoreExerciseName::TurkishGetUp),
            "weighted_ring_l_sit" => Some(CoreExerciseName::WeightedRingLSit),
            "weighted_hanging_l_sit" => Some(CoreExerciseName::WeightedHangingLSit),
            "weighted_l_sit" => Some(CoreExerciseName::WeightedLSit),
            "side_bend_low_wheelchair" => Some(CoreExerciseName::SideBendLowWheelchair),
            "side_bend_mid_wheelchair" => Some(CoreExerciseName::SideBendMidWheelchair),
            "side_bend_high_wheelchair" => Some(CoreExerciseName::SideBendHighWheelchair),
            "seated_side_bend" => Some(CoreExerciseName::SeatedSideBend),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum CrunchExerciseName {
    BicycleCrunch = 0,
    CableCrunch = 1,
    CircularArmCrunch = 2,
    CrossedArmsCrunch = 3,
    WeightedCrossedArmsCrunch = 4,
    CrossLegReverseCrunch = 5,
    WeightedCrossLegReverseCrunch = 6,
    CrunchChop = 7,
    WeightedCrunchChop = 8,
    DoubleCrunch = 9,
    WeightedDoubleCrunch = 10,
    ElbowToKneeCrunch = 11,
    WeightedElbowToKneeCrunch = 12,
    FlutterKicks = 13,
    WeightedFlutterKicks = 14,
    FoamRollerReverseCrunchOnBench = 15,
    WeightedFoamRollerReverseCrunchOnBench = 16,
    FoamRollerReverseCrunchWithDumbbell = 17,
    FoamRollerReverseCrunchWithMedicineBall = 18,
    FrogPress = 19,
    HangingKneeRaiseObliqueCrunch = 20,
    WeightedHangingKneeRaiseObliqueCrunch = 21,
    HipCrossover = 22,
    WeightedHipCrossover = 23,
    HollowRock = 24,
    WeightedHollowRock = 25,
    InclineReverseCrunch = 26,
    WeightedInclineReverseCrunch = 27,
    KneelingCableCrunch = 28,
    KneelingCrossCrunch = 29,
    WeightedKneelingCrossCrunch = 30,
    KneelingObliqueCableCrunch = 31,
    KneesToElbow = 32,
    LegExtensions = 33,
    WeightedLegExtensions = 34,
    LegLevers = 35,
    McgillCurlUp = 36,
    WeightedMcgillCurlUp = 37,
    ModifiedPilatesRollUpWithBall = 38,
    WeightedModifiedPilatesRollUpWithBall = 39,
    PilatesCrunch = 40,
    WeightedPilatesCrunch = 41,
    PilatesRollUpWithBall = 42,
    WeightedPilatesRollUpWithBall = 43,
    RaisedLegsCrunch = 44,
    WeightedRaisedLegsCrunch = 45,
    ReverseCrunch = 46,
    WeightedReverseCrunch = 47,
    ReverseCrunchOnABench = 48,
    WeightedReverseCrunchOnABench = 49,
    ReverseCurlAndLift = 50,
    WeightedReverseCurlAndLift = 51,
    RotationalLift = 52,
    WeightedRotationalLift = 53,
    SeatedAlternatingReverseCrunch = 54,
    WeightedSeatedAlternatingReverseCrunch = 55,
    SeatedLegU = 56,
    WeightedSeatedLegU = 57,
    SideToSideCrunchAndWeave = 58,
    WeightedSideToSideCrunchAndWeave = 59,
    SingleLegReverseCrunch = 60,
    WeightedSingleLegReverseCrunch = 61,
    SkaterCrunchCross = 62,
    WeightedSkaterCrunchCross = 63,
    StandingCableCrunch = 64,
    StandingSideCrunch = 65,
    StepClimb = 66,
    WeightedStepClimb = 67,
    SwissBallCrunch = 68,
    SwissBallReverseCrunch = 69,
    WeightedSwissBallReverseCrunch = 70,
    SwissBallRussianTwist = 71,
    WeightedSwissBallRussianTwist = 72,
    SwissBallSideCrunch = 73,
    WeightedSwissBallSideCrunch = 74,
    ThoracicCrunchesOnFoamRoller = 75,
    WeightedThoracicCrunchesOnFoamRoller = 76,
    TricepsCrunch = 77,
    WeightedBicycleCrunch = 78,
    WeightedCrunch = 79,
    WeightedSwissBallCrunch = 80,
    ToesToBar = 81,
    WeightedToesToBar = 82,
    Crunch = 83,
    StraightLegCrunchWithBall = 84,
    LegClimbCrunch = 86,
}

impl CrunchExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            CrunchExerciseName::BicycleCrunch => "bicycle_crunch",
            CrunchExerciseName::CableCrunch => "cable_crunch",
            CrunchExerciseName::CircularArmCrunch => "circular_arm_crunch",
            CrunchExerciseName::CrossedArmsCrunch => "crossed_arms_crunch",
            CrunchExerciseName::WeightedCrossedArmsCrunch => "weighted_crossed_arms_crunch",
            CrunchExerciseName::CrossLegReverseCrunch => "cross_leg_reverse_crunch",
            CrunchExerciseName::WeightedCrossLegReverseCrunch => {
                "weighted_cross_leg_reverse_crunch"
            }
            CrunchExerciseName::CrunchChop => "crunch_chop",
            CrunchExerciseName::WeightedCrunchChop => "weighted_crunch_chop",
            CrunchExerciseName::DoubleCrunch => "double_crunch",
            CrunchExerciseName::WeightedDoubleCrunch => "weighted_double_crunch",
            CrunchExerciseName::ElbowToKneeCrunch => "elbow_to_knee_crunch",
            CrunchExerciseName::WeightedElbowToKneeCrunch => "weighted_elbow_to_knee_crunch",
            CrunchExerciseName::FlutterKicks => "flutter_kicks",
            CrunchExerciseName::WeightedFlutterKicks => "weighted_flutter_kicks",
            CrunchExerciseName::FoamRollerReverseCrunchOnBench => {
                "foam_roller_reverse_crunch_on_bench"
            }
            CrunchExerciseName::WeightedFoamRollerReverseCrunchOnBench => {
                "weighted_foam_roller_reverse_crunch_on_bench"
            }
            CrunchExerciseName::FoamRollerReverseCrunchWithDumbbell => {
                "foam_roller_reverse_crunch_with_dumbbell"
            }
            CrunchExerciseName::FoamRollerReverseCrunchWithMedicineBall => {
                "foam_roller_reverse_crunch_with_medicine_ball"
            }
            CrunchExerciseName::FrogPress => "frog_press",
            CrunchExerciseName::HangingKneeRaiseObliqueCrunch => {
                "hanging_knee_raise_oblique_crunch"
            }
            CrunchExerciseName::WeightedHangingKneeRaiseObliqueCrunch => {
                "weighted_hanging_knee_raise_oblique_crunch"
            }
            CrunchExerciseName::HipCrossover => "hip_crossover",
            CrunchExerciseName::WeightedHipCrossover => "weighted_hip_crossover",
            CrunchExerciseName::HollowRock => "hollow_rock",
            CrunchExerciseName::WeightedHollowRock => "weighted_hollow_rock",
            CrunchExerciseName::InclineReverseCrunch => "incline_reverse_crunch",
            CrunchExerciseName::WeightedInclineReverseCrunch => "weighted_incline_reverse_crunch",
            CrunchExerciseName::KneelingCableCrunch => "kneeling_cable_crunch",
            CrunchExerciseName::KneelingCrossCrunch => "kneeling_cross_crunch",
            CrunchExerciseName::WeightedKneelingCrossCrunch => "weighted_kneeling_cross_crunch",
            CrunchExerciseName::KneelingObliqueCableCrunch => "kneeling_oblique_cable_crunch",
            CrunchExerciseName::KneesToElbow => "knees_to_elbow",
            CrunchExerciseName::LegExtensions => "leg_extensions",
            CrunchExerciseName::WeightedLegExtensions => "weighted_leg_extensions",
            CrunchExerciseName::LegLevers => "leg_levers",
            CrunchExerciseName::McgillCurlUp => "mcgill_curl_up",
            CrunchExerciseName::WeightedMcgillCurlUp => "weighted_mcgill_curl_up",
            CrunchExerciseName::ModifiedPilatesRollUpWithBall => {
                "modified_pilates_roll_up_with_ball"
            }
            CrunchExerciseName::WeightedModifiedPilatesRollUpWithBall => {
                "weighted_modified_pilates_roll_up_with_ball"
            }
            CrunchExerciseName::PilatesCrunch => "pilates_crunch",
            CrunchExerciseName::WeightedPilatesCrunch => "weighted_pilates_crunch",
            CrunchExerciseName::PilatesRollUpWithBall => "pilates_roll_up_with_ball",
            CrunchExerciseName::WeightedPilatesRollUpWithBall => {
                "weighted_pilates_roll_up_with_ball"
            }
            CrunchExerciseName::RaisedLegsCrunch => "raised_legs_crunch",
            CrunchExerciseName::WeightedRaisedLegsCrunch => "weighted_raised_legs_crunch",
            CrunchExerciseName::ReverseCrunch => "reverse_crunch",
            CrunchExerciseName::WeightedReverseCrunch => "weighted_reverse_crunch",
            CrunchExerciseName::ReverseCrunchOnABench => "reverse_crunch_on_a_bench",
            CrunchExerciseName::WeightedReverseCrunchOnABench => {
                "weighted_reverse_crunch_on_a_bench"
            }
            CrunchExerciseName::ReverseCurlAndLift => "reverse_curl_and_lift",
            CrunchExerciseName::WeightedReverseCurlAndLift => "weighted_reverse_curl_and_lift",
            CrunchExerciseName::RotationalLift => "rotational_lift",
            CrunchExerciseName::WeightedRotationalLift => "weighted_rotational_lift",
            CrunchExerciseName::SeatedAlternatingReverseCrunch => {
                "seated_alternating_reverse_crunch"
            }
            CrunchExerciseName::WeightedSeatedAlternatingReverseCrunch => {
                "weighted_seated_alternating_reverse_crunch"
            }
            CrunchExerciseName::SeatedLegU => "seated_leg_u",
            CrunchExerciseName::WeightedSeatedLegU => "weighted_seated_leg_u",
            CrunchExerciseName::SideToSideCrunchAndWeave => "side_to_side_crunch_and_weave",
            CrunchExerciseName::WeightedSideToSideCrunchAndWeave => {
                "weighted_side_to_side_crunch_and_weave"
            }
            CrunchExerciseName::SingleLegReverseCrunch => "single_leg_reverse_crunch",
            CrunchExerciseName::WeightedSingleLegReverseCrunch => {
                "weighted_single_leg_reverse_crunch"
            }
            CrunchExerciseName::SkaterCrunchCross => "skater_crunch_cross",
            CrunchExerciseName::WeightedSkaterCrunchCross => "weighted_skater_crunch_cross",
            CrunchExerciseName::StandingCableCrunch => "standing_cable_crunch",
            CrunchExerciseName::StandingSideCrunch => "standing_side_crunch",
            CrunchExerciseName::StepClimb => "step_climb",
            CrunchExerciseName::WeightedStepClimb => "weighted_step_climb",
            CrunchExerciseName::SwissBallCrunch => "swiss_ball_crunch",
            CrunchExerciseName::SwissBallReverseCrunch => "swiss_ball_reverse_crunch",
            CrunchExerciseName::WeightedSwissBallReverseCrunch => {
                "weighted_swiss_ball_reverse_crunch"
            }
            CrunchExerciseName::SwissBallRussianTwist => "swiss_ball_russian_twist",
            CrunchExerciseName::WeightedSwissBallRussianTwist => {
                "weighted_swiss_ball_russian_twist"
            }
            CrunchExerciseName::SwissBallSideCrunch => "swiss_ball_side_crunch",
            CrunchExerciseName::WeightedSwissBallSideCrunch => "weighted_swiss_ball_side_crunch",
            CrunchExerciseName::ThoracicCrunchesOnFoamRoller => "thoracic_crunches_on_foam_roller",
            CrunchExerciseName::WeightedThoracicCrunchesOnFoamRoller => {
                "weighted_thoracic_crunches_on_foam_roller"
            }
            CrunchExerciseName::TricepsCrunch => "triceps_crunch",
            CrunchExerciseName::WeightedBicycleCrunch => "weighted_bicycle_crunch",
            CrunchExerciseName::WeightedCrunch => "weighted_crunch",
            CrunchExerciseName::WeightedSwissBallCrunch => "weighted_swiss_ball_crunch",
            CrunchExerciseName::ToesToBar => "toes_to_bar",
            CrunchExerciseName::WeightedToesToBar => "weighted_toes_to_bar",
            CrunchExerciseName::Crunch => "crunch",
            CrunchExerciseName::StraightLegCrunchWithBall => "straight_leg_crunch_with_ball",
            CrunchExerciseName::LegClimbCrunch => "leg_climb_crunch",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(CrunchExerciseName::BicycleCrunch),
            1 => Some(CrunchExerciseName::CableCrunch),
            2 => Some(CrunchExerciseName::CircularArmCrunch),
            3 => Some(CrunchExerciseName::CrossedArmsCrunch),
            4 => Some(CrunchExerciseName::WeightedCrossedArmsCrunch),
            5 => Some(CrunchExerciseName::CrossLegReverseCrunch),
            6 => Some(CrunchExerciseName::WeightedCrossLegReverseCrunch),
            7 => Some(CrunchExerciseName::CrunchChop),
            8 => Some(CrunchExerciseName::WeightedCrunchChop),
            9 => Some(CrunchExerciseName::DoubleCrunch),
            10 => Some(CrunchExerciseName::WeightedDoubleCrunch),
            11 => Some(CrunchExerciseName::ElbowToKneeCrunch),
            12 => Some(CrunchExerciseName::WeightedElbowToKneeCrunch),
            13 => Some(CrunchExerciseName::FlutterKicks),
            14 => Some(CrunchExerciseName::WeightedFlutterKicks),
            15 => Some(CrunchExerciseName::FoamRollerReverseCrunchOnBench),
            16 => Some(CrunchExerciseName::WeightedFoamRollerReverseCrunchOnBench),
            17 => Some(CrunchExerciseName::FoamRollerReverseCrunchWithDumbbell),
            18 => Some(CrunchExerciseName::FoamRollerReverseCrunchWithMedicineBall),
            19 => Some(CrunchExerciseName::FrogPress),
            20 => Some(CrunchExerciseName::HangingKneeRaiseObliqueCrunch),
            21 => Some(CrunchExerciseName::WeightedHangingKneeRaiseObliqueCrunch),
            22 => Some(CrunchExerciseName::HipCrossover),
            23 => Some(CrunchExerciseName::WeightedHipCrossover),
            24 => Some(CrunchExerciseName::HollowRock),
            25 => Some(CrunchExerciseName::WeightedHollowRock),
            26 => Some(CrunchExerciseName::InclineReverseCrunch),
            27 => Some(CrunchExerciseName::WeightedInclineReverseCrunch),
            28 => Some(CrunchExerciseName::KneelingCableCrunch),
            29 => Some(CrunchExerciseName::KneelingCrossCrunch),
            30 => Some(CrunchExerciseName::WeightedKneelingCrossCrunch),
            31 => Some(CrunchExerciseName::KneelingObliqueCableCrunch),
            32 => Some(CrunchExerciseName::KneesToElbow),
            33 => Some(CrunchExerciseName::LegExtensions),
            34 => Some(CrunchExerciseName::WeightedLegExtensions),
            35 => Some(CrunchExerciseName::LegLevers),
            36 => Some(CrunchExerciseName::McgillCurlUp),
            37 => Some(CrunchExerciseName::WeightedMcgillCurlUp),
            38 => Some(CrunchExerciseName::ModifiedPilatesRollUpWithBall),
            39 => Some(CrunchExerciseName::WeightedModifiedPilatesRollUpWithBall),
            40 => Some(CrunchExerciseName::PilatesCrunch),
            41 => Some(CrunchExerciseName::WeightedPilatesCrunch),
            42 => Some(CrunchExerciseName::PilatesRollUpWithBall),
            43 => Some(CrunchExerciseName::WeightedPilatesRollUpWithBall),
            44 => Some(CrunchExerciseName::RaisedLegsCrunch),
            45 => Some(CrunchExerciseName::WeightedRaisedLegsCrunch),
            46 => Some(CrunchExerciseName::ReverseCrunch),
            47 => Some(CrunchExerciseName::WeightedReverseCrunch),
            48 => Some(CrunchExerciseName::ReverseCrunchOnABench),
            49 => Some(CrunchExerciseName::WeightedReverseCrunchOnABench),
            50 => Some(CrunchExerciseName::ReverseCurlAndLift),
            51 => Some(CrunchExerciseName::WeightedReverseCurlAndLift),
            52 => Some(CrunchExerciseName::RotationalLift),
            53 => Some(CrunchExerciseName::WeightedRotationalLift),
            54 => Some(CrunchExerciseName::SeatedAlternatingReverseCrunch),
            55 => Some(CrunchExerciseName::WeightedSeatedAlternatingReverseCrunch),
            56 => Some(CrunchExerciseName::SeatedLegU),
            57 => Some(CrunchExerciseName::WeightedSeatedLegU),
            58 => Some(CrunchExerciseName::SideToSideCrunchAndWeave),
            59 => Some(CrunchExerciseName::WeightedSideToSideCrunchAndWeave),
            60 => Some(CrunchExerciseName::SingleLegReverseCrunch),
            61 => Some(CrunchExerciseName::WeightedSingleLegReverseCrunch),
            62 => Some(CrunchExerciseName::SkaterCrunchCross),
            63 => Some(CrunchExerciseName::WeightedSkaterCrunchCross),
            64 => Some(CrunchExerciseName::StandingCableCrunch),
            65 => Some(CrunchExerciseName::StandingSideCrunch),
            66 => Some(CrunchExerciseName::StepClimb),
            67 => Some(CrunchExerciseName::WeightedStepClimb),
            68 => Some(CrunchExerciseName::SwissBallCrunch),
            69 => Some(CrunchExerciseName::SwissBallReverseCrunch),
            70 => Some(CrunchExerciseName::WeightedSwissBallReverseCrunch),
            71 => Some(CrunchExerciseName::SwissBallRussianTwist),
            72 => Some(CrunchExerciseName::WeightedSwissBallRussianTwist),
            73 => Some(CrunchExerciseName::SwissBallSideCrunch),
            74 => Some(CrunchExerciseName::WeightedSwissBallSideCrunch),
            75 => Some(CrunchExerciseName::ThoracicCrunchesOnFoamRoller),
            76 => Some(CrunchExerciseName::WeightedThoracicCrunchesOnFoamRoller),
            77 => Some(CrunchExerciseName::TricepsCrunch),
            78 => Some(CrunchExerciseName::WeightedBicycleCrunch),
            79 => Some(CrunchExerciseName::WeightedCrunch),
            80 => Some(CrunchExerciseName::WeightedSwissBallCrunch),
            81 => Some(CrunchExerciseName::ToesToBar),
            82 => Some(CrunchExerciseName::WeightedToesToBar),
            83 => Some(CrunchExerciseName::Crunch),
            84 => Some(CrunchExerciseName::StraightLegCrunchWithBall),
            86 => Some(CrunchExerciseName::LegClimbCrunch),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "bicycle_crunch" => Some(CrunchExerciseName::BicycleCrunch),
            "cable_crunch" => Some(CrunchExerciseName::CableCrunch),
            "circular_arm_crunch" => Some(CrunchExerciseName::CircularArmCrunch),
            "crossed_arms_crunch" => Some(CrunchExerciseName::CrossedArmsCrunch),
            "weighted_crossed_arms_crunch" => Some(CrunchExerciseName::WeightedCrossedArmsCrunch),
            "cross_leg_reverse_crunch" => Some(CrunchExerciseName::CrossLegReverseCrunch),
            "weighted_cross_leg_reverse_crunch" => {
                Some(CrunchExerciseName::WeightedCrossLegReverseCrunch)
            }
            "crunch_chop" => Some(CrunchExerciseName::CrunchChop),
            "weighted_crunch_chop" => Some(CrunchExerciseName::WeightedCrunchChop),
            "double_crunch" => Some(CrunchExerciseName::DoubleCrunch),
            "weighted_double_crunch" => Some(CrunchExerciseName::WeightedDoubleCrunch),
            "elbow_to_knee_crunch" => Some(CrunchExerciseName::ElbowToKneeCrunch),
            "weighted_elbow_to_knee_crunch" => Some(CrunchExerciseName::WeightedElbowToKneeCrunch),
            "flutter_kicks" => Some(CrunchExerciseName::FlutterKicks),
            "weighted_flutter_kicks" => Some(CrunchExerciseName::WeightedFlutterKicks),
            "foam_roller_reverse_crunch_on_bench" => {
                Some(CrunchExerciseName::FoamRollerReverseCrunchOnBench)
            }
            "weighted_foam_roller_reverse_crunch_on_bench" => {
                Some(CrunchExerciseName::WeightedFoamRollerReverseCrunchOnBench)
            }
            "foam_roller_reverse_crunch_with_dumbbell" => {
                Some(CrunchExerciseName::FoamRollerReverseCrunchWithDumbbell)
            }
            "foam_roller_reverse_crunch_with_medicine_ball" => {
                Some(CrunchExerciseName::FoamRollerReverseCrunchWithMedicineBall)
            }
            "frog_press" => Some(CrunchExerciseName::FrogPress),
            "hanging_knee_raise_oblique_crunch" => {
                Some(CrunchExerciseName::HangingKneeRaiseObliqueCrunch)
            }
            "weighted_hanging_knee_raise_oblique_crunch" => {
                Some(CrunchExerciseName::WeightedHangingKneeRaiseObliqueCrunch)
            }
            "hip_crossover" => Some(CrunchExerciseName::HipCrossover),
            "weighted_hip_crossover" => Some(CrunchExerciseName::WeightedHipCrossover),
            "hollow_rock" => Some(CrunchExerciseName::HollowRock),
            "weighted_hollow_rock" => Some(CrunchExerciseName::WeightedHollowRock),
            "incline_reverse_crunch" => Some(CrunchExerciseName::InclineReverseCrunch),
            "weighted_incline_reverse_crunch" => {
                Some(CrunchExerciseName::WeightedInclineReverseCrunch)
            }
            "kneeling_cable_crunch" => Some(CrunchExerciseName::KneelingCableCrunch),
            "kneeling_cross_crunch" => Some(CrunchExerciseName::KneelingCrossCrunch),
            "weighted_kneeling_cross_crunch" => {
                Some(CrunchExerciseName::WeightedKneelingCrossCrunch)
            }
            "kneeling_oblique_cable_crunch" => Some(CrunchExerciseName::KneelingObliqueCableCrunch),
            "knees_to_elbow" => Some(CrunchExerciseName::KneesToElbow),
            "leg_extensions" => Some(CrunchExerciseName::LegExtensions),
            "weighted_leg_extensions" => Some(CrunchExerciseName::WeightedLegExtensions),
            "leg_levers" => Some(CrunchExerciseName::LegLevers),
            "mcgill_curl_up" => Some(CrunchExerciseName::McgillCurlUp),
            "weighted_mcgill_curl_up" => Some(CrunchExerciseName::WeightedMcgillCurlUp),
            "modified_pilates_roll_up_with_ball" => {
                Some(CrunchExerciseName::ModifiedPilatesRollUpWithBall)
            }
            "weighted_modified_pilates_roll_up_with_ball" => {
                Some(CrunchExerciseName::WeightedModifiedPilatesRollUpWithBall)
            }
            "pilates_crunch" => Some(CrunchExerciseName::PilatesCrunch),
            "weighted_pilates_crunch" => Some(CrunchExerciseName::WeightedPilatesCrunch),
            "pilates_roll_up_with_ball" => Some(CrunchExerciseName::PilatesRollUpWithBall),
            "weighted_pilates_roll_up_with_ball" => {
                Some(CrunchExerciseName::WeightedPilatesRollUpWithBall)
            }
            "raised_legs_crunch" => Some(CrunchExerciseName::RaisedLegsCrunch),
            "weighted_raised_legs_crunch" => Some(CrunchExerciseName::WeightedRaisedLegsCrunch),
            "reverse_crunch" => Some(CrunchExerciseName::ReverseCrunch),
            "weighted_reverse_crunch" => Some(CrunchExerciseName::WeightedReverseCrunch),
            "reverse_crunch_on_a_bench" => Some(CrunchExerciseName::ReverseCrunchOnABench),
            "weighted_reverse_crunch_on_a_bench" => {
                Some(CrunchExerciseName::WeightedReverseCrunchOnABench)
            }
            "reverse_curl_and_lift" => Some(CrunchExerciseName::ReverseCurlAndLift),
            "weighted_reverse_curl_and_lift" => {
                Some(CrunchExerciseName::WeightedReverseCurlAndLift)
            }
            "rotational_lift" => Some(CrunchExerciseName::RotationalLift),
            "weighted_rotational_lift" => Some(CrunchExerciseName::WeightedRotationalLift),
            "seated_alternating_reverse_crunch" => {
                Some(CrunchExerciseName::SeatedAlternatingReverseCrunch)
            }
            "weighted_seated_alternating_reverse_crunch" => {
                Some(CrunchExerciseName::WeightedSeatedAlternatingReverseCrunch)
            }
            "seated_leg_u" => Some(CrunchExerciseName::SeatedLegU),
            "weighted_seated_leg_u" => Some(CrunchExerciseName::WeightedSeatedLegU),
            "side_to_side_crunch_and_weave" => Some(CrunchExerciseName::SideToSideCrunchAndWeave),
            "weighted_side_to_side_crunch_and_weave" => {
                Some(CrunchExerciseName::WeightedSideToSideCrunchAndWeave)
            }
            "single_leg_reverse_crunch" => Some(CrunchExerciseName::SingleLegReverseCrunch),
            "weighted_single_leg_reverse_crunch" => {
                Some(CrunchExerciseName::WeightedSingleLegReverseCrunch)
            }
            "skater_crunch_cross" => Some(CrunchExerciseName::SkaterCrunchCross),
            "weighted_skater_crunch_cross" => Some(CrunchExerciseName::WeightedSkaterCrunchCross),
            "standing_cable_crunch" => Some(CrunchExerciseName::StandingCableCrunch),
            "standing_side_crunch" => Some(CrunchExerciseName::StandingSideCrunch),
            "step_climb" => Some(CrunchExerciseName::StepClimb),
            "weighted_step_climb" => Some(CrunchExerciseName::WeightedStepClimb),
            "swiss_ball_crunch" => Some(CrunchExerciseName::SwissBallCrunch),
            "swiss_ball_reverse_crunch" => Some(CrunchExerciseName::SwissBallReverseCrunch),
            "weighted_swiss_ball_reverse_crunch" => {
                Some(CrunchExerciseName::WeightedSwissBallReverseCrunch)
            }
            "swiss_ball_russian_twist" => Some(CrunchExerciseName::SwissBallRussianTwist),
            "weighted_swiss_ball_russian_twist" => {
                Some(CrunchExerciseName::WeightedSwissBallRussianTwist)
            }
            "swiss_ball_side_crunch" => Some(CrunchExerciseName::SwissBallSideCrunch),
            "weighted_swiss_ball_side_crunch" => {
                Some(CrunchExerciseName::WeightedSwissBallSideCrunch)
            }
            "thoracic_crunches_on_foam_roller" => {
                Some(CrunchExerciseName::ThoracicCrunchesOnFoamRoller)
            }
            "weighted_thoracic_crunches_on_foam_roller" => {
                Some(CrunchExerciseName::WeightedThoracicCrunchesOnFoamRoller)
            }
            "triceps_crunch" => Some(CrunchExerciseName::TricepsCrunch),
            "weighted_bicycle_crunch" => Some(CrunchExerciseName::WeightedBicycleCrunch),
            "weighted_crunch" => Some(CrunchExerciseName::WeightedCrunch),
            "weighted_swiss_ball_crunch" => Some(CrunchExerciseName::WeightedSwissBallCrunch),
            "toes_to_bar" => Some(CrunchExerciseName::ToesToBar),
            "weighted_toes_to_bar" => Some(CrunchExerciseName::WeightedToesToBar),
            "crunch" => Some(CrunchExerciseName::Crunch),
            "straight_leg_crunch_with_ball" => Some(CrunchExerciseName::StraightLegCrunchWithBall),
            "leg_climb_crunch" => Some(CrunchExerciseName::LegClimbCrunch),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum CurlExerciseName {
    AlternatingDumbbellBicepsCurl = 0,
    AlternatingDumbbellBicepsCurlOnSwissBall = 1,
    AlternatingInclineDumbbellBicepsCurl = 2,
    BarbellBicepsCurl = 3,
    BarbellReverseWristCurl = 4,
    BarbellWristCurl = 5,
    BehindTheBackBarbellReverseWristCurl = 6,
    BehindTheBackOneArmCableCurl = 7,
    CableBicepsCurl = 8,
    CableHammerCurl = 9,
    CheatingBarbellBicepsCurl = 10,
    CloseGripEzBarBicepsCurl = 11,
    CrossBodyDumbbellHammerCurl = 12,
    DeadHangBicepsCurl = 13,
    DeclineHammerCurl = 14,
    DumbbellBicepsCurlWithStaticHold = 15,
    DumbbellHammerCurl = 16,
    DumbbellReverseWristCurl = 17,
    DumbbellWristCurl = 18,
    EzBarPreacherCurl = 19,
    ForwardBendBicepsCurl = 20,
    HammerCurlToPress = 21,
    InclineDumbbellBicepsCurl = 22,
    InclineOffsetThumbDumbbellCurl = 23,
    KettlebellBicepsCurl = 24,
    LyingConcentrationCableCurl = 25,
    OneArmPreacherCurl = 26,
    PlatePinchCurl = 27,
    PreacherCurlWithCable = 28,
    ReverseEzBarCurl = 29,
    ReverseGripWristCurl = 30,
    ReverseGripBarbellBicepsCurl = 31,
    SeatedAlternatingDumbbellBicepsCurl = 32,
    SeatedDumbbellBicepsCurl = 33,
    SeatedReverseDumbbellCurl = 34,
    SplitStanceOffsetPinkyDumbbellCurl = 35,
    StandingAlternatingDumbbellCurls = 36,
    StandingDumbbellBicepsCurl = 37,
    StandingEzBarBicepsCurl = 38,
    StaticCurl = 39,
    SwissBallDumbbellOverheadTricepsExtension = 40,
    SwissBallEzBarPreacherCurl = 41,
    TwistingStandingDumbbellBicepsCurl = 42,
    WideGripEzBarBicepsCurl = 43,
    OneArmConcentrationCurl = 44,
    StandingZottmanBicepsCurl = 45,
    DumbbellBicepsCurl = 46,
    DragCurlWheelchair = 47,
    DumbbellBicepsCurlWheelchair = 48,
    BottleCurl = 49,
    SeatedBottleCurl = 50,
}

impl CurlExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            CurlExerciseName::AlternatingDumbbellBicepsCurl => "alternating_dumbbell_biceps_curl",
            CurlExerciseName::AlternatingDumbbellBicepsCurlOnSwissBall => {
                "alternating_dumbbell_biceps_curl_on_swiss_ball"
            }
            CurlExerciseName::AlternatingInclineDumbbellBicepsCurl => {
                "alternating_incline_dumbbell_biceps_curl"
            }
            CurlExerciseName::BarbellBicepsCurl => "barbell_biceps_curl",
            CurlExerciseName::BarbellReverseWristCurl => "barbell_reverse_wrist_curl",
            CurlExerciseName::BarbellWristCurl => "barbell_wrist_curl",
            CurlExerciseName::BehindTheBackBarbellReverseWristCurl => {
                "behind_the_back_barbell_reverse_wrist_curl"
            }
            CurlExerciseName::BehindTheBackOneArmCableCurl => "behind_the_back_one_arm_cable_curl",
            CurlExerciseName::CableBicepsCurl => "cable_biceps_curl",
            CurlExerciseName::CableHammerCurl => "cable_hammer_curl",
            CurlExerciseName::CheatingBarbellBicepsCurl => "cheating_barbell_biceps_curl",
            CurlExerciseName::CloseGripEzBarBicepsCurl => "close_grip_ez_bar_biceps_curl",
            CurlExerciseName::CrossBodyDumbbellHammerCurl => "cross_body_dumbbell_hammer_curl",
            CurlExerciseName::DeadHangBicepsCurl => "dead_hang_biceps_curl",
            CurlExerciseName::DeclineHammerCurl => "decline_hammer_curl",
            CurlExerciseName::DumbbellBicepsCurlWithStaticHold => {
                "dumbbell_biceps_curl_with_static_hold"
            }
            CurlExerciseName::DumbbellHammerCurl => "dumbbell_hammer_curl",
            CurlExerciseName::DumbbellReverseWristCurl => "dumbbell_reverse_wrist_curl",
            CurlExerciseName::DumbbellWristCurl => "dumbbell_wrist_curl",
            CurlExerciseName::EzBarPreacherCurl => "ez_bar_preacher_curl",
            CurlExerciseName::ForwardBendBicepsCurl => "forward_bend_biceps_curl",
            CurlExerciseName::HammerCurlToPress => "hammer_curl_to_press",
            CurlExerciseName::InclineDumbbellBicepsCurl => "incline_dumbbell_biceps_curl",
            CurlExerciseName::InclineOffsetThumbDumbbellCurl => {
                "incline_offset_thumb_dumbbell_curl"
            }
            CurlExerciseName::KettlebellBicepsCurl => "kettlebell_biceps_curl",
            CurlExerciseName::LyingConcentrationCableCurl => "lying_concentration_cable_curl",
            CurlExerciseName::OneArmPreacherCurl => "one_arm_preacher_curl",
            CurlExerciseName::PlatePinchCurl => "plate_pinch_curl",
            CurlExerciseName::PreacherCurlWithCable => "preacher_curl_with_cable",
            CurlExerciseName::ReverseEzBarCurl => "reverse_ez_bar_curl",
            CurlExerciseName::ReverseGripWristCurl => "reverse_grip_wrist_curl",
            CurlExerciseName::ReverseGripBarbellBicepsCurl => "reverse_grip_barbell_biceps_curl",
            CurlExerciseName::SeatedAlternatingDumbbellBicepsCurl => {
                "seated_alternating_dumbbell_biceps_curl"
            }
            CurlExerciseName::SeatedDumbbellBicepsCurl => "seated_dumbbell_biceps_curl",
            CurlExerciseName::SeatedReverseDumbbellCurl => "seated_reverse_dumbbell_curl",
            CurlExerciseName::SplitStanceOffsetPinkyDumbbellCurl => {
                "split_stance_offset_pinky_dumbbell_curl"
            }
            CurlExerciseName::StandingAlternatingDumbbellCurls => {
                "standing_alternating_dumbbell_curls"
            }
            CurlExerciseName::StandingDumbbellBicepsCurl => "standing_dumbbell_biceps_curl",
            CurlExerciseName::StandingEzBarBicepsCurl => "standing_ez_bar_biceps_curl",
            CurlExerciseName::StaticCurl => "static_curl",
            CurlExerciseName::SwissBallDumbbellOverheadTricepsExtension => {
                "swiss_ball_dumbbell_overhead_triceps_extension"
            }
            CurlExerciseName::SwissBallEzBarPreacherCurl => "swiss_ball_ez_bar_preacher_curl",
            CurlExerciseName::TwistingStandingDumbbellBicepsCurl => {
                "twisting_standing_dumbbell_biceps_curl"
            }
            CurlExerciseName::WideGripEzBarBicepsCurl => "wide_grip_ez_bar_biceps_curl",
            CurlExerciseName::OneArmConcentrationCurl => "one_arm_concentration_curl",
            CurlExerciseName::StandingZottmanBicepsCurl => "standing_zottman_biceps_curl",
            CurlExerciseName::DumbbellBicepsCurl => "dumbbell_biceps_curl",
            CurlExerciseName::DragCurlWheelchair => "drag_curl_wheelchair",
            CurlExerciseName::DumbbellBicepsCurlWheelchair => "dumbbell_biceps_curl_wheelchair",
            CurlExerciseName::BottleCurl => "bottle_curl",
            CurlExerciseName::SeatedBottleCurl => "seated_bottle_curl",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(CurlExerciseName::AlternatingDumbbellBicepsCurl),
            1 => Some(CurlExerciseName::AlternatingDumbbellBicepsCurlOnSwissBall),
            2 => Some(CurlExerciseName::AlternatingInclineDumbbellBicepsCurl),
            3 => Some(CurlExerciseName::BarbellBicepsCurl),
            4 => Some(CurlExerciseName::BarbellReverseWristCurl),
            5 => Some(CurlExerciseName::BarbellWristCurl),
            6 => Some(CurlExerciseName::BehindTheBackBarbellReverseWristCurl),
            7 => Some(CurlExerciseName::BehindTheBackOneArmCableCurl),
            8 => Some(CurlExerciseName::CableBicepsCurl),
            9 => Some(CurlExerciseName::CableHammerCurl),
            10 => Some(CurlExerciseName::CheatingBarbellBicepsCurl),
            11 => Some(CurlExerciseName::CloseGripEzBarBicepsCurl),
            12 => Some(CurlExerciseName::CrossBodyDumbbellHammerCurl),
            13 => Some(CurlExerciseName::DeadHangBicepsCurl),
            14 => Some(CurlExerciseName::DeclineHammerCurl),
            15 => Some(CurlExerciseName::DumbbellBicepsCurlWithStaticHold),
            16 => Some(CurlExerciseName::DumbbellHammerCurl),
            17 => Some(CurlExerciseName::DumbbellReverseWristCurl),
            18 => Some(CurlExerciseName::DumbbellWristCurl),
            19 => Some(CurlExerciseName::EzBarPreacherCurl),
            20 => Some(CurlExerciseName::ForwardBendBicepsCurl),
            21 => Some(CurlExerciseName::HammerCurlToPress),
            22 => Some(CurlExerciseName::InclineDumbbellBicepsCurl),
            23 => Some(CurlExerciseName::InclineOffsetThumbDumbbellCurl),
            24 => Some(CurlExerciseName::KettlebellBicepsCurl),
            25 => Some(CurlExerciseName::LyingConcentrationCableCurl),
            26 => Some(CurlExerciseName::OneArmPreacherCurl),
            27 => Some(CurlExerciseName::PlatePinchCurl),
            28 => Some(CurlExerciseName::PreacherCurlWithCable),
            29 => Some(CurlExerciseName::ReverseEzBarCurl),
            30 => Some(CurlExerciseName::ReverseGripWristCurl),
            31 => Some(CurlExerciseName::ReverseGripBarbellBicepsCurl),
            32 => Some(CurlExerciseName::SeatedAlternatingDumbbellBicepsCurl),
            33 => Some(CurlExerciseName::SeatedDumbbellBicepsCurl),
            34 => Some(CurlExerciseName::SeatedReverseDumbbellCurl),
            35 => Some(CurlExerciseName::SplitStanceOffsetPinkyDumbbellCurl),
            36 => Some(CurlExerciseName::StandingAlternatingDumbbellCurls),
            37 => Some(CurlExerciseName::StandingDumbbellBicepsCurl),
            38 => Some(CurlExerciseName::StandingEzBarBicepsCurl),
            39 => Some(CurlExerciseName::StaticCurl),
            40 => Some(CurlExerciseName::SwissBallDumbbellOverheadTricepsExtension),
            41 => Some(CurlExerciseName::SwissBallEzBarPreacherCurl),
            42 => Some(CurlExerciseName::TwistingStandingDumbbellBicepsCurl),
            43 => Some(CurlExerciseName::WideGripEzBarBicepsCurl),
            44 => Some(CurlExerciseName::OneArmConcentrationCurl),
            45 => Some(CurlExerciseName::StandingZottmanBicepsCurl),
            46 => Some(CurlExerciseName::DumbbellBicepsCurl),
            47 => Some(CurlExerciseName::DragCurlWheelchair),
            48 => Some(CurlExerciseName::DumbbellBicepsCurlWheelchair),
            49 => Some(CurlExerciseName::BottleCurl),
            50 => Some(CurlExerciseName::SeatedBottleCurl),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "alternating_dumbbell_biceps_curl" => {
                Some(CurlExerciseName::AlternatingDumbbellBicepsCurl)
            }
            "alternating_dumbbell_biceps_curl_on_swiss_ball" => {
                Some(CurlExerciseName::AlternatingDumbbellBicepsCurlOnSwissBall)
            }
            "alternating_incline_dumbbell_biceps_curl" => {
                Some(CurlExerciseName::AlternatingInclineDumbbellBicepsCurl)
            }
            "barbell_biceps_curl" => Some(CurlExerciseName::BarbellBicepsCurl),
            "barbell_reverse_wrist_curl" => Some(CurlExerciseName::BarbellReverseWristCurl),
            "barbell_wrist_curl" => Some(CurlExerciseName::BarbellWristCurl),
            "behind_the_back_barbell_reverse_wrist_curl" => {
                Some(CurlExerciseName::BehindTheBackBarbellReverseWristCurl)
            }
            "behind_the_back_one_arm_cable_curl" => {
                Some(CurlExerciseName::BehindTheBackOneArmCableCurl)
            }
            "cable_biceps_curl" => Some(CurlExerciseName::CableBicepsCurl),
            "cable_hammer_curl" => Some(CurlExerciseName::CableHammerCurl),
            "cheating_barbell_biceps_curl" => Some(CurlExerciseName::CheatingBarbellBicepsCurl),
            "close_grip_ez_bar_biceps_curl" => Some(CurlExerciseName::CloseGripEzBarBicepsCurl),
            "cross_body_dumbbell_hammer_curl" => {
                Some(CurlExerciseName::CrossBodyDumbbellHammerCurl)
            }
            "dead_hang_biceps_curl" => Some(CurlExerciseName::DeadHangBicepsCurl),
            "decline_hammer_curl" => Some(CurlExerciseName::DeclineHammerCurl),
            "dumbbell_biceps_curl_with_static_hold" => {
                Some(CurlExerciseName::DumbbellBicepsCurlWithStaticHold)
            }
            "dumbbell_hammer_curl" => Some(CurlExerciseName::DumbbellHammerCurl),
            "dumbbell_reverse_wrist_curl" => Some(CurlExerciseName::DumbbellReverseWristCurl),
            "dumbbell_wrist_curl" => Some(CurlExerciseName::DumbbellWristCurl),
            "ez_bar_preacher_curl" => Some(CurlExerciseName::EzBarPreacherCurl),
            "forward_bend_biceps_curl" => Some(CurlExerciseName::ForwardBendBicepsCurl),
            "hammer_curl_to_press" => Some(CurlExerciseName::HammerCurlToPress),
            "incline_dumbbell_biceps_curl" => Some(CurlExerciseName::InclineDumbbellBicepsCurl),
            "incline_offset_thumb_dumbbell_curl" => {
                Some(CurlExerciseName::InclineOffsetThumbDumbbellCurl)
            }
            "kettlebell_biceps_curl" => Some(CurlExerciseName::KettlebellBicepsCurl),
            "lying_concentration_cable_curl" => Some(CurlExerciseName::LyingConcentrationCableCurl),
            "one_arm_preacher_curl" => Some(CurlExerciseName::OneArmPreacherCurl),
            "plate_pinch_curl" => Some(CurlExerciseName::PlatePinchCurl),
            "preacher_curl_with_cable" => Some(CurlExerciseName::PreacherCurlWithCable),
            "reverse_ez_bar_curl" => Some(CurlExerciseName::ReverseEzBarCurl),
            "reverse_grip_wrist_curl" => Some(CurlExerciseName::ReverseGripWristCurl),
            "reverse_grip_barbell_biceps_curl" => {
                Some(CurlExerciseName::ReverseGripBarbellBicepsCurl)
            }
            "seated_alternating_dumbbell_biceps_curl" => {
                Some(CurlExerciseName::SeatedAlternatingDumbbellBicepsCurl)
            }
            "seated_dumbbell_biceps_curl" => Some(CurlExerciseName::SeatedDumbbellBicepsCurl),
            "seated_reverse_dumbbell_curl" => Some(CurlExerciseName::SeatedReverseDumbbellCurl),
            "split_stance_offset_pinky_dumbbell_curl" => {
                Some(CurlExerciseName::SplitStanceOffsetPinkyDumbbellCurl)
            }
            "standing_alternating_dumbbell_curls" => {
                Some(CurlExerciseName::StandingAlternatingDumbbellCurls)
            }
            "standing_dumbbell_biceps_curl" => Some(CurlExerciseName::StandingDumbbellBicepsCurl),
            "standing_ez_bar_biceps_curl" => Some(CurlExerciseName::StandingEzBarBicepsCurl),
            "static_curl" => Some(CurlExerciseName::StaticCurl),
            "swiss_ball_dumbbell_overhead_triceps_extension" => {
                Some(CurlExerciseName::SwissBallDumbbellOverheadTricepsExtension)
            }
            "swiss_ball_ez_bar_preacher_curl" => Some(CurlExerciseName::SwissBallEzBarPreacherCurl),
            "twisting_standing_dumbbell_biceps_curl" => {
                Some(CurlExerciseName::TwistingStandingDumbbellBicepsCurl)
            }
            "wide_grip_ez_bar_biceps_curl" => Some(CurlExerciseName::WideGripEzBarBicepsCurl),
            "one_arm_concentration_curl" => Some(CurlExerciseName::OneArmConcentrationCurl),
            "standing_zottman_biceps_curl" => Some(CurlExerciseName::StandingZottmanBicepsCurl),
            "dumbbell_biceps_curl" => Some(CurlExerciseName::DumbbellBicepsCurl),
            "drag_curl_wheelchair" => Some(CurlExerciseName::DragCurlWheelchair),
            "dumbbell_biceps_curl_wheelchair" => {
                Some(CurlExerciseName::DumbbellBicepsCurlWheelchair)
            }
            "bottle_curl" => Some(CurlExerciseName::BottleCurl),
            "seated_bottle_curl" => Some(CurlExerciseName::SeatedBottleCurl),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum DeadliftExerciseName {
    BarbellDeadlift = 0,
    BarbellStraightLegDeadlift = 1,
    DumbbellDeadlift = 2,
    DumbbellSingleLegDeadliftToRow = 3,
    DumbbellStraightLegDeadlift = 4,
    KettlebellFloorToShelf = 5,
    OneArmOneLegDeadlift = 6,
    RackPull = 7,
    RotationalDumbbellStraightLegDeadlift = 8,
    SingleArmDeadlift = 9,
    SingleLegBarbellDeadlift = 10,
    SingleLegBarbellStraightLegDeadlift = 11,
    SingleLegDeadliftWithBarbell = 12,
    SingleLegRdlCircuit = 13,
    SingleLegRomanianDeadliftWithDumbbell = 14,
    SumoDeadlift = 15,
    SumoDeadliftHighPull = 16,
    TrapBarDeadlift = 17,
    WideGripBarbellDeadlift = 18,
    KettlebellDeadlift = 20,
    KettlebellSumoDeadlift = 21,
    RomanianDeadlift = 23,
    SingleLegRomanianDeadliftCircuit = 24,
    StraightLegDeadlift = 25,
}

impl DeadliftExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            DeadliftExerciseName::BarbellDeadlift => "barbell_deadlift",
            DeadliftExerciseName::BarbellStraightLegDeadlift => "barbell_straight_leg_deadlift",
            DeadliftExerciseName::DumbbellDeadlift => "dumbbell_deadlift",
            DeadliftExerciseName::DumbbellSingleLegDeadliftToRow => {
                "dumbbell_single_leg_deadlift_to_row"
            }
            DeadliftExerciseName::DumbbellStraightLegDeadlift => "dumbbell_straight_leg_deadlift",
            DeadliftExerciseName::KettlebellFloorToShelf => "kettlebell_floor_to_shelf",
            DeadliftExerciseName::OneArmOneLegDeadlift => "one_arm_one_leg_deadlift",
            DeadliftExerciseName::RackPull => "rack_pull",
            DeadliftExerciseName::RotationalDumbbellStraightLegDeadlift => {
                "rotational_dumbbell_straight_leg_deadlift"
            }
            DeadliftExerciseName::SingleArmDeadlift => "single_arm_deadlift",
            DeadliftExerciseName::SingleLegBarbellDeadlift => "single_leg_barbell_deadlift",
            DeadliftExerciseName::SingleLegBarbellStraightLegDeadlift => {
                "single_leg_barbell_straight_leg_deadlift"
            }
            DeadliftExerciseName::SingleLegDeadliftWithBarbell => {
                "single_leg_deadlift_with_barbell"
            }
            DeadliftExerciseName::SingleLegRdlCircuit => "single_leg_rdl_circuit",
            DeadliftExerciseName::SingleLegRomanianDeadliftWithDumbbell => {
                "single_leg_romanian_deadlift_with_dumbbell"
            }
            DeadliftExerciseName::SumoDeadlift => "sumo_deadlift",
            DeadliftExerciseName::SumoDeadliftHighPull => "sumo_deadlift_high_pull",
            DeadliftExerciseName::TrapBarDeadlift => "trap_bar_deadlift",
            DeadliftExerciseName::WideGripBarbellDeadlift => "wide_grip_barbell_deadlift",
            DeadliftExerciseName::KettlebellDeadlift => "kettlebell_deadlift",
            DeadliftExerciseName::KettlebellSumoDeadlift => "kettlebell_sumo_deadlift",
            DeadliftExerciseName::RomanianDeadlift => "romanian_deadlift",
            DeadliftExerciseName::SingleLegRomanianDeadliftCircuit => {
                "single_leg_romanian_deadlift_circuit"
            }
            DeadliftExerciseName::StraightLegDeadlift => "straight_leg_deadlift",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(DeadliftExerciseName::BarbellDeadlift),
            1 => Some(DeadliftExerciseName::BarbellStraightLegDeadlift),
            2 => Some(DeadliftExerciseName::DumbbellDeadlift),
            3 => Some(DeadliftExerciseName::DumbbellSingleLegDeadliftToRow),
            4 => Some(DeadliftExerciseName::DumbbellStraightLegDeadlift),
            5 => Some(DeadliftExerciseName::KettlebellFloorToShelf),
            6 => Some(DeadliftExerciseName::OneArmOneLegDeadlift),
            7 => Some(DeadliftExerciseName::RackPull),
            8 => Some(DeadliftExerciseName::RotationalDumbbellStraightLegDeadlift),
            9 => Some(DeadliftExerciseName::SingleArmDeadlift),
            10 => Some(DeadliftExerciseName::SingleLegBarbellDeadlift),
            11 => Some(DeadliftExerciseName::SingleLegBarbellStraightLegDeadlift),
            12 => Some(DeadliftExerciseName::SingleLegDeadliftWithBarbell),
            13 => Some(DeadliftExerciseName::SingleLegRdlCircuit),
            14 => Some(DeadliftExerciseName::SingleLegRomanianDeadliftWithDumbbell),
            15 => Some(DeadliftExerciseName::SumoDeadlift),
            16 => Some(DeadliftExerciseName::SumoDeadliftHighPull),
            17 => Some(DeadliftExerciseName::TrapBarDeadlift),
            18 => Some(DeadliftExerciseName::WideGripBarbellDeadlift),
            20 => Some(DeadliftExerciseName::KettlebellDeadlift),
            21 => Some(DeadliftExerciseName::KettlebellSumoDeadlift),
            23 => Some(DeadliftExerciseName::RomanianDeadlift),
            24 => Some(DeadliftExerciseName::SingleLegRomanianDeadliftCircuit),
            25 => Some(DeadliftExerciseName::StraightLegDeadlift),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "barbell_deadlift" => Some(DeadliftExerciseName::BarbellDeadlift),
            "barbell_straight_leg_deadlift" => {
                Some(DeadliftExerciseName::BarbellStraightLegDeadlift)
            }
            "dumbbell_deadlift" => Some(DeadliftExerciseName::DumbbellDeadlift),
            "dumbbell_single_leg_deadlift_to_row" => {
                Some(DeadliftExerciseName::DumbbellSingleLegDeadliftToRow)
            }
            "dumbbell_straight_leg_deadlift" => {
                Some(DeadliftExerciseName::DumbbellStraightLegDeadlift)
            }
            "kettlebell_floor_to_shelf" => Some(DeadliftExerciseName::KettlebellFloorToShelf),
            "one_arm_one_leg_deadlift" => Some(DeadliftExerciseName::OneArmOneLegDeadlift),
            "rack_pull" => Some(DeadliftExerciseName::RackPull),
            "rotational_dumbbell_straight_leg_deadlift" => {
                Some(DeadliftExerciseName::RotationalDumbbellStraightLegDeadlift)
            }
            "single_arm_deadlift" => Some(DeadliftExerciseName::SingleArmDeadlift),
            "single_leg_barbell_deadlift" => Some(DeadliftExerciseName::SingleLegBarbellDeadlift),
            "single_leg_barbell_straight_leg_deadlift" => {
                Some(DeadliftExerciseName::SingleLegBarbellStraightLegDeadlift)
            }
            "single_leg_deadlift_with_barbell" => {
                Some(DeadliftExerciseName::SingleLegDeadliftWithBarbell)
            }
            "single_leg_rdl_circuit" => Some(DeadliftExerciseName::SingleLegRdlCircuit),
            "single_leg_romanian_deadlift_with_dumbbell" => {
                Some(DeadliftExerciseName::SingleLegRomanianDeadliftWithDumbbell)
            }
            "sumo_deadlift" => Some(DeadliftExerciseName::SumoDeadlift),
            "sumo_deadlift_high_pull" => Some(DeadliftExerciseName::SumoDeadliftHighPull),
            "trap_bar_deadlift" => Some(DeadliftExerciseName::TrapBarDeadlift),
            "wide_grip_barbell_deadlift" => Some(DeadliftExerciseName::WideGripBarbellDeadlift),
            "kettlebell_deadlift" => Some(DeadliftExerciseName::KettlebellDeadlift),
            "kettlebell_sumo_deadlift" => Some(DeadliftExerciseName::KettlebellSumoDeadlift),
            "romanian_deadlift" => Some(DeadliftExerciseName::RomanianDeadlift),
            "single_leg_romanian_deadlift_circuit" => {
                Some(DeadliftExerciseName::SingleLegRomanianDeadliftCircuit)
            }
            "straight_leg_deadlift" => Some(DeadliftExerciseName::StraightLegDeadlift),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum FlyeExerciseName {
    CableCrossover = 0,
    DeclineDumbbellFlye = 1,
    DumbbellFlye = 2,
    InclineDumbbellFlye = 3,
    KettlebellFlye = 4,
    KneelingRearFlye = 5,
    SingleArmStandingCableReverseFlye = 6,
    SwissBallDumbbellFlye = 7,
    ArmRotations = 8,
    HugATree = 9,
    FaceDownInclineReverseFlye = 10,
    InclineReverseFlye = 11,
    RearDeltFlyWheelchair = 12,
}

impl FlyeExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            FlyeExerciseName::CableCrossover => "cable_crossover",
            FlyeExerciseName::DeclineDumbbellFlye => "decline_dumbbell_flye",
            FlyeExerciseName::DumbbellFlye => "dumbbell_flye",
            FlyeExerciseName::InclineDumbbellFlye => "incline_dumbbell_flye",
            FlyeExerciseName::KettlebellFlye => "kettlebell_flye",
            FlyeExerciseName::KneelingRearFlye => "kneeling_rear_flye",
            FlyeExerciseName::SingleArmStandingCableReverseFlye => {
                "single_arm_standing_cable_reverse_flye"
            }
            FlyeExerciseName::SwissBallDumbbellFlye => "swiss_ball_dumbbell_flye",
            FlyeExerciseName::ArmRotations => "arm_rotations",
            FlyeExerciseName::HugATree => "hug_a_tree",
            FlyeExerciseName::FaceDownInclineReverseFlye => "face_down_incline_reverse_flye",
            FlyeExerciseName::InclineReverseFlye => "incline_reverse_flye",
            FlyeExerciseName::RearDeltFlyWheelchair => "rear_delt_fly_wheelchair",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(FlyeExerciseName::CableCrossover),
            1 => Some(FlyeExerciseName::DeclineDumbbellFlye),
            2 => Some(FlyeExerciseName::DumbbellFlye),
            3 => Some(FlyeExerciseName::InclineDumbbellFlye),
            4 => Some(FlyeExerciseName::KettlebellFlye),
            5 => Some(FlyeExerciseName::KneelingRearFlye),
            6 => Some(FlyeExerciseName::SingleArmStandingCableReverseFlye),
            7 => Some(FlyeExerciseName::SwissBallDumbbellFlye),
            8 => Some(FlyeExerciseName::ArmRotations),
            9 => Some(FlyeExerciseName::HugATree),
            10 => Some(FlyeExerciseName::FaceDownInclineReverseFlye),
            11 => Some(FlyeExerciseName::InclineReverseFlye),
            12 => Some(FlyeExerciseName::RearDeltFlyWheelchair),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "cable_crossover" => Some(FlyeExerciseName::CableCrossover),
            "decline_dumbbell_flye" => Some(FlyeExerciseName::DeclineDumbbellFlye),
            "dumbbell_flye" => Some(FlyeExerciseName::DumbbellFlye),
            "incline_dumbbell_flye" => Some(FlyeExerciseName::InclineDumbbellFlye),
            "kettlebell_flye" => Some(FlyeExerciseName::KettlebellFlye),
            "kneeling_rear_flye" => Some(FlyeExerciseName::KneelingRearFlye),
            "single_arm_standing_cable_reverse_flye" => {
                Some(FlyeExerciseName::SingleArmStandingCableReverseFlye)
            }
            "swiss_ball_dumbbell_flye" => Some(FlyeExerciseName::SwissBallDumbbellFlye),
            "arm_rotations" => Some(FlyeExerciseName::ArmRotations),
            "hug_a_tree" => Some(FlyeExerciseName::HugATree),
            "face_down_incline_reverse_flye" => Some(FlyeExerciseName::FaceDownInclineReverseFlye),
            "incline_reverse_flye" => Some(FlyeExerciseName::InclineReverseFlye),
            "rear_delt_fly_wheelchair" => Some(FlyeExerciseName::RearDeltFlyWheelchair),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum HipRaiseExerciseName {
    BarbellHipThrustOnFloor = 0,
    BarbellHipThrustWithBench = 1,
    BentKneeSwissBallReverseHipRaise = 2,
    WeightedBentKneeSwissBallReverseHipRaise = 3,
    BridgeWithLegExtension = 4,
    WeightedBridgeWithLegExtension = 5,
    ClamBridge = 6,
    FrontKickTabletop = 7,
    WeightedFrontKickTabletop = 8,
    HipExtensionAndCross = 9,
    WeightedHipExtensionAndCross = 10,
    HipRaise = 11,
    WeightedHipRaise = 12,
    HipRaiseWithFeetOnSwissBall = 13,
    WeightedHipRaiseWithFeetOnSwissBall = 14,
    HipRaiseWithHeadOnBosuBall = 15,
    WeightedHipRaiseWithHeadOnBosuBall = 16,
    HipRaiseWithHeadOnSwissBall = 17,
    WeightedHipRaiseWithHeadOnSwissBall = 18,
    HipRaiseWithKneeSqueeze = 19,
    WeightedHipRaiseWithKneeSqueeze = 20,
    InclineRearLegExtension = 21,
    WeightedInclineRearLegExtension = 22,
    KettlebellSwing = 23,
    MarchingHipRaise = 24,
    WeightedMarchingHipRaise = 25,
    MarchingHipRaiseWithFeetOnASwissBall = 26,
    WeightedMarchingHipRaiseWithFeetOnASwissBall = 27,
    ReverseHipRaise = 28,
    WeightedReverseHipRaise = 29,
    SingleLegHipRaise = 30,
    WeightedSingleLegHipRaise = 31,
    SingleLegHipRaiseWithFootOnBench = 32,
    WeightedSingleLegHipRaiseWithFootOnBench = 33,
    SingleLegHipRaiseWithFootOnBosuBall = 34,
    WeightedSingleLegHipRaiseWithFootOnBosuBall = 35,
    SingleLegHipRaiseWithFootOnFoamRoller = 36,
    WeightedSingleLegHipRaiseWithFootOnFoamRoller = 37,
    SingleLegHipRaiseWithFootOnMedicineBall = 38,
    WeightedSingleLegHipRaiseWithFootOnMedicineBall = 39,
    SingleLegHipRaiseWithHeadOnBosuBall = 40,
    WeightedSingleLegHipRaiseWithHeadOnBosuBall = 41,
    WeightedClamBridge = 42,
    SingleLegSwissBallHipRaiseAndLegCurl = 43,
    Clams = 44,
    InnerThighCircles = 45,
    InnerThighSideLift = 46,
    LegCircles = 47,
    LegLift = 48,
    LegLiftInExternalRotation = 49,
}

impl HipRaiseExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            HipRaiseExerciseName::BarbellHipThrustOnFloor => "barbell_hip_thrust_on_floor",
            HipRaiseExerciseName::BarbellHipThrustWithBench => "barbell_hip_thrust_with_bench",
            HipRaiseExerciseName::BentKneeSwissBallReverseHipRaise => {
                "bent_knee_swiss_ball_reverse_hip_raise"
            }
            HipRaiseExerciseName::WeightedBentKneeSwissBallReverseHipRaise => {
                "weighted_bent_knee_swiss_ball_reverse_hip_raise"
            }
            HipRaiseExerciseName::BridgeWithLegExtension => "bridge_with_leg_extension",
            HipRaiseExerciseName::WeightedBridgeWithLegExtension => {
                "weighted_bridge_with_leg_extension"
            }
            HipRaiseExerciseName::ClamBridge => "clam_bridge",
            HipRaiseExerciseName::FrontKickTabletop => "front_kick_tabletop",
            HipRaiseExerciseName::WeightedFrontKickTabletop => "weighted_front_kick_tabletop",
            HipRaiseExerciseName::HipExtensionAndCross => "hip_extension_and_cross",
            HipRaiseExerciseName::WeightedHipExtensionAndCross => {
                "weighted_hip_extension_and_cross"
            }
            HipRaiseExerciseName::HipRaise => "hip_raise",
            HipRaiseExerciseName::WeightedHipRaise => "weighted_hip_raise",
            HipRaiseExerciseName::HipRaiseWithFeetOnSwissBall => {
                "hip_raise_with_feet_on_swiss_ball"
            }
            HipRaiseExerciseName::WeightedHipRaiseWithFeetOnSwissBall => {
                "weighted_hip_raise_with_feet_on_swiss_ball"
            }
            HipRaiseExerciseName::HipRaiseWithHeadOnBosuBall => "hip_raise_with_head_on_bosu_ball",
            HipRaiseExerciseName::WeightedHipRaiseWithHeadOnBosuBall => {
                "weighted_hip_raise_with_head_on_bosu_ball"
            }
            HipRaiseExerciseName::HipRaiseWithHeadOnSwissBall => {
                "hip_raise_with_head_on_swiss_ball"
            }
            HipRaiseExerciseName::WeightedHipRaiseWithHeadOnSwissBall => {
                "weighted_hip_raise_with_head_on_swiss_ball"
            }
            HipRaiseExerciseName::HipRaiseWithKneeSqueeze => "hip_raise_with_knee_squeeze",
            HipRaiseExerciseName::WeightedHipRaiseWithKneeSqueeze => {
                "weighted_hip_raise_with_knee_squeeze"
            }
            HipRaiseExerciseName::InclineRearLegExtension => "incline_rear_leg_extension",
            HipRaiseExerciseName::WeightedInclineRearLegExtension => {
                "weighted_incline_rear_leg_extension"
            }
            HipRaiseExerciseName::KettlebellSwing => "kettlebell_swing",
            HipRaiseExerciseName::MarchingHipRaise => "marching_hip_raise",
            HipRaiseExerciseName::WeightedMarchingHipRaise => "weighted_marching_hip_raise",
            HipRaiseExerciseName::MarchingHipRaiseWithFeetOnASwissBall => {
                "marching_hip_raise_with_feet_on_a_swiss_ball"
            }
            HipRaiseExerciseName::WeightedMarchingHipRaiseWithFeetOnASwissBall => {
                "weighted_marching_hip_raise_with_feet_on_a_swiss_ball"
            }
            HipRaiseExerciseName::ReverseHipRaise => "reverse_hip_raise",
            HipRaiseExerciseName::WeightedReverseHipRaise => "weighted_reverse_hip_raise",
            HipRaiseExerciseName::SingleLegHipRaise => "single_leg_hip_raise",
            HipRaiseExerciseName::WeightedSingleLegHipRaise => "weighted_single_leg_hip_raise",
            HipRaiseExerciseName::SingleLegHipRaiseWithFootOnBench => {
                "single_leg_hip_raise_with_foot_on_bench"
            }
            HipRaiseExerciseName::WeightedSingleLegHipRaiseWithFootOnBench => {
                "weighted_single_leg_hip_raise_with_foot_on_bench"
            }
            HipRaiseExerciseName::SingleLegHipRaiseWithFootOnBosuBall => {
                "single_leg_hip_raise_with_foot_on_bosu_ball"
            }
            HipRaiseExerciseName::WeightedSingleLegHipRaiseWithFootOnBosuBall => {
                "weighted_single_leg_hip_raise_with_foot_on_bosu_ball"
            }
            HipRaiseExerciseName::SingleLegHipRaiseWithFootOnFoamRoller => {
                "single_leg_hip_raise_with_foot_on_foam_roller"
            }
            HipRaiseExerciseName::WeightedSingleLegHipRaiseWithFootOnFoamRoller => {
                "weighted_single_leg_hip_raise_with_foot_on_foam_roller"
            }
            HipRaiseExerciseName::SingleLegHipRaiseWithFootOnMedicineBall => {
                "single_leg_hip_raise_with_foot_on_medicine_ball"
            }
            HipRaiseExerciseName::WeightedSingleLegHipRaiseWithFootOnMedicineBall => {
                "weighted_single_leg_hip_raise_with_foot_on_medicine_ball"
            }
            HipRaiseExerciseName::SingleLegHipRaiseWithHeadOnBosuBall => {
                "single_leg_hip_raise_with_head_on_bosu_ball"
            }
            HipRaiseExerciseName::WeightedSingleLegHipRaiseWithHeadOnBosuBall => {
                "weighted_single_leg_hip_raise_with_head_on_bosu_ball"
            }
            HipRaiseExerciseName::WeightedClamBridge => "weighted_clam_bridge",
            HipRaiseExerciseName::SingleLegSwissBallHipRaiseAndLegCurl => {
                "single_leg_swiss_ball_hip_raise_and_leg_curl"
            }
            HipRaiseExerciseName::Clams => "clams",
            HipRaiseExerciseName::InnerThighCircles => "inner_thigh_circles",
            HipRaiseExerciseName::InnerThighSideLift => "inner_thigh_side_lift",
            HipRaiseExerciseName::LegCircles => "leg_circles",
            HipRaiseExerciseName::LegLift => "leg_lift",
            HipRaiseExerciseName::LegLiftInExternalRotation => "leg_lift_in_external_rotation",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(HipRaiseExerciseName::BarbellHipThrustOnFloor),
            1 => Some(HipRaiseExerciseName::BarbellHipThrustWithBench),
            2 => Some(HipRaiseExerciseName::BentKneeSwissBallReverseHipRaise),
            3 => Some(HipRaiseExerciseName::WeightedBentKneeSwissBallReverseHipRaise),
            4 => Some(HipRaiseExerciseName::BridgeWithLegExtension),
            5 => Some(HipRaiseExerciseName::WeightedBridgeWithLegExtension),
            6 => Some(HipRaiseExerciseName::ClamBridge),
            7 => Some(HipRaiseExerciseName::FrontKickTabletop),
            8 => Some(HipRaiseExerciseName::WeightedFrontKickTabletop),
            9 => Some(HipRaiseExerciseName::HipExtensionAndCross),
            10 => Some(HipRaiseExerciseName::WeightedHipExtensionAndCross),
            11 => Some(HipRaiseExerciseName::HipRaise),
            12 => Some(HipRaiseExerciseName::WeightedHipRaise),
            13 => Some(HipRaiseExerciseName::HipRaiseWithFeetOnSwissBall),
            14 => Some(HipRaiseExerciseName::WeightedHipRaiseWithFeetOnSwissBall),
            15 => Some(HipRaiseExerciseName::HipRaiseWithHeadOnBosuBall),
            16 => Some(HipRaiseExerciseName::WeightedHipRaiseWithHeadOnBosuBall),
            17 => Some(HipRaiseExerciseName::HipRaiseWithHeadOnSwissBall),
            18 => Some(HipRaiseExerciseName::WeightedHipRaiseWithHeadOnSwissBall),
            19 => Some(HipRaiseExerciseName::HipRaiseWithKneeSqueeze),
            20 => Some(HipRaiseExerciseName::WeightedHipRaiseWithKneeSqueeze),
            21 => Some(HipRaiseExerciseName::InclineRearLegExtension),
            22 => Some(HipRaiseExerciseName::WeightedInclineRearLegExtension),
            23 => Some(HipRaiseExerciseName::KettlebellSwing),
            24 => Some(HipRaiseExerciseName::MarchingHipRaise),
            25 => Some(HipRaiseExerciseName::WeightedMarchingHipRaise),
            26 => Some(HipRaiseExerciseName::MarchingHipRaiseWithFeetOnASwissBall),
            27 => Some(HipRaiseExerciseName::WeightedMarchingHipRaiseWithFeetOnASwissBall),
            28 => Some(HipRaiseExerciseName::ReverseHipRaise),
            29 => Some(HipRaiseExerciseName::WeightedReverseHipRaise),
            30 => Some(HipRaiseExerciseName::SingleLegHipRaise),
            31 => Some(HipRaiseExerciseName::WeightedSingleLegHipRaise),
            32 => Some(HipRaiseExerciseName::SingleLegHipRaiseWithFootOnBench),
            33 => Some(HipRaiseExerciseName::WeightedSingleLegHipRaiseWithFootOnBench),
            34 => Some(HipRaiseExerciseName::SingleLegHipRaiseWithFootOnBosuBall),
            35 => Some(HipRaiseExerciseName::WeightedSingleLegHipRaiseWithFootOnBosuBall),
            36 => Some(HipRaiseExerciseName::SingleLegHipRaiseWithFootOnFoamRoller),
            37 => Some(HipRaiseExerciseName::WeightedSingleLegHipRaiseWithFootOnFoamRoller),
            38 => Some(HipRaiseExerciseName::SingleLegHipRaiseWithFootOnMedicineBall),
            39 => Some(HipRaiseExerciseName::WeightedSingleLegHipRaiseWithFootOnMedicineBall),
            40 => Some(HipRaiseExerciseName::SingleLegHipRaiseWithHeadOnBosuBall),
            41 => Some(HipRaiseExerciseName::WeightedSingleLegHipRaiseWithHeadOnBosuBall),
            42 => Some(HipRaiseExerciseName::WeightedClamBridge),
            43 => Some(HipRaiseExerciseName::SingleLegSwissBallHipRaiseAndLegCurl),
            44 => Some(HipRaiseExerciseName::Clams),
            45 => Some(HipRaiseExerciseName::InnerThighCircles),
            46 => Some(HipRaiseExerciseName::InnerThighSideLift),
            47 => Some(HipRaiseExerciseName::LegCircles),
            48 => Some(HipRaiseExerciseName::LegLift),
            49 => Some(HipRaiseExerciseName::LegLiftInExternalRotation),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "barbell_hip_thrust_on_floor" => Some(HipRaiseExerciseName::BarbellHipThrustOnFloor),
            "barbell_hip_thrust_with_bench" => {
                Some(HipRaiseExerciseName::BarbellHipThrustWithBench)
            }
            "bent_knee_swiss_ball_reverse_hip_raise" => {
                Some(HipRaiseExerciseName::BentKneeSwissBallReverseHipRaise)
            }
            "weighted_bent_knee_swiss_ball_reverse_hip_raise" => {
                Some(HipRaiseExerciseName::WeightedBentKneeSwissBallReverseHipRaise)
            }
            "bridge_with_leg_extension" => Some(HipRaiseExerciseName::BridgeWithLegExtension),
            "weighted_bridge_with_leg_extension" => {
                Some(HipRaiseExerciseName::WeightedBridgeWithLegExtension)
            }
            "clam_bridge" => Some(HipRaiseExerciseName::ClamBridge),
            "front_kick_tabletop" => Some(HipRaiseExerciseName::FrontKickTabletop),
            "weighted_front_kick_tabletop" => Some(HipRaiseExerciseName::WeightedFrontKickTabletop),
            "hip_extension_and_cross" => Some(HipRaiseExerciseName::HipExtensionAndCross),
            "weighted_hip_extension_and_cross" => {
                Some(HipRaiseExerciseName::WeightedHipExtensionAndCross)
            }
            "hip_raise" => Some(HipRaiseExerciseName::HipRaise),
            "weighted_hip_raise" => Some(HipRaiseExerciseName::WeightedHipRaise),
            "hip_raise_with_feet_on_swiss_ball" => {
                Some(HipRaiseExerciseName::HipRaiseWithFeetOnSwissBall)
            }
            "weighted_hip_raise_with_feet_on_swiss_ball" => {
                Some(HipRaiseExerciseName::WeightedHipRaiseWithFeetOnSwissBall)
            }
            "hip_raise_with_head_on_bosu_ball" => {
                Some(HipRaiseExerciseName::HipRaiseWithHeadOnBosuBall)
            }
            "weighted_hip_raise_with_head_on_bosu_ball" => {
                Some(HipRaiseExerciseName::WeightedHipRaiseWithHeadOnBosuBall)
            }
            "hip_raise_with_head_on_swiss_ball" => {
                Some(HipRaiseExerciseName::HipRaiseWithHeadOnSwissBall)
            }
            "weighted_hip_raise_with_head_on_swiss_ball" => {
                Some(HipRaiseExerciseName::WeightedHipRaiseWithHeadOnSwissBall)
            }
            "hip_raise_with_knee_squeeze" => Some(HipRaiseExerciseName::HipRaiseWithKneeSqueeze),
            "weighted_hip_raise_with_knee_squeeze" => {
                Some(HipRaiseExerciseName::WeightedHipRaiseWithKneeSqueeze)
            }
            "incline_rear_leg_extension" => Some(HipRaiseExerciseName::InclineRearLegExtension),
            "weighted_incline_rear_leg_extension" => {
                Some(HipRaiseExerciseName::WeightedInclineRearLegExtension)
            }
            "kettlebell_swing" => Some(HipRaiseExerciseName::KettlebellSwing),
            "marching_hip_raise" => Some(HipRaiseExerciseName::MarchingHipRaise),
            "weighted_marching_hip_raise" => Some(HipRaiseExerciseName::WeightedMarchingHipRaise),
            "marching_hip_raise_with_feet_on_a_swiss_ball" => {
                Some(HipRaiseExerciseName::MarchingHipRaiseWithFeetOnASwissBall)
            }
            "weighted_marching_hip_raise_with_feet_on_a_swiss_ball" => {
                Some(HipRaiseExerciseName::WeightedMarchingHipRaiseWithFeetOnASwissBall)
            }
            "reverse_hip_raise" => Some(HipRaiseExerciseName::ReverseHipRaise),
            "weighted_reverse_hip_raise" => Some(HipRaiseExerciseName::WeightedReverseHipRaise),
            "single_leg_hip_raise" => Some(HipRaiseExerciseName::SingleLegHipRaise),
            "weighted_single_leg_hip_raise" => {
                Some(HipRaiseExerciseName::WeightedSingleLegHipRaise)
            }
            "single_leg_hip_raise_with_foot_on_bench" => {
                Some(HipRaiseExerciseName::SingleLegHipRaiseWithFootOnBench)
            }
            "weighted_single_leg_hip_raise_with_foot_on_bench" => {
                Some(HipRaiseExerciseName::WeightedSingleLegHipRaiseWithFootOnBench)
            }
            "single_leg_hip_raise_with_foot_on_bosu_ball" => {
                Some(HipRaiseExerciseName::SingleLegHipRaiseWithFootOnBosuBall)
            }
            "weighted_single_leg_hip_raise_with_foot_on_bosu_ball" => {
                Some(HipRaiseExerciseName::WeightedSingleLegHipRaiseWithFootOnBosuBall)
            }
            "single_leg_hip_raise_with_foot_on_foam_roller" => {
                Some(HipRaiseExerciseName::SingleLegHipRaiseWithFootOnFoamRoller)
            }
            "weighted_single_leg_hip_raise_with_foot_on_foam_roller" => {
                Some(HipRaiseExerciseName::WeightedSingleLegHipRaiseWithFootOnFoamRoller)
            }
            "single_leg_hip_raise_with_foot_on_medicine_ball" => {
                Some(HipRaiseExerciseName::SingleLegHipRaiseWithFootOnMedicineBall)
            }
            "weighted_single_leg_hip_raise_with_foot_on_medicine_ball" => {
                Some(HipRaiseExerciseName::WeightedSingleLegHipRaiseWithFootOnMedicineBall)
            }
            "single_leg_hip_raise_with_head_on_bosu_ball" => {
                Some(HipRaiseExerciseName::SingleLegHipRaiseWithHeadOnBosuBall)
            }
            "weighted_single_leg_hip_raise_with_head_on_bosu_ball" => {
                Some(HipRaiseExerciseName::WeightedSingleLegHipRaiseWithHeadOnBosuBall)
            }
            "weighted_clam_bridge" => Some(HipRaiseExerciseName::WeightedClamBridge),
            "single_leg_swiss_ball_hip_raise_and_leg_curl" => {
                Some(HipRaiseExerciseName::SingleLegSwissBallHipRaiseAndLegCurl)
            }
            "clams" => Some(HipRaiseExerciseName::Clams),
            "inner_thigh_circles" => Some(HipRaiseExerciseName::InnerThighCircles),
            "inner_thigh_side_lift" => Some(HipRaiseExerciseName::InnerThighSideLift),
            "leg_circles" => Some(HipRaiseExerciseName::LegCircles),
            "leg_lift" => Some(HipRaiseExerciseName::LegLift),
            "leg_lift_in_external_rotation" => {
                Some(HipRaiseExerciseName::LegLiftInExternalRotation)
            }
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum HipStabilityExerciseName {
    BandSideLyingLegRaise = 0,
    DeadBug = 1,
    WeightedDeadBug = 2,
    ExternalHipRaise = 3,
    WeightedExternalHipRaise = 4,
    FireHydrantKicks = 5,
    WeightedFireHydrantKicks = 6,
    HipCircles = 7,
    WeightedHipCircles = 8,
    InnerThighLift = 9,
    WeightedInnerThighLift = 10,
    LateralWalksWithBandAtAnkles = 11,
    PretzelSideKick = 12,
    WeightedPretzelSideKick = 13,
    ProneHipInternalRotation = 14,
    WeightedProneHipInternalRotation = 15,
    Quadruped = 16,
    QuadrupedHipExtension = 17,
    WeightedQuadrupedHipExtension = 18,
    QuadrupedWithLegLift = 19,
    WeightedQuadrupedWithLegLift = 20,
    SideLyingLegRaise = 21,
    WeightedSideLyingLegRaise = 22,
    SlidingHipAdduction = 23,
    WeightedSlidingHipAdduction = 24,
    StandingAdduction = 25,
    WeightedStandingAdduction = 26,
    StandingCableHipAbduction = 27,
    StandingHipAbduction = 28,
    WeightedStandingHipAbduction = 29,
    StandingRearLegRaise = 30,
    WeightedStandingRearLegRaise = 31,
    SupineHipInternalRotation = 32,
    WeightedSupineHipInternalRotation = 33,
    LyingAbductionStretch = 34,
}

impl HipStabilityExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            HipStabilityExerciseName::BandSideLyingLegRaise => "band_side_lying_leg_raise",
            HipStabilityExerciseName::DeadBug => "dead_bug",
            HipStabilityExerciseName::WeightedDeadBug => "weighted_dead_bug",
            HipStabilityExerciseName::ExternalHipRaise => "external_hip_raise",
            HipStabilityExerciseName::WeightedExternalHipRaise => "weighted_external_hip_raise",
            HipStabilityExerciseName::FireHydrantKicks => "fire_hydrant_kicks",
            HipStabilityExerciseName::WeightedFireHydrantKicks => "weighted_fire_hydrant_kicks",
            HipStabilityExerciseName::HipCircles => "hip_circles",
            HipStabilityExerciseName::WeightedHipCircles => "weighted_hip_circles",
            HipStabilityExerciseName::InnerThighLift => "inner_thigh_lift",
            HipStabilityExerciseName::WeightedInnerThighLift => "weighted_inner_thigh_lift",
            HipStabilityExerciseName::LateralWalksWithBandAtAnkles => {
                "lateral_walks_with_band_at_ankles"
            }
            HipStabilityExerciseName::PretzelSideKick => "pretzel_side_kick",
            HipStabilityExerciseName::WeightedPretzelSideKick => "weighted_pretzel_side_kick",
            HipStabilityExerciseName::ProneHipInternalRotation => "prone_hip_internal_rotation",
            HipStabilityExerciseName::WeightedProneHipInternalRotation => {
                "weighted_prone_hip_internal_rotation"
            }
            HipStabilityExerciseName::Quadruped => "quadruped",
            HipStabilityExerciseName::QuadrupedHipExtension => "quadruped_hip_extension",
            HipStabilityExerciseName::WeightedQuadrupedHipExtension => {
                "weighted_quadruped_hip_extension"
            }
            HipStabilityExerciseName::QuadrupedWithLegLift => "quadruped_with_leg_lift",
            HipStabilityExerciseName::WeightedQuadrupedWithLegLift => {
                "weighted_quadruped_with_leg_lift"
            }
            HipStabilityExerciseName::SideLyingLegRaise => "side_lying_leg_raise",
            HipStabilityExerciseName::WeightedSideLyingLegRaise => "weighted_side_lying_leg_raise",
            HipStabilityExerciseName::SlidingHipAdduction => "sliding_hip_adduction",
            HipStabilityExerciseName::WeightedSlidingHipAdduction => {
                "weighted_sliding_hip_adduction"
            }
            HipStabilityExerciseName::StandingAdduction => "standing_adduction",
            HipStabilityExerciseName::WeightedStandingAdduction => "weighted_standing_adduction",
            HipStabilityExerciseName::StandingCableHipAbduction => "standing_cable_hip_abduction",
            HipStabilityExerciseName::StandingHipAbduction => "standing_hip_abduction",
            HipStabilityExerciseName::WeightedStandingHipAbduction => {
                "weighted_standing_hip_abduction"
            }
            HipStabilityExerciseName::StandingRearLegRaise => "standing_rear_leg_raise",
            HipStabilityExerciseName::WeightedStandingRearLegRaise => {
                "weighted_standing_rear_leg_raise"
            }
            HipStabilityExerciseName::SupineHipInternalRotation => "supine_hip_internal_rotation",
            HipStabilityExerciseName::WeightedSupineHipInternalRotation => {
                "weighted_supine_hip_internal_rotation"
            }
            HipStabilityExerciseName::LyingAbductionStretch => "lying_abduction_stretch",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(HipStabilityExerciseName::BandSideLyingLegRaise),
            1 => Some(HipStabilityExerciseName::DeadBug),
            2 => Some(HipStabilityExerciseName::WeightedDeadBug),
            3 => Some(HipStabilityExerciseName::ExternalHipRaise),
            4 => Some(HipStabilityExerciseName::WeightedExternalHipRaise),
            5 => Some(HipStabilityExerciseName::FireHydrantKicks),
            6 => Some(HipStabilityExerciseName::WeightedFireHydrantKicks),
            7 => Some(HipStabilityExerciseName::HipCircles),
            8 => Some(HipStabilityExerciseName::WeightedHipCircles),
            9 => Some(HipStabilityExerciseName::InnerThighLift),
            10 => Some(HipStabilityExerciseName::WeightedInnerThighLift),
            11 => Some(HipStabilityExerciseName::LateralWalksWithBandAtAnkles),
            12 => Some(HipStabilityExerciseName::PretzelSideKick),
            13 => Some(HipStabilityExerciseName::WeightedPretzelSideKick),
            14 => Some(HipStabilityExerciseName::ProneHipInternalRotation),
            15 => Some(HipStabilityExerciseName::WeightedProneHipInternalRotation),
            16 => Some(HipStabilityExerciseName::Quadruped),
            17 => Some(HipStabilityExerciseName::QuadrupedHipExtension),
            18 => Some(HipStabilityExerciseName::WeightedQuadrupedHipExtension),
            19 => Some(HipStabilityExerciseName::QuadrupedWithLegLift),
            20 => Some(HipStabilityExerciseName::WeightedQuadrupedWithLegLift),
            21 => Some(HipStabilityExerciseName::SideLyingLegRaise),
            22 => Some(HipStabilityExerciseName::WeightedSideLyingLegRaise),
            23 => Some(HipStabilityExerciseName::SlidingHipAdduction),
            24 => Some(HipStabilityExerciseName::WeightedSlidingHipAdduction),
            25 => Some(HipStabilityExerciseName::StandingAdduction),
            26 => Some(HipStabilityExerciseName::WeightedStandingAdduction),
            27 => Some(HipStabilityExerciseName::StandingCableHipAbduction),
            28 => Some(HipStabilityExerciseName::StandingHipAbduction),
            29 => Some(HipStabilityExerciseName::WeightedStandingHipAbduction),
            30 => Some(HipStabilityExerciseName::StandingRearLegRaise),
            31 => Some(HipStabilityExerciseName::WeightedStandingRearLegRaise),
            32 => Some(HipStabilityExerciseName::SupineHipInternalRotation),
            33 => Some(HipStabilityExerciseName::WeightedSupineHipInternalRotation),
            34 => Some(HipStabilityExerciseName::LyingAbductionStretch),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "band_side_lying_leg_raise" => Some(HipStabilityExerciseName::BandSideLyingLegRaise),
            "dead_bug" => Some(HipStabilityExerciseName::DeadBug),
            "weighted_dead_bug" => Some(HipStabilityExerciseName::WeightedDeadBug),
            "external_hip_raise" => Some(HipStabilityExerciseName::ExternalHipRaise),
            "weighted_external_hip_raise" => {
                Some(HipStabilityExerciseName::WeightedExternalHipRaise)
            }
            "fire_hydrant_kicks" => Some(HipStabilityExerciseName::FireHydrantKicks),
            "weighted_fire_hydrant_kicks" => {
                Some(HipStabilityExerciseName::WeightedFireHydrantKicks)
            }
            "hip_circles" => Some(HipStabilityExerciseName::HipCircles),
            "weighted_hip_circles" => Some(HipStabilityExerciseName::WeightedHipCircles),
            "inner_thigh_lift" => Some(HipStabilityExerciseName::InnerThighLift),
            "weighted_inner_thigh_lift" => Some(HipStabilityExerciseName::WeightedInnerThighLift),
            "lateral_walks_with_band_at_ankles" => {
                Some(HipStabilityExerciseName::LateralWalksWithBandAtAnkles)
            }
            "pretzel_side_kick" => Some(HipStabilityExerciseName::PretzelSideKick),
            "weighted_pretzel_side_kick" => Some(HipStabilityExerciseName::WeightedPretzelSideKick),
            "prone_hip_internal_rotation" => {
                Some(HipStabilityExerciseName::ProneHipInternalRotation)
            }
            "weighted_prone_hip_internal_rotation" => {
                Some(HipStabilityExerciseName::WeightedProneHipInternalRotation)
            }
            "quadruped" => Some(HipStabilityExerciseName::Quadruped),
            "quadruped_hip_extension" => Some(HipStabilityExerciseName::QuadrupedHipExtension),
            "weighted_quadruped_hip_extension" => {
                Some(HipStabilityExerciseName::WeightedQuadrupedHipExtension)
            }
            "quadruped_with_leg_lift" => Some(HipStabilityExerciseName::QuadrupedWithLegLift),
            "weighted_quadruped_with_leg_lift" => {
                Some(HipStabilityExerciseName::WeightedQuadrupedWithLegLift)
            }
            "side_lying_leg_raise" => Some(HipStabilityExerciseName::SideLyingLegRaise),
            "weighted_side_lying_leg_raise" => {
                Some(HipStabilityExerciseName::WeightedSideLyingLegRaise)
            }
            "sliding_hip_adduction" => Some(HipStabilityExerciseName::SlidingHipAdduction),
            "weighted_sliding_hip_adduction" => {
                Some(HipStabilityExerciseName::WeightedSlidingHipAdduction)
            }
            "standing_adduction" => Some(HipStabilityExerciseName::StandingAdduction),
            "weighted_standing_adduction" => {
                Some(HipStabilityExerciseName::WeightedStandingAdduction)
            }
            "standing_cable_hip_abduction" => {
                Some(HipStabilityExerciseName::StandingCableHipAbduction)
            }
            "standing_hip_abduction" => Some(HipStabilityExerciseName::StandingHipAbduction),
            "weighted_standing_hip_abduction" => {
                Some(HipStabilityExerciseName::WeightedStandingHipAbduction)
            }
            "standing_rear_leg_raise" => Some(HipStabilityExerciseName::StandingRearLegRaise),
            "weighted_standing_rear_leg_raise" => {
                Some(HipStabilityExerciseName::WeightedStandingRearLegRaise)
            }
            "supine_hip_internal_rotation" => {
                Some(HipStabilityExerciseName::SupineHipInternalRotation)
            }
            "weighted_supine_hip_internal_rotation" => {
                Some(HipStabilityExerciseName::WeightedSupineHipInternalRotation)
            }
            "lying_abduction_stretch" => Some(HipStabilityExerciseName::LyingAbductionStretch),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum HipSwingExerciseName {
    SingleArmKettlebellSwing = 0,
    SingleArmDumbbellSwing = 1,
    StepOutSwing = 2,
    OneArmSwing = 3,
}

impl HipSwingExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            HipSwingExerciseName::SingleArmKettlebellSwing => "single_arm_kettlebell_swing",
            HipSwingExerciseName::SingleArmDumbbellSwing => "single_arm_dumbbell_swing",
            HipSwingExerciseName::StepOutSwing => "step_out_swing",
            HipSwingExerciseName::OneArmSwing => "one_arm_swing",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(HipSwingExerciseName::SingleArmKettlebellSwing),
            1 => Some(HipSwingExerciseName::SingleArmDumbbellSwing),
            2 => Some(HipSwingExerciseName::StepOutSwing),
            3 => Some(HipSwingExerciseName::OneArmSwing),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "single_arm_kettlebell_swing" => Some(HipSwingExerciseName::SingleArmKettlebellSwing),
            "single_arm_dumbbell_swing" => Some(HipSwingExerciseName::SingleArmDumbbellSwing),
            "step_out_swing" => Some(HipSwingExerciseName::StepOutSwing),
            "one_arm_swing" => Some(HipSwingExerciseName::OneArmSwing),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum HyperextensionExerciseName {
    BackExtensionWithOppositeArmAndLegReach = 0,
    WeightedBackExtensionWithOppositeArmAndLegReach = 1,
    BaseRotations = 2,
    WeightedBaseRotations = 3,
    BentKneeReverseHyperextension = 4,
    WeightedBentKneeReverseHyperextension = 5,
    HollowHoldAndRoll = 6,
    WeightedHollowHoldAndRoll = 7,
    Kicks = 8,
    WeightedKicks = 9,
    KneeRaises = 10,
    WeightedKneeRaises = 11,
    KneelingSuperman = 12,
    WeightedKneelingSuperman = 13,
    LatPullDownWithRow = 14,
    MedicineBallDeadliftToReach = 15,
    OneArmOneLegRow = 16,
    OneArmRowWithBand = 17,
    OverheadLungeWithMedicineBall = 18,
    PlankKneeTucks = 19,
    WeightedPlankKneeTucks = 20,
    SideStep = 21,
    WeightedSideStep = 22,
    SingleLegBackExtension = 23,
    WeightedSingleLegBackExtension = 24,
    SpineExtension = 25,
    WeightedSpineExtension = 26,
    StaticBackExtension = 27,
    WeightedStaticBackExtension = 28,
    SupermanFromFloor = 29,
    WeightedSupermanFromFloor = 30,
    SwissBallBackExtension = 31,
    WeightedSwissBallBackExtension = 32,
    SwissBallHyperextension = 33,
    WeightedSwissBallHyperextension = 34,
    SwissBallOppositeArmAndLegLift = 35,
    WeightedSwissBallOppositeArmAndLegLift = 36,
    SupermanOnSwissBall = 37,
    Cobra = 38,
    SupineFloorBarre = 39,
}

impl HyperextensionExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            HyperextensionExerciseName::BackExtensionWithOppositeArmAndLegReach => {
                "back_extension_with_opposite_arm_and_leg_reach"
            }
            HyperextensionExerciseName::WeightedBackExtensionWithOppositeArmAndLegReach => {
                "weighted_back_extension_with_opposite_arm_and_leg_reach"
            }
            HyperextensionExerciseName::BaseRotations => "base_rotations",
            HyperextensionExerciseName::WeightedBaseRotations => "weighted_base_rotations",
            HyperextensionExerciseName::BentKneeReverseHyperextension => {
                "bent_knee_reverse_hyperextension"
            }
            HyperextensionExerciseName::WeightedBentKneeReverseHyperextension => {
                "weighted_bent_knee_reverse_hyperextension"
            }
            HyperextensionExerciseName::HollowHoldAndRoll => "hollow_hold_and_roll",
            HyperextensionExerciseName::WeightedHollowHoldAndRoll => {
                "weighted_hollow_hold_and_roll"
            }
            HyperextensionExerciseName::Kicks => "kicks",
            HyperextensionExerciseName::WeightedKicks => "weighted_kicks",
            HyperextensionExerciseName::KneeRaises => "knee_raises",
            HyperextensionExerciseName::WeightedKneeRaises => "weighted_knee_raises",
            HyperextensionExerciseName::KneelingSuperman => "kneeling_superman",
            HyperextensionExerciseName::WeightedKneelingSuperman => "weighted_kneeling_superman",
            HyperextensionExerciseName::LatPullDownWithRow => "lat_pull_down_with_row",
            HyperextensionExerciseName::MedicineBallDeadliftToReach => {
                "medicine_ball_deadlift_to_reach"
            }
            HyperextensionExerciseName::OneArmOneLegRow => "one_arm_one_leg_row",
            HyperextensionExerciseName::OneArmRowWithBand => "one_arm_row_with_band",
            HyperextensionExerciseName::OverheadLungeWithMedicineBall => {
                "overhead_lunge_with_medicine_ball"
            }
            HyperextensionExerciseName::PlankKneeTucks => "plank_knee_tucks",
            HyperextensionExerciseName::WeightedPlankKneeTucks => "weighted_plank_knee_tucks",
            HyperextensionExerciseName::SideStep => "side_step",
            HyperextensionExerciseName::WeightedSideStep => "weighted_side_step",
            HyperextensionExerciseName::SingleLegBackExtension => "single_leg_back_extension",
            HyperextensionExerciseName::WeightedSingleLegBackExtension => {
                "weighted_single_leg_back_extension"
            }
            HyperextensionExerciseName::SpineExtension => "spine_extension",
            HyperextensionExerciseName::WeightedSpineExtension => "weighted_spine_extension",
            HyperextensionExerciseName::StaticBackExtension => "static_back_extension",
            HyperextensionExerciseName::WeightedStaticBackExtension => {
                "weighted_static_back_extension"
            }
            HyperextensionExerciseName::SupermanFromFloor => "superman_from_floor",
            HyperextensionExerciseName::WeightedSupermanFromFloor => "weighted_superman_from_floor",
            HyperextensionExerciseName::SwissBallBackExtension => "swiss_ball_back_extension",
            HyperextensionExerciseName::WeightedSwissBallBackExtension => {
                "weighted_swiss_ball_back_extension"
            }
            HyperextensionExerciseName::SwissBallHyperextension => "swiss_ball_hyperextension",
            HyperextensionExerciseName::WeightedSwissBallHyperextension => {
                "weighted_swiss_ball_hyperextension"
            }
            HyperextensionExerciseName::SwissBallOppositeArmAndLegLift => {
                "swiss_ball_opposite_arm_and_leg_lift"
            }
            HyperextensionExerciseName::WeightedSwissBallOppositeArmAndLegLift => {
                "weighted_swiss_ball_opposite_arm_and_leg_lift"
            }
            HyperextensionExerciseName::SupermanOnSwissBall => "superman_on_swiss_ball",
            HyperextensionExerciseName::Cobra => "cobra",
            HyperextensionExerciseName::SupineFloorBarre => "supine_floor_barre",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(HyperextensionExerciseName::BackExtensionWithOppositeArmAndLegReach),
            1 => Some(HyperextensionExerciseName::WeightedBackExtensionWithOppositeArmAndLegReach),
            2 => Some(HyperextensionExerciseName::BaseRotations),
            3 => Some(HyperextensionExerciseName::WeightedBaseRotations),
            4 => Some(HyperextensionExerciseName::BentKneeReverseHyperextension),
            5 => Some(HyperextensionExerciseName::WeightedBentKneeReverseHyperextension),
            6 => Some(HyperextensionExerciseName::HollowHoldAndRoll),
            7 => Some(HyperextensionExerciseName::WeightedHollowHoldAndRoll),
            8 => Some(HyperextensionExerciseName::Kicks),
            9 => Some(HyperextensionExerciseName::WeightedKicks),
            10 => Some(HyperextensionExerciseName::KneeRaises),
            11 => Some(HyperextensionExerciseName::WeightedKneeRaises),
            12 => Some(HyperextensionExerciseName::KneelingSuperman),
            13 => Some(HyperextensionExerciseName::WeightedKneelingSuperman),
            14 => Some(HyperextensionExerciseName::LatPullDownWithRow),
            15 => Some(HyperextensionExerciseName::MedicineBallDeadliftToReach),
            16 => Some(HyperextensionExerciseName::OneArmOneLegRow),
            17 => Some(HyperextensionExerciseName::OneArmRowWithBand),
            18 => Some(HyperextensionExerciseName::OverheadLungeWithMedicineBall),
            19 => Some(HyperextensionExerciseName::PlankKneeTucks),
            20 => Some(HyperextensionExerciseName::WeightedPlankKneeTucks),
            21 => Some(HyperextensionExerciseName::SideStep),
            22 => Some(HyperextensionExerciseName::WeightedSideStep),
            23 => Some(HyperextensionExerciseName::SingleLegBackExtension),
            24 => Some(HyperextensionExerciseName::WeightedSingleLegBackExtension),
            25 => Some(HyperextensionExerciseName::SpineExtension),
            26 => Some(HyperextensionExerciseName::WeightedSpineExtension),
            27 => Some(HyperextensionExerciseName::StaticBackExtension),
            28 => Some(HyperextensionExerciseName::WeightedStaticBackExtension),
            29 => Some(HyperextensionExerciseName::SupermanFromFloor),
            30 => Some(HyperextensionExerciseName::WeightedSupermanFromFloor),
            31 => Some(HyperextensionExerciseName::SwissBallBackExtension),
            32 => Some(HyperextensionExerciseName::WeightedSwissBallBackExtension),
            33 => Some(HyperextensionExerciseName::SwissBallHyperextension),
            34 => Some(HyperextensionExerciseName::WeightedSwissBallHyperextension),
            35 => Some(HyperextensionExerciseName::SwissBallOppositeArmAndLegLift),
            36 => Some(HyperextensionExerciseName::WeightedSwissBallOppositeArmAndLegLift),
            37 => Some(HyperextensionExerciseName::SupermanOnSwissBall),
            38 => Some(HyperextensionExerciseName::Cobra),
            39 => Some(HyperextensionExerciseName::SupineFloorBarre),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "back_extension_with_opposite_arm_and_leg_reach" => {
                Some(HyperextensionExerciseName::BackExtensionWithOppositeArmAndLegReach)
            }
            "weighted_back_extension_with_opposite_arm_and_leg_reach" => {
                Some(HyperextensionExerciseName::WeightedBackExtensionWithOppositeArmAndLegReach)
            }
            "base_rotations" => Some(HyperextensionExerciseName::BaseRotations),
            "weighted_base_rotations" => Some(HyperextensionExerciseName::WeightedBaseRotations),
            "bent_knee_reverse_hyperextension" => {
                Some(HyperextensionExerciseName::BentKneeReverseHyperextension)
            }
            "weighted_bent_knee_reverse_hyperextension" => {
                Some(HyperextensionExerciseName::WeightedBentKneeReverseHyperextension)
            }
            "hollow_hold_and_roll" => Some(HyperextensionExerciseName::HollowHoldAndRoll),
            "weighted_hollow_hold_and_roll" => {
                Some(HyperextensionExerciseName::WeightedHollowHoldAndRoll)
            }
            "kicks" => Some(HyperextensionExerciseName::Kicks),
            "weighted_kicks" => Some(HyperextensionExerciseName::WeightedKicks),
            "knee_raises" => Some(HyperextensionExerciseName::KneeRaises),
            "weighted_knee_raises" => Some(HyperextensionExerciseName::WeightedKneeRaises),
            "kneeling_superman" => Some(HyperextensionExerciseName::KneelingSuperman),
            "weighted_kneeling_superman" => {
                Some(HyperextensionExerciseName::WeightedKneelingSuperman)
            }
            "lat_pull_down_with_row" => Some(HyperextensionExerciseName::LatPullDownWithRow),
            "medicine_ball_deadlift_to_reach" => {
                Some(HyperextensionExerciseName::MedicineBallDeadliftToReach)
            }
            "one_arm_one_leg_row" => Some(HyperextensionExerciseName::OneArmOneLegRow),
            "one_arm_row_with_band" => Some(HyperextensionExerciseName::OneArmRowWithBand),
            "overhead_lunge_with_medicine_ball" => {
                Some(HyperextensionExerciseName::OverheadLungeWithMedicineBall)
            }
            "plank_knee_tucks" => Some(HyperextensionExerciseName::PlankKneeTucks),
            "weighted_plank_knee_tucks" => Some(HyperextensionExerciseName::WeightedPlankKneeTucks),
            "side_step" => Some(HyperextensionExerciseName::SideStep),
            "weighted_side_step" => Some(HyperextensionExerciseName::WeightedSideStep),
            "single_leg_back_extension" => Some(HyperextensionExerciseName::SingleLegBackExtension),
            "weighted_single_leg_back_extension" => {
                Some(HyperextensionExerciseName::WeightedSingleLegBackExtension)
            }
            "spine_extension" => Some(HyperextensionExerciseName::SpineExtension),
            "weighted_spine_extension" => Some(HyperextensionExerciseName::WeightedSpineExtension),
            "static_back_extension" => Some(HyperextensionExerciseName::StaticBackExtension),
            "weighted_static_back_extension" => {
                Some(HyperextensionExerciseName::WeightedStaticBackExtension)
            }
            "superman_from_floor" => Some(HyperextensionExerciseName::SupermanFromFloor),
            "weighted_superman_from_floor" => {
                Some(HyperextensionExerciseName::WeightedSupermanFromFloor)
            }
            "swiss_ball_back_extension" => Some(HyperextensionExerciseName::SwissBallBackExtension),
            "weighted_swiss_ball_back_extension" => {
                Some(HyperextensionExerciseName::WeightedSwissBallBackExtension)
            }
            "swiss_ball_hyperextension" => {
                Some(HyperextensionExerciseName::SwissBallHyperextension)
            }
            "weighted_swiss_ball_hyperextension" => {
                Some(HyperextensionExerciseName::WeightedSwissBallHyperextension)
            }
            "swiss_ball_opposite_arm_and_leg_lift" => {
                Some(HyperextensionExerciseName::SwissBallOppositeArmAndLegLift)
            }
            "weighted_swiss_ball_opposite_arm_and_leg_lift" => {
                Some(HyperextensionExerciseName::WeightedSwissBallOppositeArmAndLegLift)
            }
            "superman_on_swiss_ball" => Some(HyperextensionExerciseName::SupermanOnSwissBall),
            "cobra" => Some(HyperextensionExerciseName::Cobra),
            "supine_floor_barre" => Some(HyperextensionExerciseName::SupineFloorBarre),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum LateralRaiseExerciseName {
    _45DegreeCableExternalRotation = 0,
    AlternatingLateralRaiseWithStaticHold = 1,
    BarMuscleUp = 2,
    BentOverLateralRaise = 3,
    CableDiagonalRaise = 4,
    CableFrontRaise = 5,
    CalorieRow = 6,
    ComboShoulderRaise = 7,
    DumbbellDiagonalRaise = 8,
    DumbbellVRaise = 9,
    FrontRaise = 10,
    LeaningDumbbellLateralRaise = 11,
    LyingDumbbellRaise = 12,
    MuscleUp = 13,
    OneArmCableLateralRaise = 14,
    OverhandGripRearLateralRaise = 15,
    PlateRaises = 16,
    RingDip = 17,
    WeightedRingDip = 18,
    RingMuscleUp = 19,
    WeightedRingMuscleUp = 20,
    RopeClimb = 21,
    WeightedRopeClimb = 22,
    Scaption = 23,
    SeatedLateralRaise = 24,
    SeatedRearLateralRaise = 25,
    SideLyingLateralRaise = 26,
    StandingLift = 27,
    SuspendedRow = 28,
    UnderhandGripRearLateralRaise = 29,
    WallSlide = 30,
    WeightedWallSlide = 31,
    ArmCircles = 32,
    ShavingTheHead = 33,
    DumbbellLateralRaise = 34,
    RingDipKipping = 36,
    WallWalk = 37,
    DumbbellFrontRaiseWheelchair = 38,
    DumbbellLateralRaiseWheelchair = 39,
    PoleDoubleArmOverheadAndForwardWheelchair = 40,
    PoleStraightArmOverheadWheelchair = 41,
}

impl LateralRaiseExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            LateralRaiseExerciseName::_45DegreeCableExternalRotation => {
                "45_degree_cable_external_rotation"
            }
            LateralRaiseExerciseName::AlternatingLateralRaiseWithStaticHold => {
                "alternating_lateral_raise_with_static_hold"
            }
            LateralRaiseExerciseName::BarMuscleUp => "bar_muscle_up",
            LateralRaiseExerciseName::BentOverLateralRaise => "bent_over_lateral_raise",
            LateralRaiseExerciseName::CableDiagonalRaise => "cable_diagonal_raise",
            LateralRaiseExerciseName::CableFrontRaise => "cable_front_raise",
            LateralRaiseExerciseName::CalorieRow => "calorie_row",
            LateralRaiseExerciseName::ComboShoulderRaise => "combo_shoulder_raise",
            LateralRaiseExerciseName::DumbbellDiagonalRaise => "dumbbell_diagonal_raise",
            LateralRaiseExerciseName::DumbbellVRaise => "dumbbell_v_raise",
            LateralRaiseExerciseName::FrontRaise => "front_raise",
            LateralRaiseExerciseName::LeaningDumbbellLateralRaise => {
                "leaning_dumbbell_lateral_raise"
            }
            LateralRaiseExerciseName::LyingDumbbellRaise => "lying_dumbbell_raise",
            LateralRaiseExerciseName::MuscleUp => "muscle_up",
            LateralRaiseExerciseName::OneArmCableLateralRaise => "one_arm_cable_lateral_raise",
            LateralRaiseExerciseName::OverhandGripRearLateralRaise => {
                "overhand_grip_rear_lateral_raise"
            }
            LateralRaiseExerciseName::PlateRaises => "plate_raises",
            LateralRaiseExerciseName::RingDip => "ring_dip",
            LateralRaiseExerciseName::WeightedRingDip => "weighted_ring_dip",
            LateralRaiseExerciseName::RingMuscleUp => "ring_muscle_up",
            LateralRaiseExerciseName::WeightedRingMuscleUp => "weighted_ring_muscle_up",
            LateralRaiseExerciseName::RopeClimb => "rope_climb",
            LateralRaiseExerciseName::WeightedRopeClimb => "weighted_rope_climb",
            LateralRaiseExerciseName::Scaption => "scaption",
            LateralRaiseExerciseName::SeatedLateralRaise => "seated_lateral_raise",
            LateralRaiseExerciseName::SeatedRearLateralRaise => "seated_rear_lateral_raise",
            LateralRaiseExerciseName::SideLyingLateralRaise => "side_lying_lateral_raise",
            LateralRaiseExerciseName::StandingLift => "standing_lift",
            LateralRaiseExerciseName::SuspendedRow => "suspended_row",
            LateralRaiseExerciseName::UnderhandGripRearLateralRaise => {
                "underhand_grip_rear_lateral_raise"
            }
            LateralRaiseExerciseName::WallSlide => "wall_slide",
            LateralRaiseExerciseName::WeightedWallSlide => "weighted_wall_slide",
            LateralRaiseExerciseName::ArmCircles => "arm_circles",
            LateralRaiseExerciseName::ShavingTheHead => "shaving_the_head",
            LateralRaiseExerciseName::DumbbellLateralRaise => "dumbbell_lateral_raise",
            LateralRaiseExerciseName::RingDipKipping => "ring_dip_kipping",
            LateralRaiseExerciseName::WallWalk => "wall_walk",
            LateralRaiseExerciseName::DumbbellFrontRaiseWheelchair => {
                "dumbbell_front_raise_wheelchair"
            }
            LateralRaiseExerciseName::DumbbellLateralRaiseWheelchair => {
                "dumbbell_lateral_raise_wheelchair"
            }
            LateralRaiseExerciseName::PoleDoubleArmOverheadAndForwardWheelchair => {
                "pole_double_arm_overhead_and_forward_wheelchair"
            }
            LateralRaiseExerciseName::PoleStraightArmOverheadWheelchair => {
                "pole_straight_arm_overhead_wheelchair"
            }
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(LateralRaiseExerciseName::_45DegreeCableExternalRotation),
            1 => Some(LateralRaiseExerciseName::AlternatingLateralRaiseWithStaticHold),
            2 => Some(LateralRaiseExerciseName::BarMuscleUp),
            3 => Some(LateralRaiseExerciseName::BentOverLateralRaise),
            4 => Some(LateralRaiseExerciseName::CableDiagonalRaise),
            5 => Some(LateralRaiseExerciseName::CableFrontRaise),
            6 => Some(LateralRaiseExerciseName::CalorieRow),
            7 => Some(LateralRaiseExerciseName::ComboShoulderRaise),
            8 => Some(LateralRaiseExerciseName::DumbbellDiagonalRaise),
            9 => Some(LateralRaiseExerciseName::DumbbellVRaise),
            10 => Some(LateralRaiseExerciseName::FrontRaise),
            11 => Some(LateralRaiseExerciseName::LeaningDumbbellLateralRaise),
            12 => Some(LateralRaiseExerciseName::LyingDumbbellRaise),
            13 => Some(LateralRaiseExerciseName::MuscleUp),
            14 => Some(LateralRaiseExerciseName::OneArmCableLateralRaise),
            15 => Some(LateralRaiseExerciseName::OverhandGripRearLateralRaise),
            16 => Some(LateralRaiseExerciseName::PlateRaises),
            17 => Some(LateralRaiseExerciseName::RingDip),
            18 => Some(LateralRaiseExerciseName::WeightedRingDip),
            19 => Some(LateralRaiseExerciseName::RingMuscleUp),
            20 => Some(LateralRaiseExerciseName::WeightedRingMuscleUp),
            21 => Some(LateralRaiseExerciseName::RopeClimb),
            22 => Some(LateralRaiseExerciseName::WeightedRopeClimb),
            23 => Some(LateralRaiseExerciseName::Scaption),
            24 => Some(LateralRaiseExerciseName::SeatedLateralRaise),
            25 => Some(LateralRaiseExerciseName::SeatedRearLateralRaise),
            26 => Some(LateralRaiseExerciseName::SideLyingLateralRaise),
            27 => Some(LateralRaiseExerciseName::StandingLift),
            28 => Some(LateralRaiseExerciseName::SuspendedRow),
            29 => Some(LateralRaiseExerciseName::UnderhandGripRearLateralRaise),
            30 => Some(LateralRaiseExerciseName::WallSlide),
            31 => Some(LateralRaiseExerciseName::WeightedWallSlide),
            32 => Some(LateralRaiseExerciseName::ArmCircles),
            33 => Some(LateralRaiseExerciseName::ShavingTheHead),
            34 => Some(LateralRaiseExerciseName::DumbbellLateralRaise),
            36 => Some(LateralRaiseExerciseName::RingDipKipping),
            37 => Some(LateralRaiseExerciseName::WallWalk),
            38 => Some(LateralRaiseExerciseName::DumbbellFrontRaiseWheelchair),
            39 => Some(LateralRaiseExerciseName::DumbbellLateralRaiseWheelchair),
            40 => Some(LateralRaiseExerciseName::PoleDoubleArmOverheadAndForwardWheelchair),
            41 => Some(LateralRaiseExerciseName::PoleStraightArmOverheadWheelchair),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "45_degree_cable_external_rotation" => {
                Some(LateralRaiseExerciseName::_45DegreeCableExternalRotation)
            }
            "alternating_lateral_raise_with_static_hold" => {
                Some(LateralRaiseExerciseName::AlternatingLateralRaiseWithStaticHold)
            }
            "bar_muscle_up" => Some(LateralRaiseExerciseName::BarMuscleUp),
            "bent_over_lateral_raise" => Some(LateralRaiseExerciseName::BentOverLateralRaise),
            "cable_diagonal_raise" => Some(LateralRaiseExerciseName::CableDiagonalRaise),
            "cable_front_raise" => Some(LateralRaiseExerciseName::CableFrontRaise),
            "calorie_row" => Some(LateralRaiseExerciseName::CalorieRow),
            "combo_shoulder_raise" => Some(LateralRaiseExerciseName::ComboShoulderRaise),
            "dumbbell_diagonal_raise" => Some(LateralRaiseExerciseName::DumbbellDiagonalRaise),
            "dumbbell_v_raise" => Some(LateralRaiseExerciseName::DumbbellVRaise),
            "front_raise" => Some(LateralRaiseExerciseName::FrontRaise),
            "leaning_dumbbell_lateral_raise" => {
                Some(LateralRaiseExerciseName::LeaningDumbbellLateralRaise)
            }
            "lying_dumbbell_raise" => Some(LateralRaiseExerciseName::LyingDumbbellRaise),
            "muscle_up" => Some(LateralRaiseExerciseName::MuscleUp),
            "one_arm_cable_lateral_raise" => {
                Some(LateralRaiseExerciseName::OneArmCableLateralRaise)
            }
            "overhand_grip_rear_lateral_raise" => {
                Some(LateralRaiseExerciseName::OverhandGripRearLateralRaise)
            }
            "plate_raises" => Some(LateralRaiseExerciseName::PlateRaises),
            "ring_dip" => Some(LateralRaiseExerciseName::RingDip),
            "weighted_ring_dip" => Some(LateralRaiseExerciseName::WeightedRingDip),
            "ring_muscle_up" => Some(LateralRaiseExerciseName::RingMuscleUp),
            "weighted_ring_muscle_up" => Some(LateralRaiseExerciseName::WeightedRingMuscleUp),
            "rope_climb" => Some(LateralRaiseExerciseName::RopeClimb),
            "weighted_rope_climb" => Some(LateralRaiseExerciseName::WeightedRopeClimb),
            "scaption" => Some(LateralRaiseExerciseName::Scaption),
            "seated_lateral_raise" => Some(LateralRaiseExerciseName::SeatedLateralRaise),
            "seated_rear_lateral_raise" => Some(LateralRaiseExerciseName::SeatedRearLateralRaise),
            "side_lying_lateral_raise" => Some(LateralRaiseExerciseName::SideLyingLateralRaise),
            "standing_lift" => Some(LateralRaiseExerciseName::StandingLift),
            "suspended_row" => Some(LateralRaiseExerciseName::SuspendedRow),
            "underhand_grip_rear_lateral_raise" => {
                Some(LateralRaiseExerciseName::UnderhandGripRearLateralRaise)
            }
            "wall_slide" => Some(LateralRaiseExerciseName::WallSlide),
            "weighted_wall_slide" => Some(LateralRaiseExerciseName::WeightedWallSlide),
            "arm_circles" => Some(LateralRaiseExerciseName::ArmCircles),
            "shaving_the_head" => Some(LateralRaiseExerciseName::ShavingTheHead),
            "dumbbell_lateral_raise" => Some(LateralRaiseExerciseName::DumbbellLateralRaise),
            "ring_dip_kipping" => Some(LateralRaiseExerciseName::RingDipKipping),
            "wall_walk" => Some(LateralRaiseExerciseName::WallWalk),
            "dumbbell_front_raise_wheelchair" => {
                Some(LateralRaiseExerciseName::DumbbellFrontRaiseWheelchair)
            }
            "dumbbell_lateral_raise_wheelchair" => {
                Some(LateralRaiseExerciseName::DumbbellLateralRaiseWheelchair)
            }
            "pole_double_arm_overhead_and_forward_wheelchair" => {
                Some(LateralRaiseExerciseName::PoleDoubleArmOverheadAndForwardWheelchair)
            }
            "pole_straight_arm_overhead_wheelchair" => {
                Some(LateralRaiseExerciseName::PoleStraightArmOverheadWheelchair)
            }
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum LegCurlExerciseName {
    LegCurl = 0,
    WeightedLegCurl = 1,
    GoodMorning = 2,
    SeatedBarbellGoodMorning = 3,
    SingleLegBarbellGoodMorning = 4,
    SingleLegSlidingLegCurl = 5,
    SlidingLegCurl = 6,
    SplitBarbellGoodMorning = 7,
    SplitStanceExtension = 8,
    StaggeredStanceGoodMorning = 9,
    SwissBallHipRaiseAndLegCurl = 10,
    ZercherGoodMorning = 11,
    BandGoodMorning = 12,
    BarGoodMorning = 13,
}

impl LegCurlExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            LegCurlExerciseName::LegCurl => "leg_curl",
            LegCurlExerciseName::WeightedLegCurl => "weighted_leg_curl",
            LegCurlExerciseName::GoodMorning => "good_morning",
            LegCurlExerciseName::SeatedBarbellGoodMorning => "seated_barbell_good_morning",
            LegCurlExerciseName::SingleLegBarbellGoodMorning => "single_leg_barbell_good_morning",
            LegCurlExerciseName::SingleLegSlidingLegCurl => "single_leg_sliding_leg_curl",
            LegCurlExerciseName::SlidingLegCurl => "sliding_leg_curl",
            LegCurlExerciseName::SplitBarbellGoodMorning => "split_barbell_good_morning",
            LegCurlExerciseName::SplitStanceExtension => "split_stance_extension",
            LegCurlExerciseName::StaggeredStanceGoodMorning => "staggered_stance_good_morning",
            LegCurlExerciseName::SwissBallHipRaiseAndLegCurl => "swiss_ball_hip_raise_and_leg_curl",
            LegCurlExerciseName::ZercherGoodMorning => "zercher_good_morning",
            LegCurlExerciseName::BandGoodMorning => "band_good_morning",
            LegCurlExerciseName::BarGoodMorning => "bar_good_morning",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(LegCurlExerciseName::LegCurl),
            1 => Some(LegCurlExerciseName::WeightedLegCurl),
            2 => Some(LegCurlExerciseName::GoodMorning),
            3 => Some(LegCurlExerciseName::SeatedBarbellGoodMorning),
            4 => Some(LegCurlExerciseName::SingleLegBarbellGoodMorning),
            5 => Some(LegCurlExerciseName::SingleLegSlidingLegCurl),
            6 => Some(LegCurlExerciseName::SlidingLegCurl),
            7 => Some(LegCurlExerciseName::SplitBarbellGoodMorning),
            8 => Some(LegCurlExerciseName::SplitStanceExtension),
            9 => Some(LegCurlExerciseName::StaggeredStanceGoodMorning),
            10 => Some(LegCurlExerciseName::SwissBallHipRaiseAndLegCurl),
            11 => Some(LegCurlExerciseName::ZercherGoodMorning),
            12 => Some(LegCurlExerciseName::BandGoodMorning),
            13 => Some(LegCurlExerciseName::BarGoodMorning),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "leg_curl" => Some(LegCurlExerciseName::LegCurl),
            "weighted_leg_curl" => Some(LegCurlExerciseName::WeightedLegCurl),
            "good_morning" => Some(LegCurlExerciseName::GoodMorning),
            "seated_barbell_good_morning" => Some(LegCurlExerciseName::SeatedBarbellGoodMorning),
            "single_leg_barbell_good_morning" => {
                Some(LegCurlExerciseName::SingleLegBarbellGoodMorning)
            }
            "single_leg_sliding_leg_curl" => Some(LegCurlExerciseName::SingleLegSlidingLegCurl),
            "sliding_leg_curl" => Some(LegCurlExerciseName::SlidingLegCurl),
            "split_barbell_good_morning" => Some(LegCurlExerciseName::SplitBarbellGoodMorning),
            "split_stance_extension" => Some(LegCurlExerciseName::SplitStanceExtension),
            "staggered_stance_good_morning" => {
                Some(LegCurlExerciseName::StaggeredStanceGoodMorning)
            }
            "swiss_ball_hip_raise_and_leg_curl" => {
                Some(LegCurlExerciseName::SwissBallHipRaiseAndLegCurl)
            }
            "zercher_good_morning" => Some(LegCurlExerciseName::ZercherGoodMorning),
            "band_good_morning" => Some(LegCurlExerciseName::BandGoodMorning),
            "bar_good_morning" => Some(LegCurlExerciseName::BarGoodMorning),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum LegRaiseExerciseName {
    HangingKneeRaise = 0,
    HangingLegRaise = 1,
    WeightedHangingLegRaise = 2,
    HangingSingleLegRaise = 3,
    WeightedHangingSingleLegRaise = 4,
    KettlebellLegRaises = 5,
    LegLoweringDrill = 6,
    WeightedLegLoweringDrill = 7,
    LyingStraightLegRaise = 8,
    WeightedLyingStraightLegRaise = 9,
    MedicineBallLegDrops = 10,
    QuadrupedLegRaise = 11,
    WeightedQuadrupedLegRaise = 12,
    ReverseLegRaise = 13,
    WeightedReverseLegRaise = 14,
    ReverseLegRaiseOnSwissBall = 15,
    WeightedReverseLegRaiseOnSwissBall = 16,
    SingleLegLoweringDrill = 17,
    WeightedSingleLegLoweringDrill = 18,
    WeightedHangingKneeRaise = 19,
    LateralStepover = 20,
    WeightedLateralStepover = 21,
}

impl LegRaiseExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            LegRaiseExerciseName::HangingKneeRaise => "hanging_knee_raise",
            LegRaiseExerciseName::HangingLegRaise => "hanging_leg_raise",
            LegRaiseExerciseName::WeightedHangingLegRaise => "weighted_hanging_leg_raise",
            LegRaiseExerciseName::HangingSingleLegRaise => "hanging_single_leg_raise",
            LegRaiseExerciseName::WeightedHangingSingleLegRaise => {
                "weighted_hanging_single_leg_raise"
            }
            LegRaiseExerciseName::KettlebellLegRaises => "kettlebell_leg_raises",
            LegRaiseExerciseName::LegLoweringDrill => "leg_lowering_drill",
            LegRaiseExerciseName::WeightedLegLoweringDrill => "weighted_leg_lowering_drill",
            LegRaiseExerciseName::LyingStraightLegRaise => "lying_straight_leg_raise",
            LegRaiseExerciseName::WeightedLyingStraightLegRaise => {
                "weighted_lying_straight_leg_raise"
            }
            LegRaiseExerciseName::MedicineBallLegDrops => "medicine_ball_leg_drops",
            LegRaiseExerciseName::QuadrupedLegRaise => "quadruped_leg_raise",
            LegRaiseExerciseName::WeightedQuadrupedLegRaise => "weighted_quadruped_leg_raise",
            LegRaiseExerciseName::ReverseLegRaise => "reverse_leg_raise",
            LegRaiseExerciseName::WeightedReverseLegRaise => "weighted_reverse_leg_raise",
            LegRaiseExerciseName::ReverseLegRaiseOnSwissBall => "reverse_leg_raise_on_swiss_ball",
            LegRaiseExerciseName::WeightedReverseLegRaiseOnSwissBall => {
                "weighted_reverse_leg_raise_on_swiss_ball"
            }
            LegRaiseExerciseName::SingleLegLoweringDrill => "single_leg_lowering_drill",
            LegRaiseExerciseName::WeightedSingleLegLoweringDrill => {
                "weighted_single_leg_lowering_drill"
            }
            LegRaiseExerciseName::WeightedHangingKneeRaise => "weighted_hanging_knee_raise",
            LegRaiseExerciseName::LateralStepover => "lateral_stepover",
            LegRaiseExerciseName::WeightedLateralStepover => "weighted_lateral_stepover",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(LegRaiseExerciseName::HangingKneeRaise),
            1 => Some(LegRaiseExerciseName::HangingLegRaise),
            2 => Some(LegRaiseExerciseName::WeightedHangingLegRaise),
            3 => Some(LegRaiseExerciseName::HangingSingleLegRaise),
            4 => Some(LegRaiseExerciseName::WeightedHangingSingleLegRaise),
            5 => Some(LegRaiseExerciseName::KettlebellLegRaises),
            6 => Some(LegRaiseExerciseName::LegLoweringDrill),
            7 => Some(LegRaiseExerciseName::WeightedLegLoweringDrill),
            8 => Some(LegRaiseExerciseName::LyingStraightLegRaise),
            9 => Some(LegRaiseExerciseName::WeightedLyingStraightLegRaise),
            10 => Some(LegRaiseExerciseName::MedicineBallLegDrops),
            11 => Some(LegRaiseExerciseName::QuadrupedLegRaise),
            12 => Some(LegRaiseExerciseName::WeightedQuadrupedLegRaise),
            13 => Some(LegRaiseExerciseName::ReverseLegRaise),
            14 => Some(LegRaiseExerciseName::WeightedReverseLegRaise),
            15 => Some(LegRaiseExerciseName::ReverseLegRaiseOnSwissBall),
            16 => Some(LegRaiseExerciseName::WeightedReverseLegRaiseOnSwissBall),
            17 => Some(LegRaiseExerciseName::SingleLegLoweringDrill),
            18 => Some(LegRaiseExerciseName::WeightedSingleLegLoweringDrill),
            19 => Some(LegRaiseExerciseName::WeightedHangingKneeRaise),
            20 => Some(LegRaiseExerciseName::LateralStepover),
            21 => Some(LegRaiseExerciseName::WeightedLateralStepover),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "hanging_knee_raise" => Some(LegRaiseExerciseName::HangingKneeRaise),
            "hanging_leg_raise" => Some(LegRaiseExerciseName::HangingLegRaise),
            "weighted_hanging_leg_raise" => Some(LegRaiseExerciseName::WeightedHangingLegRaise),
            "hanging_single_leg_raise" => Some(LegRaiseExerciseName::HangingSingleLegRaise),
            "weighted_hanging_single_leg_raise" => {
                Some(LegRaiseExerciseName::WeightedHangingSingleLegRaise)
            }
            "kettlebell_leg_raises" => Some(LegRaiseExerciseName::KettlebellLegRaises),
            "leg_lowering_drill" => Some(LegRaiseExerciseName::LegLoweringDrill),
            "weighted_leg_lowering_drill" => Some(LegRaiseExerciseName::WeightedLegLoweringDrill),
            "lying_straight_leg_raise" => Some(LegRaiseExerciseName::LyingStraightLegRaise),
            "weighted_lying_straight_leg_raise" => {
                Some(LegRaiseExerciseName::WeightedLyingStraightLegRaise)
            }
            "medicine_ball_leg_drops" => Some(LegRaiseExerciseName::MedicineBallLegDrops),
            "quadruped_leg_raise" => Some(LegRaiseExerciseName::QuadrupedLegRaise),
            "weighted_quadruped_leg_raise" => Some(LegRaiseExerciseName::WeightedQuadrupedLegRaise),
            "reverse_leg_raise" => Some(LegRaiseExerciseName::ReverseLegRaise),
            "weighted_reverse_leg_raise" => Some(LegRaiseExerciseName::WeightedReverseLegRaise),
            "reverse_leg_raise_on_swiss_ball" => {
                Some(LegRaiseExerciseName::ReverseLegRaiseOnSwissBall)
            }
            "weighted_reverse_leg_raise_on_swiss_ball" => {
                Some(LegRaiseExerciseName::WeightedReverseLegRaiseOnSwissBall)
            }
            "single_leg_lowering_drill" => Some(LegRaiseExerciseName::SingleLegLoweringDrill),
            "weighted_single_leg_lowering_drill" => {
                Some(LegRaiseExerciseName::WeightedSingleLegLoweringDrill)
            }
            "weighted_hanging_knee_raise" => Some(LegRaiseExerciseName::WeightedHangingKneeRaise),
            "lateral_stepover" => Some(LegRaiseExerciseName::LateralStepover),
            "weighted_lateral_stepover" => Some(LegRaiseExerciseName::WeightedLateralStepover),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum LungeExerciseName {
    OverheadLunge = 0,
    LungeMatrix = 1,
    WeightedLungeMatrix = 2,
    AlternatingBarbellForwardLunge = 3,
    AlternatingDumbbellLungeWithReach = 4,
    BackFootElevatedDumbbellSplitSquat = 5,
    BarbellBoxLunge = 6,
    BarbellBulgarianSplitSquat = 7,
    BarbellCrossoverLunge = 8,
    BarbellFrontSplitSquat = 9,
    BarbellLunge = 10,
    BarbellReverseLunge = 11,
    BarbellSideLunge = 12,
    BarbellSplitSquat = 13,
    CoreControlRearLunge = 14,
    DiagonalLunge = 15,
    DropLunge = 16,
    DumbbellBoxLunge = 17,
    DumbbellBulgarianSplitSquat = 18,
    DumbbellCrossoverLunge = 19,
    DumbbellDiagonalLunge = 20,
    DumbbellLunge = 21,
    DumbbellLungeAndRotation = 22,
    DumbbellOverheadBulgarianSplitSquat = 23,
    DumbbellReverseLungeToHighKneeAndPress = 24,
    DumbbellSideLunge = 25,
    ElevatedFrontFootBarbellSplitSquat = 26,
    FrontFootElevatedDumbbellSplitSquat = 27,
    GunslingerLunge = 28,
    LawnmowerLunge = 29,
    LowLungeWithIsometricAdduction = 30,
    LowSideToSideLunge = 31,
    Lunge = 32,
    WeightedLunge = 33,
    LungeWithArmReach = 34,
    LungeWithDiagonalReach = 35,
    LungeWithSideBend = 36,
    OffsetDumbbellLunge = 37,
    OffsetDumbbellReverseLunge = 38,
    OverheadBulgarianSplitSquat = 39,
    OverheadDumbbellReverseLunge = 40,
    OverheadDumbbellSplitSquat = 41,
    OverheadLungeWithRotation = 42,
    ReverseBarbellBoxLunge = 43,
    ReverseBoxLunge = 44,
    ReverseDumbbellBoxLunge = 45,
    ReverseDumbbellCrossoverLunge = 46,
    ReverseDumbbellDiagonalLunge = 47,
    ReverseLungeWithReachBack = 48,
    WeightedReverseLungeWithReachBack = 49,
    ReverseLungeWithTwistAndOverheadReach = 50,
    WeightedReverseLungeWithTwistAndOverheadReach = 51,
    ReverseSlidingBoxLunge = 52,
    WeightedReverseSlidingBoxLunge = 53,
    ReverseSlidingLunge = 54,
    WeightedReverseSlidingLunge = 55,
    RunnersLungeToBalance = 56,
    WeightedRunnersLungeToBalance = 57,
    ShiftingSideLunge = 58,
    SideAndCrossoverLunge = 59,
    WeightedSideAndCrossoverLunge = 60,
    SideLunge = 61,
    WeightedSideLunge = 62,
    SideLungeAndPress = 63,
    SideLungeJumpOff = 64,
    SideLungeSweep = 65,
    WeightedSideLungeSweep = 66,
    SideLungeToCrossoverTap = 67,
    WeightedSideLungeToCrossoverTap = 68,
    SideToSideLungeChops = 69,
    WeightedSideToSideLungeChops = 70,
    SiffJumpLunge = 71,
    WeightedSiffJumpLunge = 72,
    SingleArmReverseLungeAndPress = 73,
    SlidingLateralLunge = 74,
    WeightedSlidingLateralLunge = 75,
    WalkingBarbellLunge = 76,
    WalkingDumbbellLunge = 77,
    WalkingLunge = 78,
    WeightedWalkingLunge = 79,
    WideGripOverheadBarbellSplitSquat = 80,
    AlternatingDumbbellLunge = 81,
    DumbbellReverseLunge = 82,
    OverheadDumbbellLunge = 83,
    ScissorPowerSwitch = 84,
    DumbbellOverheadWalkingLunge = 85,
    CurtsyLunge = 86,
    WeightedCurtsyLunge = 87,
    WeightedShiftingSideLunge = 88,
    WeightedSideLungeAndPress = 89,
    WeightedSideLungeJumpOff = 90,
}

impl LungeExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            LungeExerciseName::OverheadLunge => "overhead_lunge",
            LungeExerciseName::LungeMatrix => "lunge_matrix",
            LungeExerciseName::WeightedLungeMatrix => "weighted_lunge_matrix",
            LungeExerciseName::AlternatingBarbellForwardLunge => {
                "alternating_barbell_forward_lunge"
            }
            LungeExerciseName::AlternatingDumbbellLungeWithReach => {
                "alternating_dumbbell_lunge_with_reach"
            }
            LungeExerciseName::BackFootElevatedDumbbellSplitSquat => {
                "back_foot_elevated_dumbbell_split_squat"
            }
            LungeExerciseName::BarbellBoxLunge => "barbell_box_lunge",
            LungeExerciseName::BarbellBulgarianSplitSquat => "barbell_bulgarian_split_squat",
            LungeExerciseName::BarbellCrossoverLunge => "barbell_crossover_lunge",
            LungeExerciseName::BarbellFrontSplitSquat => "barbell_front_split_squat",
            LungeExerciseName::BarbellLunge => "barbell_lunge",
            LungeExerciseName::BarbellReverseLunge => "barbell_reverse_lunge",
            LungeExerciseName::BarbellSideLunge => "barbell_side_lunge",
            LungeExerciseName::BarbellSplitSquat => "barbell_split_squat",
            LungeExerciseName::CoreControlRearLunge => "core_control_rear_lunge",
            LungeExerciseName::DiagonalLunge => "diagonal_lunge",
            LungeExerciseName::DropLunge => "drop_lunge",
            LungeExerciseName::DumbbellBoxLunge => "dumbbell_box_lunge",
            LungeExerciseName::DumbbellBulgarianSplitSquat => "dumbbell_bulgarian_split_squat",
            LungeExerciseName::DumbbellCrossoverLunge => "dumbbell_crossover_lunge",
            LungeExerciseName::DumbbellDiagonalLunge => "dumbbell_diagonal_lunge",
            LungeExerciseName::DumbbellLunge => "dumbbell_lunge",
            LungeExerciseName::DumbbellLungeAndRotation => "dumbbell_lunge_and_rotation",
            LungeExerciseName::DumbbellOverheadBulgarianSplitSquat => {
                "dumbbell_overhead_bulgarian_split_squat"
            }
            LungeExerciseName::DumbbellReverseLungeToHighKneeAndPress => {
                "dumbbell_reverse_lunge_to_high_knee_and_press"
            }
            LungeExerciseName::DumbbellSideLunge => "dumbbell_side_lunge",
            LungeExerciseName::ElevatedFrontFootBarbellSplitSquat => {
                "elevated_front_foot_barbell_split_squat"
            }
            LungeExerciseName::FrontFootElevatedDumbbellSplitSquat => {
                "front_foot_elevated_dumbbell_split_squat"
            }
            LungeExerciseName::GunslingerLunge => "gunslinger_lunge",
            LungeExerciseName::LawnmowerLunge => "lawnmower_lunge",
            LungeExerciseName::LowLungeWithIsometricAdduction => {
                "low_lunge_with_isometric_adduction"
            }
            LungeExerciseName::LowSideToSideLunge => "low_side_to_side_lunge",
            LungeExerciseName::Lunge => "lunge",
            LungeExerciseName::WeightedLunge => "weighted_lunge",
            LungeExerciseName::LungeWithArmReach => "lunge_with_arm_reach",
            LungeExerciseName::LungeWithDiagonalReach => "lunge_with_diagonal_reach",
            LungeExerciseName::LungeWithSideBend => "lunge_with_side_bend",
            LungeExerciseName::OffsetDumbbellLunge => "offset_dumbbell_lunge",
            LungeExerciseName::OffsetDumbbellReverseLunge => "offset_dumbbell_reverse_lunge",
            LungeExerciseName::OverheadBulgarianSplitSquat => "overhead_bulgarian_split_squat",
            LungeExerciseName::OverheadDumbbellReverseLunge => "overhead_dumbbell_reverse_lunge",
            LungeExerciseName::OverheadDumbbellSplitSquat => "overhead_dumbbell_split_squat",
            LungeExerciseName::OverheadLungeWithRotation => "overhead_lunge_with_rotation",
            LungeExerciseName::ReverseBarbellBoxLunge => "reverse_barbell_box_lunge",
            LungeExerciseName::ReverseBoxLunge => "reverse_box_lunge",
            LungeExerciseName::ReverseDumbbellBoxLunge => "reverse_dumbbell_box_lunge",
            LungeExerciseName::ReverseDumbbellCrossoverLunge => "reverse_dumbbell_crossover_lunge",
            LungeExerciseName::ReverseDumbbellDiagonalLunge => "reverse_dumbbell_diagonal_lunge",
            LungeExerciseName::ReverseLungeWithReachBack => "reverse_lunge_with_reach_back",
            LungeExerciseName::WeightedReverseLungeWithReachBack => {
                "weighted_reverse_lunge_with_reach_back"
            }
            LungeExerciseName::ReverseLungeWithTwistAndOverheadReach => {
                "reverse_lunge_with_twist_and_overhead_reach"
            }
            LungeExerciseName::WeightedReverseLungeWithTwistAndOverheadReach => {
                "weighted_reverse_lunge_with_twist_and_overhead_reach"
            }
            LungeExerciseName::ReverseSlidingBoxLunge => "reverse_sliding_box_lunge",
            LungeExerciseName::WeightedReverseSlidingBoxLunge => {
                "weighted_reverse_sliding_box_lunge"
            }
            LungeExerciseName::ReverseSlidingLunge => "reverse_sliding_lunge",
            LungeExerciseName::WeightedReverseSlidingLunge => "weighted_reverse_sliding_lunge",
            LungeExerciseName::RunnersLungeToBalance => "runners_lunge_to_balance",
            LungeExerciseName::WeightedRunnersLungeToBalance => "weighted_runners_lunge_to_balance",
            LungeExerciseName::ShiftingSideLunge => "shifting_side_lunge",
            LungeExerciseName::SideAndCrossoverLunge => "side_and_crossover_lunge",
            LungeExerciseName::WeightedSideAndCrossoverLunge => "weighted_side_and_crossover_lunge",
            LungeExerciseName::SideLunge => "side_lunge",
            LungeExerciseName::WeightedSideLunge => "weighted_side_lunge",
            LungeExerciseName::SideLungeAndPress => "side_lunge_and_press",
            LungeExerciseName::SideLungeJumpOff => "side_lunge_jump_off",
            LungeExerciseName::SideLungeSweep => "side_lunge_sweep",
            LungeExerciseName::WeightedSideLungeSweep => "weighted_side_lunge_sweep",
            LungeExerciseName::SideLungeToCrossoverTap => "side_lunge_to_crossover_tap",
            LungeExerciseName::WeightedSideLungeToCrossoverTap => {
                "weighted_side_lunge_to_crossover_tap"
            }
            LungeExerciseName::SideToSideLungeChops => "side_to_side_lunge_chops",
            LungeExerciseName::WeightedSideToSideLungeChops => "weighted_side_to_side_lunge_chops",
            LungeExerciseName::SiffJumpLunge => "siff_jump_lunge",
            LungeExerciseName::WeightedSiffJumpLunge => "weighted_siff_jump_lunge",
            LungeExerciseName::SingleArmReverseLungeAndPress => {
                "single_arm_reverse_lunge_and_press"
            }
            LungeExerciseName::SlidingLateralLunge => "sliding_lateral_lunge",
            LungeExerciseName::WeightedSlidingLateralLunge => "weighted_sliding_lateral_lunge",
            LungeExerciseName::WalkingBarbellLunge => "walking_barbell_lunge",
            LungeExerciseName::WalkingDumbbellLunge => "walking_dumbbell_lunge",
            LungeExerciseName::WalkingLunge => "walking_lunge",
            LungeExerciseName::WeightedWalkingLunge => "weighted_walking_lunge",
            LungeExerciseName::WideGripOverheadBarbellSplitSquat => {
                "wide_grip_overhead_barbell_split_squat"
            }
            LungeExerciseName::AlternatingDumbbellLunge => "alternating_dumbbell_lunge",
            LungeExerciseName::DumbbellReverseLunge => "dumbbell_reverse_lunge",
            LungeExerciseName::OverheadDumbbellLunge => "overhead_dumbbell_lunge",
            LungeExerciseName::ScissorPowerSwitch => "scissor_power_switch",
            LungeExerciseName::DumbbellOverheadWalkingLunge => "dumbbell_overhead_walking_lunge",
            LungeExerciseName::CurtsyLunge => "curtsy_lunge",
            LungeExerciseName::WeightedCurtsyLunge => "weighted_curtsy_lunge",
            LungeExerciseName::WeightedShiftingSideLunge => "weighted_shifting_side_lunge",
            LungeExerciseName::WeightedSideLungeAndPress => "weighted_side_lunge_and_press",
            LungeExerciseName::WeightedSideLungeJumpOff => "weighted_side_lunge_jump_off",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(LungeExerciseName::OverheadLunge),
            1 => Some(LungeExerciseName::LungeMatrix),
            2 => Some(LungeExerciseName::WeightedLungeMatrix),
            3 => Some(LungeExerciseName::AlternatingBarbellForwardLunge),
            4 => Some(LungeExerciseName::AlternatingDumbbellLungeWithReach),
            5 => Some(LungeExerciseName::BackFootElevatedDumbbellSplitSquat),
            6 => Some(LungeExerciseName::BarbellBoxLunge),
            7 => Some(LungeExerciseName::BarbellBulgarianSplitSquat),
            8 => Some(LungeExerciseName::BarbellCrossoverLunge),
            9 => Some(LungeExerciseName::BarbellFrontSplitSquat),
            10 => Some(LungeExerciseName::BarbellLunge),
            11 => Some(LungeExerciseName::BarbellReverseLunge),
            12 => Some(LungeExerciseName::BarbellSideLunge),
            13 => Some(LungeExerciseName::BarbellSplitSquat),
            14 => Some(LungeExerciseName::CoreControlRearLunge),
            15 => Some(LungeExerciseName::DiagonalLunge),
            16 => Some(LungeExerciseName::DropLunge),
            17 => Some(LungeExerciseName::DumbbellBoxLunge),
            18 => Some(LungeExerciseName::DumbbellBulgarianSplitSquat),
            19 => Some(LungeExerciseName::DumbbellCrossoverLunge),
            20 => Some(LungeExerciseName::DumbbellDiagonalLunge),
            21 => Some(LungeExerciseName::DumbbellLunge),
            22 => Some(LungeExerciseName::DumbbellLungeAndRotation),
            23 => Some(LungeExerciseName::DumbbellOverheadBulgarianSplitSquat),
            24 => Some(LungeExerciseName::DumbbellReverseLungeToHighKneeAndPress),
            25 => Some(LungeExerciseName::DumbbellSideLunge),
            26 => Some(LungeExerciseName::ElevatedFrontFootBarbellSplitSquat),
            27 => Some(LungeExerciseName::FrontFootElevatedDumbbellSplitSquat),
            28 => Some(LungeExerciseName::GunslingerLunge),
            29 => Some(LungeExerciseName::LawnmowerLunge),
            30 => Some(LungeExerciseName::LowLungeWithIsometricAdduction),
            31 => Some(LungeExerciseName::LowSideToSideLunge),
            32 => Some(LungeExerciseName::Lunge),
            33 => Some(LungeExerciseName::WeightedLunge),
            34 => Some(LungeExerciseName::LungeWithArmReach),
            35 => Some(LungeExerciseName::LungeWithDiagonalReach),
            36 => Some(LungeExerciseName::LungeWithSideBend),
            37 => Some(LungeExerciseName::OffsetDumbbellLunge),
            38 => Some(LungeExerciseName::OffsetDumbbellReverseLunge),
            39 => Some(LungeExerciseName::OverheadBulgarianSplitSquat),
            40 => Some(LungeExerciseName::OverheadDumbbellReverseLunge),
            41 => Some(LungeExerciseName::OverheadDumbbellSplitSquat),
            42 => Some(LungeExerciseName::OverheadLungeWithRotation),
            43 => Some(LungeExerciseName::ReverseBarbellBoxLunge),
            44 => Some(LungeExerciseName::ReverseBoxLunge),
            45 => Some(LungeExerciseName::ReverseDumbbellBoxLunge),
            46 => Some(LungeExerciseName::ReverseDumbbellCrossoverLunge),
            47 => Some(LungeExerciseName::ReverseDumbbellDiagonalLunge),
            48 => Some(LungeExerciseName::ReverseLungeWithReachBack),
            49 => Some(LungeExerciseName::WeightedReverseLungeWithReachBack),
            50 => Some(LungeExerciseName::ReverseLungeWithTwistAndOverheadReach),
            51 => Some(LungeExerciseName::WeightedReverseLungeWithTwistAndOverheadReach),
            52 => Some(LungeExerciseName::ReverseSlidingBoxLunge),
            53 => Some(LungeExerciseName::WeightedReverseSlidingBoxLunge),
            54 => Some(LungeExerciseName::ReverseSlidingLunge),
            55 => Some(LungeExerciseName::WeightedReverseSlidingLunge),
            56 => Some(LungeExerciseName::RunnersLungeToBalance),
            57 => Some(LungeExerciseName::WeightedRunnersLungeToBalance),
            58 => Some(LungeExerciseName::ShiftingSideLunge),
            59 => Some(LungeExerciseName::SideAndCrossoverLunge),
            60 => Some(LungeExerciseName::WeightedSideAndCrossoverLunge),
            61 => Some(LungeExerciseName::SideLunge),
            62 => Some(LungeExerciseName::WeightedSideLunge),
            63 => Some(LungeExerciseName::SideLungeAndPress),
            64 => Some(LungeExerciseName::SideLungeJumpOff),
            65 => Some(LungeExerciseName::SideLungeSweep),
            66 => Some(LungeExerciseName::WeightedSideLungeSweep),
            67 => Some(LungeExerciseName::SideLungeToCrossoverTap),
            68 => Some(LungeExerciseName::WeightedSideLungeToCrossoverTap),
            69 => Some(LungeExerciseName::SideToSideLungeChops),
            70 => Some(LungeExerciseName::WeightedSideToSideLungeChops),
            71 => Some(LungeExerciseName::SiffJumpLunge),
            72 => Some(LungeExerciseName::WeightedSiffJumpLunge),
            73 => Some(LungeExerciseName::SingleArmReverseLungeAndPress),
            74 => Some(LungeExerciseName::SlidingLateralLunge),
            75 => Some(LungeExerciseName::WeightedSlidingLateralLunge),
            76 => Some(LungeExerciseName::WalkingBarbellLunge),
            77 => Some(LungeExerciseName::WalkingDumbbellLunge),
            78 => Some(LungeExerciseName::WalkingLunge),
            79 => Some(LungeExerciseName::WeightedWalkingLunge),
            80 => Some(LungeExerciseName::WideGripOverheadBarbellSplitSquat),
            81 => Some(LungeExerciseName::AlternatingDumbbellLunge),
            82 => Some(LungeExerciseName::DumbbellReverseLunge),
            83 => Some(LungeExerciseName::OverheadDumbbellLunge),
            84 => Some(LungeExerciseName::ScissorPowerSwitch),
            85 => Some(LungeExerciseName::DumbbellOverheadWalkingLunge),
            86 => Some(LungeExerciseName::CurtsyLunge),
            87 => Some(LungeExerciseName::WeightedCurtsyLunge),
            88 => Some(LungeExerciseName::WeightedShiftingSideLunge),
            89 => Some(LungeExerciseName::WeightedSideLungeAndPress),
            90 => Some(LungeExerciseName::WeightedSideLungeJumpOff),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "overhead_lunge" => Some(LungeExerciseName::OverheadLunge),
            "lunge_matrix" => Some(LungeExerciseName::LungeMatrix),
            "weighted_lunge_matrix" => Some(LungeExerciseName::WeightedLungeMatrix),
            "alternating_barbell_forward_lunge" => {
                Some(LungeExerciseName::AlternatingBarbellForwardLunge)
            }
            "alternating_dumbbell_lunge_with_reach" => {
                Some(LungeExerciseName::AlternatingDumbbellLungeWithReach)
            }
            "back_foot_elevated_dumbbell_split_squat" => {
                Some(LungeExerciseName::BackFootElevatedDumbbellSplitSquat)
            }
            "barbell_box_lunge" => Some(LungeExerciseName::BarbellBoxLunge),
            "barbell_bulgarian_split_squat" => Some(LungeExerciseName::BarbellBulgarianSplitSquat),
            "barbell_crossover_lunge" => Some(LungeExerciseName::BarbellCrossoverLunge),
            "barbell_front_split_squat" => Some(LungeExerciseName::BarbellFrontSplitSquat),
            "barbell_lunge" => Some(LungeExerciseName::BarbellLunge),
            "barbell_reverse_lunge" => Some(LungeExerciseName::BarbellReverseLunge),
            "barbell_side_lunge" => Some(LungeExerciseName::BarbellSideLunge),
            "barbell_split_squat" => Some(LungeExerciseName::BarbellSplitSquat),
            "core_control_rear_lunge" => Some(LungeExerciseName::CoreControlRearLunge),
            "diagonal_lunge" => Some(LungeExerciseName::DiagonalLunge),
            "drop_lunge" => Some(LungeExerciseName::DropLunge),
            "dumbbell_box_lunge" => Some(LungeExerciseName::DumbbellBoxLunge),
            "dumbbell_bulgarian_split_squat" => {
                Some(LungeExerciseName::DumbbellBulgarianSplitSquat)
            }
            "dumbbell_crossover_lunge" => Some(LungeExerciseName::DumbbellCrossoverLunge),
            "dumbbell_diagonal_lunge" => Some(LungeExerciseName::DumbbellDiagonalLunge),
            "dumbbell_lunge" => Some(LungeExerciseName::DumbbellLunge),
            "dumbbell_lunge_and_rotation" => Some(LungeExerciseName::DumbbellLungeAndRotation),
            "dumbbell_overhead_bulgarian_split_squat" => {
                Some(LungeExerciseName::DumbbellOverheadBulgarianSplitSquat)
            }
            "dumbbell_reverse_lunge_to_high_knee_and_press" => {
                Some(LungeExerciseName::DumbbellReverseLungeToHighKneeAndPress)
            }
            "dumbbell_side_lunge" => Some(LungeExerciseName::DumbbellSideLunge),
            "elevated_front_foot_barbell_split_squat" => {
                Some(LungeExerciseName::ElevatedFrontFootBarbellSplitSquat)
            }
            "front_foot_elevated_dumbbell_split_squat" => {
                Some(LungeExerciseName::FrontFootElevatedDumbbellSplitSquat)
            }
            "gunslinger_lunge" => Some(LungeExerciseName::GunslingerLunge),
            "lawnmower_lunge" => Some(LungeExerciseName::LawnmowerLunge),
            "low_lunge_with_isometric_adduction" => {
                Some(LungeExerciseName::LowLungeWithIsometricAdduction)
            }
            "low_side_to_side_lunge" => Some(LungeExerciseName::LowSideToSideLunge),
            "lunge" => Some(LungeExerciseName::Lunge),
            "weighted_lunge" => Some(LungeExerciseName::WeightedLunge),
            "lunge_with_arm_reach" => Some(LungeExerciseName::LungeWithArmReach),
            "lunge_with_diagonal_reach" => Some(LungeExerciseName::LungeWithDiagonalReach),
            "lunge_with_side_bend" => Some(LungeExerciseName::LungeWithSideBend),
            "offset_dumbbell_lunge" => Some(LungeExerciseName::OffsetDumbbellLunge),
            "offset_dumbbell_reverse_lunge" => Some(LungeExerciseName::OffsetDumbbellReverseLunge),
            "overhead_bulgarian_split_squat" => {
                Some(LungeExerciseName::OverheadBulgarianSplitSquat)
            }
            "overhead_dumbbell_reverse_lunge" => {
                Some(LungeExerciseName::OverheadDumbbellReverseLunge)
            }
            "overhead_dumbbell_split_squat" => Some(LungeExerciseName::OverheadDumbbellSplitSquat),
            "overhead_lunge_with_rotation" => Some(LungeExerciseName::OverheadLungeWithRotation),
            "reverse_barbell_box_lunge" => Some(LungeExerciseName::ReverseBarbellBoxLunge),
            "reverse_box_lunge" => Some(LungeExerciseName::ReverseBoxLunge),
            "reverse_dumbbell_box_lunge" => Some(LungeExerciseName::ReverseDumbbellBoxLunge),
            "reverse_dumbbell_crossover_lunge" => {
                Some(LungeExerciseName::ReverseDumbbellCrossoverLunge)
            }
            "reverse_dumbbell_diagonal_lunge" => {
                Some(LungeExerciseName::ReverseDumbbellDiagonalLunge)
            }
            "reverse_lunge_with_reach_back" => Some(LungeExerciseName::ReverseLungeWithReachBack),
            "weighted_reverse_lunge_with_reach_back" => {
                Some(LungeExerciseName::WeightedReverseLungeWithReachBack)
            }
            "reverse_lunge_with_twist_and_overhead_reach" => {
                Some(LungeExerciseName::ReverseLungeWithTwistAndOverheadReach)
            }
            "weighted_reverse_lunge_with_twist_and_overhead_reach" => {
                Some(LungeExerciseName::WeightedReverseLungeWithTwistAndOverheadReach)
            }
            "reverse_sliding_box_lunge" => Some(LungeExerciseName::ReverseSlidingBoxLunge),
            "weighted_reverse_sliding_box_lunge" => {
                Some(LungeExerciseName::WeightedReverseSlidingBoxLunge)
            }
            "reverse_sliding_lunge" => Some(LungeExerciseName::ReverseSlidingLunge),
            "weighted_reverse_sliding_lunge" => {
                Some(LungeExerciseName::WeightedReverseSlidingLunge)
            }
            "runners_lunge_to_balance" => Some(LungeExerciseName::RunnersLungeToBalance),
            "weighted_runners_lunge_to_balance" => {
                Some(LungeExerciseName::WeightedRunnersLungeToBalance)
            }
            "shifting_side_lunge" => Some(LungeExerciseName::ShiftingSideLunge),
            "side_and_crossover_lunge" => Some(LungeExerciseName::SideAndCrossoverLunge),
            "weighted_side_and_crossover_lunge" => {
                Some(LungeExerciseName::WeightedSideAndCrossoverLunge)
            }
            "side_lunge" => Some(LungeExerciseName::SideLunge),
            "weighted_side_lunge" => Some(LungeExerciseName::WeightedSideLunge),
            "side_lunge_and_press" => Some(LungeExerciseName::SideLungeAndPress),
            "side_lunge_jump_off" => Some(LungeExerciseName::SideLungeJumpOff),
            "side_lunge_sweep" => Some(LungeExerciseName::SideLungeSweep),
            "weighted_side_lunge_sweep" => Some(LungeExerciseName::WeightedSideLungeSweep),
            "side_lunge_to_crossover_tap" => Some(LungeExerciseName::SideLungeToCrossoverTap),
            "weighted_side_lunge_to_crossover_tap" => {
                Some(LungeExerciseName::WeightedSideLungeToCrossoverTap)
            }
            "side_to_side_lunge_chops" => Some(LungeExerciseName::SideToSideLungeChops),
            "weighted_side_to_side_lunge_chops" => {
                Some(LungeExerciseName::WeightedSideToSideLungeChops)
            }
            "siff_jump_lunge" => Some(LungeExerciseName::SiffJumpLunge),
            "weighted_siff_jump_lunge" => Some(LungeExerciseName::WeightedSiffJumpLunge),
            "single_arm_reverse_lunge_and_press" => {
                Some(LungeExerciseName::SingleArmReverseLungeAndPress)
            }
            "sliding_lateral_lunge" => Some(LungeExerciseName::SlidingLateralLunge),
            "weighted_sliding_lateral_lunge" => {
                Some(LungeExerciseName::WeightedSlidingLateralLunge)
            }
            "walking_barbell_lunge" => Some(LungeExerciseName::WalkingBarbellLunge),
            "walking_dumbbell_lunge" => Some(LungeExerciseName::WalkingDumbbellLunge),
            "walking_lunge" => Some(LungeExerciseName::WalkingLunge),
            "weighted_walking_lunge" => Some(LungeExerciseName::WeightedWalkingLunge),
            "wide_grip_overhead_barbell_split_squat" => {
                Some(LungeExerciseName::WideGripOverheadBarbellSplitSquat)
            }
            "alternating_dumbbell_lunge" => Some(LungeExerciseName::AlternatingDumbbellLunge),
            "dumbbell_reverse_lunge" => Some(LungeExerciseName::DumbbellReverseLunge),
            "overhead_dumbbell_lunge" => Some(LungeExerciseName::OverheadDumbbellLunge),
            "scissor_power_switch" => Some(LungeExerciseName::ScissorPowerSwitch),
            "dumbbell_overhead_walking_lunge" => {
                Some(LungeExerciseName::DumbbellOverheadWalkingLunge)
            }
            "curtsy_lunge" => Some(LungeExerciseName::CurtsyLunge),
            "weighted_curtsy_lunge" => Some(LungeExerciseName::WeightedCurtsyLunge),
            "weighted_shifting_side_lunge" => Some(LungeExerciseName::WeightedShiftingSideLunge),
            "weighted_side_lunge_and_press" => Some(LungeExerciseName::WeightedSideLungeAndPress),
            "weighted_side_lunge_jump_off" => Some(LungeExerciseName::WeightedSideLungeJumpOff),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum OlympicLiftExerciseName {
    BarbellHangPowerClean = 0,
    BarbellHangSquatClean = 1,
    BarbellPowerClean = 2,
    BarbellPowerSnatch = 3,
    BarbellSquatClean = 4,
    CleanAndJerk = 5,
    BarbellHangPowerSnatch = 6,
    BarbellHangPull = 7,
    BarbellHighPull = 8,
    BarbellSnatch = 9,
    BarbellSplitJerk = 10,
    Clean = 11,
    DumbbellClean = 12,
    DumbbellHangPull = 13,
    OneHandDumbbellSplitSnatch = 14,
    PushJerk = 15,
    SingleArmDumbbellSnatch = 16,
    SingleArmHangSnatch = 17,
    SingleArmKettlebellSnatch = 18,
    SplitJerk = 19,
    SquatCleanAndJerk = 20,
    DumbbellHangSnatch = 21,
    DumbbellPowerCleanAndJerk = 22,
    DumbbellPowerCleanAndPushPress = 23,
    DumbbellPowerCleanAndStrictPress = 24,
    DumbbellSnatch = 25,
    MedicineBallClean = 26,
    CleanAndPress = 27,
    Snatch = 28,
}

impl OlympicLiftExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            OlympicLiftExerciseName::BarbellHangPowerClean => "barbell_hang_power_clean",
            OlympicLiftExerciseName::BarbellHangSquatClean => "barbell_hang_squat_clean",
            OlympicLiftExerciseName::BarbellPowerClean => "barbell_power_clean",
            OlympicLiftExerciseName::BarbellPowerSnatch => "barbell_power_snatch",
            OlympicLiftExerciseName::BarbellSquatClean => "barbell_squat_clean",
            OlympicLiftExerciseName::CleanAndJerk => "clean_and_jerk",
            OlympicLiftExerciseName::BarbellHangPowerSnatch => "barbell_hang_power_snatch",
            OlympicLiftExerciseName::BarbellHangPull => "barbell_hang_pull",
            OlympicLiftExerciseName::BarbellHighPull => "barbell_high_pull",
            OlympicLiftExerciseName::BarbellSnatch => "barbell_snatch",
            OlympicLiftExerciseName::BarbellSplitJerk => "barbell_split_jerk",
            OlympicLiftExerciseName::Clean => "clean",
            OlympicLiftExerciseName::DumbbellClean => "dumbbell_clean",
            OlympicLiftExerciseName::DumbbellHangPull => "dumbbell_hang_pull",
            OlympicLiftExerciseName::OneHandDumbbellSplitSnatch => "one_hand_dumbbell_split_snatch",
            OlympicLiftExerciseName::PushJerk => "push_jerk",
            OlympicLiftExerciseName::SingleArmDumbbellSnatch => "single_arm_dumbbell_snatch",
            OlympicLiftExerciseName::SingleArmHangSnatch => "single_arm_hang_snatch",
            OlympicLiftExerciseName::SingleArmKettlebellSnatch => "single_arm_kettlebell_snatch",
            OlympicLiftExerciseName::SplitJerk => "split_jerk",
            OlympicLiftExerciseName::SquatCleanAndJerk => "squat_clean_and_jerk",
            OlympicLiftExerciseName::DumbbellHangSnatch => "dumbbell_hang_snatch",
            OlympicLiftExerciseName::DumbbellPowerCleanAndJerk => "dumbbell_power_clean_and_jerk",
            OlympicLiftExerciseName::DumbbellPowerCleanAndPushPress => {
                "dumbbell_power_clean_and_push_press"
            }
            OlympicLiftExerciseName::DumbbellPowerCleanAndStrictPress => {
                "dumbbell_power_clean_and_strict_press"
            }
            OlympicLiftExerciseName::DumbbellSnatch => "dumbbell_snatch",
            OlympicLiftExerciseName::MedicineBallClean => "medicine_ball_clean",
            OlympicLiftExerciseName::CleanAndPress => "clean_and_press",
            OlympicLiftExerciseName::Snatch => "snatch",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(OlympicLiftExerciseName::BarbellHangPowerClean),
            1 => Some(OlympicLiftExerciseName::BarbellHangSquatClean),
            2 => Some(OlympicLiftExerciseName::BarbellPowerClean),
            3 => Some(OlympicLiftExerciseName::BarbellPowerSnatch),
            4 => Some(OlympicLiftExerciseName::BarbellSquatClean),
            5 => Some(OlympicLiftExerciseName::CleanAndJerk),
            6 => Some(OlympicLiftExerciseName::BarbellHangPowerSnatch),
            7 => Some(OlympicLiftExerciseName::BarbellHangPull),
            8 => Some(OlympicLiftExerciseName::BarbellHighPull),
            9 => Some(OlympicLiftExerciseName::BarbellSnatch),
            10 => Some(OlympicLiftExerciseName::BarbellSplitJerk),
            11 => Some(OlympicLiftExerciseName::Clean),
            12 => Some(OlympicLiftExerciseName::DumbbellClean),
            13 => Some(OlympicLiftExerciseName::DumbbellHangPull),
            14 => Some(OlympicLiftExerciseName::OneHandDumbbellSplitSnatch),
            15 => Some(OlympicLiftExerciseName::PushJerk),
            16 => Some(OlympicLiftExerciseName::SingleArmDumbbellSnatch),
            17 => Some(OlympicLiftExerciseName::SingleArmHangSnatch),
            18 => Some(OlympicLiftExerciseName::SingleArmKettlebellSnatch),
            19 => Some(OlympicLiftExerciseName::SplitJerk),
            20 => Some(OlympicLiftExerciseName::SquatCleanAndJerk),
            21 => Some(OlympicLiftExerciseName::DumbbellHangSnatch),
            22 => Some(OlympicLiftExerciseName::DumbbellPowerCleanAndJerk),
            23 => Some(OlympicLiftExerciseName::DumbbellPowerCleanAndPushPress),
            24 => Some(OlympicLiftExerciseName::DumbbellPowerCleanAndStrictPress),
            25 => Some(OlympicLiftExerciseName::DumbbellSnatch),
            26 => Some(OlympicLiftExerciseName::MedicineBallClean),
            27 => Some(OlympicLiftExerciseName::CleanAndPress),
            28 => Some(OlympicLiftExerciseName::Snatch),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "barbell_hang_power_clean" => Some(OlympicLiftExerciseName::BarbellHangPowerClean),
            "barbell_hang_squat_clean" => Some(OlympicLiftExerciseName::BarbellHangSquatClean),
            "barbell_power_clean" => Some(OlympicLiftExerciseName::BarbellPowerClean),
            "barbell_power_snatch" => Some(OlympicLiftExerciseName::BarbellPowerSnatch),
            "barbell_squat_clean" => Some(OlympicLiftExerciseName::BarbellSquatClean),
            "clean_and_jerk" => Some(OlympicLiftExerciseName::CleanAndJerk),
            "barbell_hang_power_snatch" => Some(OlympicLiftExerciseName::BarbellHangPowerSnatch),
            "barbell_hang_pull" => Some(OlympicLiftExerciseName::BarbellHangPull),
            "barbell_high_pull" => Some(OlympicLiftExerciseName::BarbellHighPull),
            "barbell_snatch" => Some(OlympicLiftExerciseName::BarbellSnatch),
            "barbell_split_jerk" => Some(OlympicLiftExerciseName::BarbellSplitJerk),
            "clean" => Some(OlympicLiftExerciseName::Clean),
            "dumbbell_clean" => Some(OlympicLiftExerciseName::DumbbellClean),
            "dumbbell_hang_pull" => Some(OlympicLiftExerciseName::DumbbellHangPull),
            "one_hand_dumbbell_split_snatch" => {
                Some(OlympicLiftExerciseName::OneHandDumbbellSplitSnatch)
            }
            "push_jerk" => Some(OlympicLiftExerciseName::PushJerk),
            "single_arm_dumbbell_snatch" => Some(OlympicLiftExerciseName::SingleArmDumbbellSnatch),
            "single_arm_hang_snatch" => Some(OlympicLiftExerciseName::SingleArmHangSnatch),
            "single_arm_kettlebell_snatch" => {
                Some(OlympicLiftExerciseName::SingleArmKettlebellSnatch)
            }
            "split_jerk" => Some(OlympicLiftExerciseName::SplitJerk),
            "squat_clean_and_jerk" => Some(OlympicLiftExerciseName::SquatCleanAndJerk),
            "dumbbell_hang_snatch" => Some(OlympicLiftExerciseName::DumbbellHangSnatch),
            "dumbbell_power_clean_and_jerk" => {
                Some(OlympicLiftExerciseName::DumbbellPowerCleanAndJerk)
            }
            "dumbbell_power_clean_and_push_press" => {
                Some(OlympicLiftExerciseName::DumbbellPowerCleanAndPushPress)
            }
            "dumbbell_power_clean_and_strict_press" => {
                Some(OlympicLiftExerciseName::DumbbellPowerCleanAndStrictPress)
            }
            "dumbbell_snatch" => Some(OlympicLiftExerciseName::DumbbellSnatch),
            "medicine_ball_clean" => Some(OlympicLiftExerciseName::MedicineBallClean),
            "clean_and_press" => Some(OlympicLiftExerciseName::CleanAndPress),
            "snatch" => Some(OlympicLiftExerciseName::Snatch),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum PlankExerciseName {
    _45DegreePlank = 0,
    Weighted45DegreePlank = 1,
    _90DegreeStaticHold = 2,
    Weighted90DegreeStaticHold = 3,
    BearCrawl = 4,
    WeightedBearCrawl = 5,
    CrossBodyMountainClimber = 6,
    WeightedCrossBodyMountainClimber = 7,
    ElbowPlankPikeJacks = 8,
    WeightedElbowPlankPikeJacks = 9,
    ElevatedFeetPlank = 10,
    WeightedElevatedFeetPlank = 11,
    ElevatorAbs = 12,
    WeightedElevatorAbs = 13,
    ExtendedPlank = 14,
    WeightedExtendedPlank = 15,
    FullPlankPasseTwist = 16,
    WeightedFullPlankPasseTwist = 17,
    InchingElbowPlank = 18,
    WeightedInchingElbowPlank = 19,
    InchwormToSidePlank = 20,
    WeightedInchwormToSidePlank = 21,
    KneelingPlank = 22,
    WeightedKneelingPlank = 23,
    KneelingSidePlankWithLegLift = 24,
    WeightedKneelingSidePlankWithLegLift = 25,
    LateralRoll = 26,
    WeightedLateralRoll = 27,
    LyingReversePlank = 28,
    WeightedLyingReversePlank = 29,
    MedicineBallMountainClimber = 30,
    WeightedMedicineBallMountainClimber = 31,
    ModifiedMountainClimberAndExtension = 32,
    WeightedModifiedMountainClimberAndExtension = 33,
    MountainClimber = 34,
    WeightedMountainClimber = 35,
    MountainClimberOnSlidingDiscs = 36,
    WeightedMountainClimberOnSlidingDiscs = 37,
    MountainClimberWithFeetOnBosuBall = 38,
    WeightedMountainClimberWithFeetOnBosuBall = 39,
    MountainClimberWithHandsOnBench = 40,
    MountainClimberWithHandsOnSwissBall = 41,
    WeightedMountainClimberWithHandsOnSwissBall = 42,
    Plank = 43,
    PlankJacksWithFeetOnSlidingDiscs = 44,
    WeightedPlankJacksWithFeetOnSlidingDiscs = 45,
    PlankKneeTwist = 46,
    WeightedPlankKneeTwist = 47,
    PlankPikeJumps = 48,
    WeightedPlankPikeJumps = 49,
    PlankPikes = 50,
    WeightedPlankPikes = 51,
    PlankToStandUp = 52,
    WeightedPlankToStandUp = 53,
    PlankWithArmRaise = 54,
    WeightedPlankWithArmRaise = 55,
    PlankWithKneeToElbow = 56,
    WeightedPlankWithKneeToElbow = 57,
    PlankWithObliqueCrunch = 58,
    WeightedPlankWithObliqueCrunch = 59,
    PlyometricSidePlank = 60,
    WeightedPlyometricSidePlank = 61,
    RollingSidePlank = 62,
    WeightedRollingSidePlank = 63,
    SideKickPlank = 64,
    WeightedSideKickPlank = 65,
    SidePlank = 66,
    WeightedSidePlank = 67,
    SidePlankAndRow = 68,
    WeightedSidePlankAndRow = 69,
    SidePlankLift = 70,
    WeightedSidePlankLift = 71,
    SidePlankWithElbowOnBosuBall = 72,
    WeightedSidePlankWithElbowOnBosuBall = 73,
    SidePlankWithFeetOnBench = 74,
    WeightedSidePlankWithFeetOnBench = 75,
    SidePlankWithKneeCircle = 76,
    WeightedSidePlankWithKneeCircle = 77,
    SidePlankWithKneeTuck = 78,
    WeightedSidePlankWithKneeTuck = 79,
    SidePlankWithLegLift = 80,
    WeightedSidePlankWithLegLift = 81,
    SidePlankWithReachUnder = 82,
    WeightedSidePlankWithReachUnder = 83,
    SingleLegElevatedFeetPlank = 84,
    WeightedSingleLegElevatedFeetPlank = 85,
    SingleLegFlexAndExtend = 86,
    WeightedSingleLegFlexAndExtend = 87,
    SingleLegSidePlank = 88,
    WeightedSingleLegSidePlank = 89,
    SpidermanPlank = 90,
    WeightedSpidermanPlank = 91,
    StraightArmPlank = 92,
    WeightedStraightArmPlank = 93,
    StraightArmPlankWithShoulderTouch = 94,
    WeightedStraightArmPlankWithShoulderTouch = 95,
    SwissBallPlank = 96,
    WeightedSwissBallPlank = 97,
    SwissBallPlankLegLift = 98,
    WeightedSwissBallPlankLegLift = 99,
    SwissBallPlankLegLiftAndHold = 100,
    SwissBallPlankWithFeetOnBench = 101,
    WeightedSwissBallPlankWithFeetOnBench = 102,
    SwissBallProneJackknife = 103,
    WeightedSwissBallProneJackknife = 104,
    SwissBallSidePlank = 105,
    WeightedSwissBallSidePlank = 106,
    ThreeWayPlank = 107,
    WeightedThreeWayPlank = 108,
    TowelPlankAndKneeIn = 109,
    WeightedTowelPlankAndKneeIn = 110,
    TStabilization = 111,
    WeightedTStabilization = 112,
    TurkishGetUpToSidePlank = 113,
    WeightedTurkishGetUpToSidePlank = 114,
    TwoPointPlank = 115,
    WeightedTwoPointPlank = 116,
    WeightedPlank = 117,
    WideStancePlankWithDiagonalArmLift = 118,
    WeightedWideStancePlankWithDiagonalArmLift = 119,
    WideStancePlankWithDiagonalLegLift = 120,
    WeightedWideStancePlankWithDiagonalLegLift = 121,
    WideStancePlankWithLegLift = 122,
    WeightedWideStancePlankWithLegLift = 123,
    WideStancePlankWithOppositeArmAndLegLift = 124,
    WeightedMountainClimberWithHandsOnBench = 125,
    WeightedSwissBallPlankLegLiftAndHold = 126,
    WeightedWideStancePlankWithOppositeArmAndLegLift = 127,
    PlankWithFeetOnSwissBall = 128,
    SidePlankToPlankWithReachUnder = 129,
    BridgeWithGluteLowerLift = 130,
    BridgeOneLegBridge = 131,
    PlankWithArmVariations = 132,
    PlankWithLegLift = 133,
    ReversePlankWithLegPull = 134,
    RingPlankSprawls = 135,
}

impl PlankExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            PlankExerciseName::_45DegreePlank => "45_degree_plank",
            PlankExerciseName::Weighted45DegreePlank => "weighted_45_degree_plank",
            PlankExerciseName::_90DegreeStaticHold => "90_degree_static_hold",
            PlankExerciseName::Weighted90DegreeStaticHold => "weighted_90_degree_static_hold",
            PlankExerciseName::BearCrawl => "bear_crawl",
            PlankExerciseName::WeightedBearCrawl => "weighted_bear_crawl",
            PlankExerciseName::CrossBodyMountainClimber => "cross_body_mountain_climber",
            PlankExerciseName::WeightedCrossBodyMountainClimber => {
                "weighted_cross_body_mountain_climber"
            }
            PlankExerciseName::ElbowPlankPikeJacks => "elbow_plank_pike_jacks",
            PlankExerciseName::WeightedElbowPlankPikeJacks => "weighted_elbow_plank_pike_jacks",
            PlankExerciseName::ElevatedFeetPlank => "elevated_feet_plank",
            PlankExerciseName::WeightedElevatedFeetPlank => "weighted_elevated_feet_plank",
            PlankExerciseName::ElevatorAbs => "elevator_abs",
            PlankExerciseName::WeightedElevatorAbs => "weighted_elevator_abs",
            PlankExerciseName::ExtendedPlank => "extended_plank",
            PlankExerciseName::WeightedExtendedPlank => "weighted_extended_plank",
            PlankExerciseName::FullPlankPasseTwist => "full_plank_passe_twist",
            PlankExerciseName::WeightedFullPlankPasseTwist => "weighted_full_plank_passe_twist",
            PlankExerciseName::InchingElbowPlank => "inching_elbow_plank",
            PlankExerciseName::WeightedInchingElbowPlank => "weighted_inching_elbow_plank",
            PlankExerciseName::InchwormToSidePlank => "inchworm_to_side_plank",
            PlankExerciseName::WeightedInchwormToSidePlank => "weighted_inchworm_to_side_plank",
            PlankExerciseName::KneelingPlank => "kneeling_plank",
            PlankExerciseName::WeightedKneelingPlank => "weighted_kneeling_plank",
            PlankExerciseName::KneelingSidePlankWithLegLift => "kneeling_side_plank_with_leg_lift",
            PlankExerciseName::WeightedKneelingSidePlankWithLegLift => {
                "weighted_kneeling_side_plank_with_leg_lift"
            }
            PlankExerciseName::LateralRoll => "lateral_roll",
            PlankExerciseName::WeightedLateralRoll => "weighted_lateral_roll",
            PlankExerciseName::LyingReversePlank => "lying_reverse_plank",
            PlankExerciseName::WeightedLyingReversePlank => "weighted_lying_reverse_plank",
            PlankExerciseName::MedicineBallMountainClimber => "medicine_ball_mountain_climber",
            PlankExerciseName::WeightedMedicineBallMountainClimber => {
                "weighted_medicine_ball_mountain_climber"
            }
            PlankExerciseName::ModifiedMountainClimberAndExtension => {
                "modified_mountain_climber_and_extension"
            }
            PlankExerciseName::WeightedModifiedMountainClimberAndExtension => {
                "weighted_modified_mountain_climber_and_extension"
            }
            PlankExerciseName::MountainClimber => "mountain_climber",
            PlankExerciseName::WeightedMountainClimber => "weighted_mountain_climber",
            PlankExerciseName::MountainClimberOnSlidingDiscs => "mountain_climber_on_sliding_discs",
            PlankExerciseName::WeightedMountainClimberOnSlidingDiscs => {
                "weighted_mountain_climber_on_sliding_discs"
            }
            PlankExerciseName::MountainClimberWithFeetOnBosuBall => {
                "mountain_climber_with_feet_on_bosu_ball"
            }
            PlankExerciseName::WeightedMountainClimberWithFeetOnBosuBall => {
                "weighted_mountain_climber_with_feet_on_bosu_ball"
            }
            PlankExerciseName::MountainClimberWithHandsOnBench => {
                "mountain_climber_with_hands_on_bench"
            }
            PlankExerciseName::MountainClimberWithHandsOnSwissBall => {
                "mountain_climber_with_hands_on_swiss_ball"
            }
            PlankExerciseName::WeightedMountainClimberWithHandsOnSwissBall => {
                "weighted_mountain_climber_with_hands_on_swiss_ball"
            }
            PlankExerciseName::Plank => "plank",
            PlankExerciseName::PlankJacksWithFeetOnSlidingDiscs => {
                "plank_jacks_with_feet_on_sliding_discs"
            }
            PlankExerciseName::WeightedPlankJacksWithFeetOnSlidingDiscs => {
                "weighted_plank_jacks_with_feet_on_sliding_discs"
            }
            PlankExerciseName::PlankKneeTwist => "plank_knee_twist",
            PlankExerciseName::WeightedPlankKneeTwist => "weighted_plank_knee_twist",
            PlankExerciseName::PlankPikeJumps => "plank_pike_jumps",
            PlankExerciseName::WeightedPlankPikeJumps => "weighted_plank_pike_jumps",
            PlankExerciseName::PlankPikes => "plank_pikes",
            PlankExerciseName::WeightedPlankPikes => "weighted_plank_pikes",
            PlankExerciseName::PlankToStandUp => "plank_to_stand_up",
            PlankExerciseName::WeightedPlankToStandUp => "weighted_plank_to_stand_up",
            PlankExerciseName::PlankWithArmRaise => "plank_with_arm_raise",
            PlankExerciseName::WeightedPlankWithArmRaise => "weighted_plank_with_arm_raise",
            PlankExerciseName::PlankWithKneeToElbow => "plank_with_knee_to_elbow",
            PlankExerciseName::WeightedPlankWithKneeToElbow => "weighted_plank_with_knee_to_elbow",
            PlankExerciseName::PlankWithObliqueCrunch => "plank_with_oblique_crunch",
            PlankExerciseName::WeightedPlankWithObliqueCrunch => {
                "weighted_plank_with_oblique_crunch"
            }
            PlankExerciseName::PlyometricSidePlank => "plyometric_side_plank",
            PlankExerciseName::WeightedPlyometricSidePlank => "weighted_plyometric_side_plank",
            PlankExerciseName::RollingSidePlank => "rolling_side_plank",
            PlankExerciseName::WeightedRollingSidePlank => "weighted_rolling_side_plank",
            PlankExerciseName::SideKickPlank => "side_kick_plank",
            PlankExerciseName::WeightedSideKickPlank => "weighted_side_kick_plank",
            PlankExerciseName::SidePlank => "side_plank",
            PlankExerciseName::WeightedSidePlank => "weighted_side_plank",
            PlankExerciseName::SidePlankAndRow => "side_plank_and_row",
            PlankExerciseName::WeightedSidePlankAndRow => "weighted_side_plank_and_row",
            PlankExerciseName::SidePlankLift => "side_plank_lift",
            PlankExerciseName::WeightedSidePlankLift => "weighted_side_plank_lift",
            PlankExerciseName::SidePlankWithElbowOnBosuBall => "side_plank_with_elbow_on_bosu_ball",
            PlankExerciseName::WeightedSidePlankWithElbowOnBosuBall => {
                "weighted_side_plank_with_elbow_on_bosu_ball"
            }
            PlankExerciseName::SidePlankWithFeetOnBench => "side_plank_with_feet_on_bench",
            PlankExerciseName::WeightedSidePlankWithFeetOnBench => {
                "weighted_side_plank_with_feet_on_bench"
            }
            PlankExerciseName::SidePlankWithKneeCircle => "side_plank_with_knee_circle",
            PlankExerciseName::WeightedSidePlankWithKneeCircle => {
                "weighted_side_plank_with_knee_circle"
            }
            PlankExerciseName::SidePlankWithKneeTuck => "side_plank_with_knee_tuck",
            PlankExerciseName::WeightedSidePlankWithKneeTuck => {
                "weighted_side_plank_with_knee_tuck"
            }
            PlankExerciseName::SidePlankWithLegLift => "side_plank_with_leg_lift",
            PlankExerciseName::WeightedSidePlankWithLegLift => "weighted_side_plank_with_leg_lift",
            PlankExerciseName::SidePlankWithReachUnder => "side_plank_with_reach_under",
            PlankExerciseName::WeightedSidePlankWithReachUnder => {
                "weighted_side_plank_with_reach_under"
            }
            PlankExerciseName::SingleLegElevatedFeetPlank => "single_leg_elevated_feet_plank",
            PlankExerciseName::WeightedSingleLegElevatedFeetPlank => {
                "weighted_single_leg_elevated_feet_plank"
            }
            PlankExerciseName::SingleLegFlexAndExtend => "single_leg_flex_and_extend",
            PlankExerciseName::WeightedSingleLegFlexAndExtend => {
                "weighted_single_leg_flex_and_extend"
            }
            PlankExerciseName::SingleLegSidePlank => "single_leg_side_plank",
            PlankExerciseName::WeightedSingleLegSidePlank => "weighted_single_leg_side_plank",
            PlankExerciseName::SpidermanPlank => "spiderman_plank",
            PlankExerciseName::WeightedSpidermanPlank => "weighted_spiderman_plank",
            PlankExerciseName::StraightArmPlank => "straight_arm_plank",
            PlankExerciseName::WeightedStraightArmPlank => "weighted_straight_arm_plank",
            PlankExerciseName::StraightArmPlankWithShoulderTouch => {
                "straight_arm_plank_with_shoulder_touch"
            }
            PlankExerciseName::WeightedStraightArmPlankWithShoulderTouch => {
                "weighted_straight_arm_plank_with_shoulder_touch"
            }
            PlankExerciseName::SwissBallPlank => "swiss_ball_plank",
            PlankExerciseName::WeightedSwissBallPlank => "weighted_swiss_ball_plank",
            PlankExerciseName::SwissBallPlankLegLift => "swiss_ball_plank_leg_lift",
            PlankExerciseName::WeightedSwissBallPlankLegLift => {
                "weighted_swiss_ball_plank_leg_lift"
            }
            PlankExerciseName::SwissBallPlankLegLiftAndHold => "swiss_ball_plank_leg_lift_and_hold",
            PlankExerciseName::SwissBallPlankWithFeetOnBench => {
                "swiss_ball_plank_with_feet_on_bench"
            }
            PlankExerciseName::WeightedSwissBallPlankWithFeetOnBench => {
                "weighted_swiss_ball_plank_with_feet_on_bench"
            }
            PlankExerciseName::SwissBallProneJackknife => "swiss_ball_prone_jackknife",
            PlankExerciseName::WeightedSwissBallProneJackknife => {
                "weighted_swiss_ball_prone_jackknife"
            }
            PlankExerciseName::SwissBallSidePlank => "swiss_ball_side_plank",
            PlankExerciseName::WeightedSwissBallSidePlank => "weighted_swiss_ball_side_plank",
            PlankExerciseName::ThreeWayPlank => "three_way_plank",
            PlankExerciseName::WeightedThreeWayPlank => "weighted_three_way_plank",
            PlankExerciseName::TowelPlankAndKneeIn => "towel_plank_and_knee_in",
            PlankExerciseName::WeightedTowelPlankAndKneeIn => "weighted_towel_plank_and_knee_in",
            PlankExerciseName::TStabilization => "t_stabilization",
            PlankExerciseName::WeightedTStabilization => "weighted_t_stabilization",
            PlankExerciseName::TurkishGetUpToSidePlank => "turkish_get_up_to_side_plank",
            PlankExerciseName::WeightedTurkishGetUpToSidePlank => {
                "weighted_turkish_get_up_to_side_plank"
            }
            PlankExerciseName::TwoPointPlank => "two_point_plank",
            PlankExerciseName::WeightedTwoPointPlank => "weighted_two_point_plank",
            PlankExerciseName::WeightedPlank => "weighted_plank",
            PlankExerciseName::WideStancePlankWithDiagonalArmLift => {
                "wide_stance_plank_with_diagonal_arm_lift"
            }
            PlankExerciseName::WeightedWideStancePlankWithDiagonalArmLift => {
                "weighted_wide_stance_plank_with_diagonal_arm_lift"
            }
            PlankExerciseName::WideStancePlankWithDiagonalLegLift => {
                "wide_stance_plank_with_diagonal_leg_lift"
            }
            PlankExerciseName::WeightedWideStancePlankWithDiagonalLegLift => {
                "weighted_wide_stance_plank_with_diagonal_leg_lift"
            }
            PlankExerciseName::WideStancePlankWithLegLift => "wide_stance_plank_with_leg_lift",
            PlankExerciseName::WeightedWideStancePlankWithLegLift => {
                "weighted_wide_stance_plank_with_leg_lift"
            }
            PlankExerciseName::WideStancePlankWithOppositeArmAndLegLift => {
                "wide_stance_plank_with_opposite_arm_and_leg_lift"
            }
            PlankExerciseName::WeightedMountainClimberWithHandsOnBench => {
                "weighted_mountain_climber_with_hands_on_bench"
            }
            PlankExerciseName::WeightedSwissBallPlankLegLiftAndHold => {
                "weighted_swiss_ball_plank_leg_lift_and_hold"
            }
            PlankExerciseName::WeightedWideStancePlankWithOppositeArmAndLegLift => {
                "weighted_wide_stance_plank_with_opposite_arm_and_leg_lift"
            }
            PlankExerciseName::PlankWithFeetOnSwissBall => "plank_with_feet_on_swiss_ball",
            PlankExerciseName::SidePlankToPlankWithReachUnder => {
                "side_plank_to_plank_with_reach_under"
            }
            PlankExerciseName::BridgeWithGluteLowerLift => "bridge_with_glute_lower_lift",
            PlankExerciseName::BridgeOneLegBridge => "bridge_one_leg_bridge",
            PlankExerciseName::PlankWithArmVariations => "plank_with_arm_variations",
            PlankExerciseName::PlankWithLegLift => "plank_with_leg_lift",
            PlankExerciseName::ReversePlankWithLegPull => "reverse_plank_with_leg_pull",
            PlankExerciseName::RingPlankSprawls => "ring_plank_sprawls",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(PlankExerciseName::_45DegreePlank),
            1 => Some(PlankExerciseName::Weighted45DegreePlank),
            2 => Some(PlankExerciseName::_90DegreeStaticHold),
            3 => Some(PlankExerciseName::Weighted90DegreeStaticHold),
            4 => Some(PlankExerciseName::BearCrawl),
            5 => Some(PlankExerciseName::WeightedBearCrawl),
            6 => Some(PlankExerciseName::CrossBodyMountainClimber),
            7 => Some(PlankExerciseName::WeightedCrossBodyMountainClimber),
            8 => Some(PlankExerciseName::ElbowPlankPikeJacks),
            9 => Some(PlankExerciseName::WeightedElbowPlankPikeJacks),
            10 => Some(PlankExerciseName::ElevatedFeetPlank),
            11 => Some(PlankExerciseName::WeightedElevatedFeetPlank),
            12 => Some(PlankExerciseName::ElevatorAbs),
            13 => Some(PlankExerciseName::WeightedElevatorAbs),
            14 => Some(PlankExerciseName::ExtendedPlank),
            15 => Some(PlankExerciseName::WeightedExtendedPlank),
            16 => Some(PlankExerciseName::FullPlankPasseTwist),
            17 => Some(PlankExerciseName::WeightedFullPlankPasseTwist),
            18 => Some(PlankExerciseName::InchingElbowPlank),
            19 => Some(PlankExerciseName::WeightedInchingElbowPlank),
            20 => Some(PlankExerciseName::InchwormToSidePlank),
            21 => Some(PlankExerciseName::WeightedInchwormToSidePlank),
            22 => Some(PlankExerciseName::KneelingPlank),
            23 => Some(PlankExerciseName::WeightedKneelingPlank),
            24 => Some(PlankExerciseName::KneelingSidePlankWithLegLift),
            25 => Some(PlankExerciseName::WeightedKneelingSidePlankWithLegLift),
            26 => Some(PlankExerciseName::LateralRoll),
            27 => Some(PlankExerciseName::WeightedLateralRoll),
            28 => Some(PlankExerciseName::LyingReversePlank),
            29 => Some(PlankExerciseName::WeightedLyingReversePlank),
            30 => Some(PlankExerciseName::MedicineBallMountainClimber),
            31 => Some(PlankExerciseName::WeightedMedicineBallMountainClimber),
            32 => Some(PlankExerciseName::ModifiedMountainClimberAndExtension),
            33 => Some(PlankExerciseName::WeightedModifiedMountainClimberAndExtension),
            34 => Some(PlankExerciseName::MountainClimber),
            35 => Some(PlankExerciseName::WeightedMountainClimber),
            36 => Some(PlankExerciseName::MountainClimberOnSlidingDiscs),
            37 => Some(PlankExerciseName::WeightedMountainClimberOnSlidingDiscs),
            38 => Some(PlankExerciseName::MountainClimberWithFeetOnBosuBall),
            39 => Some(PlankExerciseName::WeightedMountainClimberWithFeetOnBosuBall),
            40 => Some(PlankExerciseName::MountainClimberWithHandsOnBench),
            41 => Some(PlankExerciseName::MountainClimberWithHandsOnSwissBall),
            42 => Some(PlankExerciseName::WeightedMountainClimberWithHandsOnSwissBall),
            43 => Some(PlankExerciseName::Plank),
            44 => Some(PlankExerciseName::PlankJacksWithFeetOnSlidingDiscs),
            45 => Some(PlankExerciseName::WeightedPlankJacksWithFeetOnSlidingDiscs),
            46 => Some(PlankExerciseName::PlankKneeTwist),
            47 => Some(PlankExerciseName::WeightedPlankKneeTwist),
            48 => Some(PlankExerciseName::PlankPikeJumps),
            49 => Some(PlankExerciseName::WeightedPlankPikeJumps),
            50 => Some(PlankExerciseName::PlankPikes),
            51 => Some(PlankExerciseName::WeightedPlankPikes),
            52 => Some(PlankExerciseName::PlankToStandUp),
            53 => Some(PlankExerciseName::WeightedPlankToStandUp),
            54 => Some(PlankExerciseName::PlankWithArmRaise),
            55 => Some(PlankExerciseName::WeightedPlankWithArmRaise),
            56 => Some(PlankExerciseName::PlankWithKneeToElbow),
            57 => Some(PlankExerciseName::WeightedPlankWithKneeToElbow),
            58 => Some(PlankExerciseName::PlankWithObliqueCrunch),
            59 => Some(PlankExerciseName::WeightedPlankWithObliqueCrunch),
            60 => Some(PlankExerciseName::PlyometricSidePlank),
            61 => Some(PlankExerciseName::WeightedPlyometricSidePlank),
            62 => Some(PlankExerciseName::RollingSidePlank),
            63 => Some(PlankExerciseName::WeightedRollingSidePlank),
            64 => Some(PlankExerciseName::SideKickPlank),
            65 => Some(PlankExerciseName::WeightedSideKickPlank),
            66 => Some(PlankExerciseName::SidePlank),
            67 => Some(PlankExerciseName::WeightedSidePlank),
            68 => Some(PlankExerciseName::SidePlankAndRow),
            69 => Some(PlankExerciseName::WeightedSidePlankAndRow),
            70 => Some(PlankExerciseName::SidePlankLift),
            71 => Some(PlankExerciseName::WeightedSidePlankLift),
            72 => Some(PlankExerciseName::SidePlankWithElbowOnBosuBall),
            73 => Some(PlankExerciseName::WeightedSidePlankWithElbowOnBosuBall),
            74 => Some(PlankExerciseName::SidePlankWithFeetOnBench),
            75 => Some(PlankExerciseName::WeightedSidePlankWithFeetOnBench),
            76 => Some(PlankExerciseName::SidePlankWithKneeCircle),
            77 => Some(PlankExerciseName::WeightedSidePlankWithKneeCircle),
            78 => Some(PlankExerciseName::SidePlankWithKneeTuck),
            79 => Some(PlankExerciseName::WeightedSidePlankWithKneeTuck),
            80 => Some(PlankExerciseName::SidePlankWithLegLift),
            81 => Some(PlankExerciseName::WeightedSidePlankWithLegLift),
            82 => Some(PlankExerciseName::SidePlankWithReachUnder),
            83 => Some(PlankExerciseName::WeightedSidePlankWithReachUnder),
            84 => Some(PlankExerciseName::SingleLegElevatedFeetPlank),
            85 => Some(PlankExerciseName::WeightedSingleLegElevatedFeetPlank),
            86 => Some(PlankExerciseName::SingleLegFlexAndExtend),
            87 => Some(PlankExerciseName::WeightedSingleLegFlexAndExtend),
            88 => Some(PlankExerciseName::SingleLegSidePlank),
            89 => Some(PlankExerciseName::WeightedSingleLegSidePlank),
            90 => Some(PlankExerciseName::SpidermanPlank),
            91 => Some(PlankExerciseName::WeightedSpidermanPlank),
            92 => Some(PlankExerciseName::StraightArmPlank),
            93 => Some(PlankExerciseName::WeightedStraightArmPlank),
            94 => Some(PlankExerciseName::StraightArmPlankWithShoulderTouch),
            95 => Some(PlankExerciseName::WeightedStraightArmPlankWithShoulderTouch),
            96 => Some(PlankExerciseName::SwissBallPlank),
            97 => Some(PlankExerciseName::WeightedSwissBallPlank),
            98 => Some(PlankExerciseName::SwissBallPlankLegLift),
            99 => Some(PlankExerciseName::WeightedSwissBallPlankLegLift),
            100 => Some(PlankExerciseName::SwissBallPlankLegLiftAndHold),
            101 => Some(PlankExerciseName::SwissBallPlankWithFeetOnBench),
            102 => Some(PlankExerciseName::WeightedSwissBallPlankWithFeetOnBench),
            103 => Some(PlankExerciseName::SwissBallProneJackknife),
            104 => Some(PlankExerciseName::WeightedSwissBallProneJackknife),
            105 => Some(PlankExerciseName::SwissBallSidePlank),
            106 => Some(PlankExerciseName::WeightedSwissBallSidePlank),
            107 => Some(PlankExerciseName::ThreeWayPlank),
            108 => Some(PlankExerciseName::WeightedThreeWayPlank),
            109 => Some(PlankExerciseName::TowelPlankAndKneeIn),
            110 => Some(PlankExerciseName::WeightedTowelPlankAndKneeIn),
            111 => Some(PlankExerciseName::TStabilization),
            112 => Some(PlankExerciseName::WeightedTStabilization),
            113 => Some(PlankExerciseName::TurkishGetUpToSidePlank),
            114 => Some(PlankExerciseName::WeightedTurkishGetUpToSidePlank),
            115 => Some(PlankExerciseName::TwoPointPlank),
            116 => Some(PlankExerciseName::WeightedTwoPointPlank),
            117 => Some(PlankExerciseName::WeightedPlank),
            118 => Some(PlankExerciseName::WideStancePlankWithDiagonalArmLift),
            119 => Some(PlankExerciseName::WeightedWideStancePlankWithDiagonalArmLift),
            120 => Some(PlankExerciseName::WideStancePlankWithDiagonalLegLift),
            121 => Some(PlankExerciseName::WeightedWideStancePlankWithDiagonalLegLift),
            122 => Some(PlankExerciseName::WideStancePlankWithLegLift),
            123 => Some(PlankExerciseName::WeightedWideStancePlankWithLegLift),
            124 => Some(PlankExerciseName::WideStancePlankWithOppositeArmAndLegLift),
            125 => Some(PlankExerciseName::WeightedMountainClimberWithHandsOnBench),
            126 => Some(PlankExerciseName::WeightedSwissBallPlankLegLiftAndHold),
            127 => Some(PlankExerciseName::WeightedWideStancePlankWithOppositeArmAndLegLift),
            128 => Some(PlankExerciseName::PlankWithFeetOnSwissBall),
            129 => Some(PlankExerciseName::SidePlankToPlankWithReachUnder),
            130 => Some(PlankExerciseName::BridgeWithGluteLowerLift),
            131 => Some(PlankExerciseName::BridgeOneLegBridge),
            132 => Some(PlankExerciseName::PlankWithArmVariations),
            133 => Some(PlankExerciseName::PlankWithLegLift),
            134 => Some(PlankExerciseName::ReversePlankWithLegPull),
            135 => Some(PlankExerciseName::RingPlankSprawls),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "45_degree_plank" => Some(PlankExerciseName::_45DegreePlank),
            "weighted_45_degree_plank" => Some(PlankExerciseName::Weighted45DegreePlank),
            "90_degree_static_hold" => Some(PlankExerciseName::_90DegreeStaticHold),
            "weighted_90_degree_static_hold" => Some(PlankExerciseName::Weighted90DegreeStaticHold),
            "bear_crawl" => Some(PlankExerciseName::BearCrawl),
            "weighted_bear_crawl" => Some(PlankExerciseName::WeightedBearCrawl),
            "cross_body_mountain_climber" => Some(PlankExerciseName::CrossBodyMountainClimber),
            "weighted_cross_body_mountain_climber" => {
                Some(PlankExerciseName::WeightedCrossBodyMountainClimber)
            }
            "elbow_plank_pike_jacks" => Some(PlankExerciseName::ElbowPlankPikeJacks),
            "weighted_elbow_plank_pike_jacks" => {
                Some(PlankExerciseName::WeightedElbowPlankPikeJacks)
            }
            "elevated_feet_plank" => Some(PlankExerciseName::ElevatedFeetPlank),
            "weighted_elevated_feet_plank" => Some(PlankExerciseName::WeightedElevatedFeetPlank),
            "elevator_abs" => Some(PlankExerciseName::ElevatorAbs),
            "weighted_elevator_abs" => Some(PlankExerciseName::WeightedElevatorAbs),
            "extended_plank" => Some(PlankExerciseName::ExtendedPlank),
            "weighted_extended_plank" => Some(PlankExerciseName::WeightedExtendedPlank),
            "full_plank_passe_twist" => Some(PlankExerciseName::FullPlankPasseTwist),
            "weighted_full_plank_passe_twist" => {
                Some(PlankExerciseName::WeightedFullPlankPasseTwist)
            }
            "inching_elbow_plank" => Some(PlankExerciseName::InchingElbowPlank),
            "weighted_inching_elbow_plank" => Some(PlankExerciseName::WeightedInchingElbowPlank),
            "inchworm_to_side_plank" => Some(PlankExerciseName::InchwormToSidePlank),
            "weighted_inchworm_to_side_plank" => {
                Some(PlankExerciseName::WeightedInchwormToSidePlank)
            }
            "kneeling_plank" => Some(PlankExerciseName::KneelingPlank),
            "weighted_kneeling_plank" => Some(PlankExerciseName::WeightedKneelingPlank),
            "kneeling_side_plank_with_leg_lift" => {
                Some(PlankExerciseName::KneelingSidePlankWithLegLift)
            }
            "weighted_kneeling_side_plank_with_leg_lift" => {
                Some(PlankExerciseName::WeightedKneelingSidePlankWithLegLift)
            }
            "lateral_roll" => Some(PlankExerciseName::LateralRoll),
            "weighted_lateral_roll" => Some(PlankExerciseName::WeightedLateralRoll),
            "lying_reverse_plank" => Some(PlankExerciseName::LyingReversePlank),
            "weighted_lying_reverse_plank" => Some(PlankExerciseName::WeightedLyingReversePlank),
            "medicine_ball_mountain_climber" => {
                Some(PlankExerciseName::MedicineBallMountainClimber)
            }
            "weighted_medicine_ball_mountain_climber" => {
                Some(PlankExerciseName::WeightedMedicineBallMountainClimber)
            }
            "modified_mountain_climber_and_extension" => {
                Some(PlankExerciseName::ModifiedMountainClimberAndExtension)
            }
            "weighted_modified_mountain_climber_and_extension" => {
                Some(PlankExerciseName::WeightedModifiedMountainClimberAndExtension)
            }
            "mountain_climber" => Some(PlankExerciseName::MountainClimber),
            "weighted_mountain_climber" => Some(PlankExerciseName::WeightedMountainClimber),
            "mountain_climber_on_sliding_discs" => {
                Some(PlankExerciseName::MountainClimberOnSlidingDiscs)
            }
            "weighted_mountain_climber_on_sliding_discs" => {
                Some(PlankExerciseName::WeightedMountainClimberOnSlidingDiscs)
            }
            "mountain_climber_with_feet_on_bosu_ball" => {
                Some(PlankExerciseName::MountainClimberWithFeetOnBosuBall)
            }
            "weighted_mountain_climber_with_feet_on_bosu_ball" => {
                Some(PlankExerciseName::WeightedMountainClimberWithFeetOnBosuBall)
            }
            "mountain_climber_with_hands_on_bench" => {
                Some(PlankExerciseName::MountainClimberWithHandsOnBench)
            }
            "mountain_climber_with_hands_on_swiss_ball" => {
                Some(PlankExerciseName::MountainClimberWithHandsOnSwissBall)
            }
            "weighted_mountain_climber_with_hands_on_swiss_ball" => {
                Some(PlankExerciseName::WeightedMountainClimberWithHandsOnSwissBall)
            }
            "plank" => Some(PlankExerciseName::Plank),
            "plank_jacks_with_feet_on_sliding_discs" => {
                Some(PlankExerciseName::PlankJacksWithFeetOnSlidingDiscs)
            }
            "weighted_plank_jacks_with_feet_on_sliding_discs" => {
                Some(PlankExerciseName::WeightedPlankJacksWithFeetOnSlidingDiscs)
            }
            "plank_knee_twist" => Some(PlankExerciseName::PlankKneeTwist),
            "weighted_plank_knee_twist" => Some(PlankExerciseName::WeightedPlankKneeTwist),
            "plank_pike_jumps" => Some(PlankExerciseName::PlankPikeJumps),
            "weighted_plank_pike_jumps" => Some(PlankExerciseName::WeightedPlankPikeJumps),
            "plank_pikes" => Some(PlankExerciseName::PlankPikes),
            "weighted_plank_pikes" => Some(PlankExerciseName::WeightedPlankPikes),
            "plank_to_stand_up" => Some(PlankExerciseName::PlankToStandUp),
            "weighted_plank_to_stand_up" => Some(PlankExerciseName::WeightedPlankToStandUp),
            "plank_with_arm_raise" => Some(PlankExerciseName::PlankWithArmRaise),
            "weighted_plank_with_arm_raise" => Some(PlankExerciseName::WeightedPlankWithArmRaise),
            "plank_with_knee_to_elbow" => Some(PlankExerciseName::PlankWithKneeToElbow),
            "weighted_plank_with_knee_to_elbow" => {
                Some(PlankExerciseName::WeightedPlankWithKneeToElbow)
            }
            "plank_with_oblique_crunch" => Some(PlankExerciseName::PlankWithObliqueCrunch),
            "weighted_plank_with_oblique_crunch" => {
                Some(PlankExerciseName::WeightedPlankWithObliqueCrunch)
            }
            "plyometric_side_plank" => Some(PlankExerciseName::PlyometricSidePlank),
            "weighted_plyometric_side_plank" => {
                Some(PlankExerciseName::WeightedPlyometricSidePlank)
            }
            "rolling_side_plank" => Some(PlankExerciseName::RollingSidePlank),
            "weighted_rolling_side_plank" => Some(PlankExerciseName::WeightedRollingSidePlank),
            "side_kick_plank" => Some(PlankExerciseName::SideKickPlank),
            "weighted_side_kick_plank" => Some(PlankExerciseName::WeightedSideKickPlank),
            "side_plank" => Some(PlankExerciseName::SidePlank),
            "weighted_side_plank" => Some(PlankExerciseName::WeightedSidePlank),
            "side_plank_and_row" => Some(PlankExerciseName::SidePlankAndRow),
            "weighted_side_plank_and_row" => Some(PlankExerciseName::WeightedSidePlankAndRow),
            "side_plank_lift" => Some(PlankExerciseName::SidePlankLift),
            "weighted_side_plank_lift" => Some(PlankExerciseName::WeightedSidePlankLift),
            "side_plank_with_elbow_on_bosu_ball" => {
                Some(PlankExerciseName::SidePlankWithElbowOnBosuBall)
            }
            "weighted_side_plank_with_elbow_on_bosu_ball" => {
                Some(PlankExerciseName::WeightedSidePlankWithElbowOnBosuBall)
            }
            "side_plank_with_feet_on_bench" => Some(PlankExerciseName::SidePlankWithFeetOnBench),
            "weighted_side_plank_with_feet_on_bench" => {
                Some(PlankExerciseName::WeightedSidePlankWithFeetOnBench)
            }
            "side_plank_with_knee_circle" => Some(PlankExerciseName::SidePlankWithKneeCircle),
            "weighted_side_plank_with_knee_circle" => {
                Some(PlankExerciseName::WeightedSidePlankWithKneeCircle)
            }
            "side_plank_with_knee_tuck" => Some(PlankExerciseName::SidePlankWithKneeTuck),
            "weighted_side_plank_with_knee_tuck" => {
                Some(PlankExerciseName::WeightedSidePlankWithKneeTuck)
            }
            "side_plank_with_leg_lift" => Some(PlankExerciseName::SidePlankWithLegLift),
            "weighted_side_plank_with_leg_lift" => {
                Some(PlankExerciseName::WeightedSidePlankWithLegLift)
            }
            "side_plank_with_reach_under" => Some(PlankExerciseName::SidePlankWithReachUnder),
            "weighted_side_plank_with_reach_under" => {
                Some(PlankExerciseName::WeightedSidePlankWithReachUnder)
            }
            "single_leg_elevated_feet_plank" => Some(PlankExerciseName::SingleLegElevatedFeetPlank),
            "weighted_single_leg_elevated_feet_plank" => {
                Some(PlankExerciseName::WeightedSingleLegElevatedFeetPlank)
            }
            "single_leg_flex_and_extend" => Some(PlankExerciseName::SingleLegFlexAndExtend),
            "weighted_single_leg_flex_and_extend" => {
                Some(PlankExerciseName::WeightedSingleLegFlexAndExtend)
            }
            "single_leg_side_plank" => Some(PlankExerciseName::SingleLegSidePlank),
            "weighted_single_leg_side_plank" => Some(PlankExerciseName::WeightedSingleLegSidePlank),
            "spiderman_plank" => Some(PlankExerciseName::SpidermanPlank),
            "weighted_spiderman_plank" => Some(PlankExerciseName::WeightedSpidermanPlank),
            "straight_arm_plank" => Some(PlankExerciseName::StraightArmPlank),
            "weighted_straight_arm_plank" => Some(PlankExerciseName::WeightedStraightArmPlank),
            "straight_arm_plank_with_shoulder_touch" => {
                Some(PlankExerciseName::StraightArmPlankWithShoulderTouch)
            }
            "weighted_straight_arm_plank_with_shoulder_touch" => {
                Some(PlankExerciseName::WeightedStraightArmPlankWithShoulderTouch)
            }
            "swiss_ball_plank" => Some(PlankExerciseName::SwissBallPlank),
            "weighted_swiss_ball_plank" => Some(PlankExerciseName::WeightedSwissBallPlank),
            "swiss_ball_plank_leg_lift" => Some(PlankExerciseName::SwissBallPlankLegLift),
            "weighted_swiss_ball_plank_leg_lift" => {
                Some(PlankExerciseName::WeightedSwissBallPlankLegLift)
            }
            "swiss_ball_plank_leg_lift_and_hold" => {
                Some(PlankExerciseName::SwissBallPlankLegLiftAndHold)
            }
            "swiss_ball_plank_with_feet_on_bench" => {
                Some(PlankExerciseName::SwissBallPlankWithFeetOnBench)
            }
            "weighted_swiss_ball_plank_with_feet_on_bench" => {
                Some(PlankExerciseName::WeightedSwissBallPlankWithFeetOnBench)
            }
            "swiss_ball_prone_jackknife" => Some(PlankExerciseName::SwissBallProneJackknife),
            "weighted_swiss_ball_prone_jackknife" => {
                Some(PlankExerciseName::WeightedSwissBallProneJackknife)
            }
            "swiss_ball_side_plank" => Some(PlankExerciseName::SwissBallSidePlank),
            "weighted_swiss_ball_side_plank" => Some(PlankExerciseName::WeightedSwissBallSidePlank),
            "three_way_plank" => Some(PlankExerciseName::ThreeWayPlank),
            "weighted_three_way_plank" => Some(PlankExerciseName::WeightedThreeWayPlank),
            "towel_plank_and_knee_in" => Some(PlankExerciseName::TowelPlankAndKneeIn),
            "weighted_towel_plank_and_knee_in" => {
                Some(PlankExerciseName::WeightedTowelPlankAndKneeIn)
            }
            "t_stabilization" => Some(PlankExerciseName::TStabilization),
            "weighted_t_stabilization" => Some(PlankExerciseName::WeightedTStabilization),
            "turkish_get_up_to_side_plank" => Some(PlankExerciseName::TurkishGetUpToSidePlank),
            "weighted_turkish_get_up_to_side_plank" => {
                Some(PlankExerciseName::WeightedTurkishGetUpToSidePlank)
            }
            "two_point_plank" => Some(PlankExerciseName::TwoPointPlank),
            "weighted_two_point_plank" => Some(PlankExerciseName::WeightedTwoPointPlank),
            "weighted_plank" => Some(PlankExerciseName::WeightedPlank),
            "wide_stance_plank_with_diagonal_arm_lift" => {
                Some(PlankExerciseName::WideStancePlankWithDiagonalArmLift)
            }
            "weighted_wide_stance_plank_with_diagonal_arm_lift" => {
                Some(PlankExerciseName::WeightedWideStancePlankWithDiagonalArmLift)
            }
            "wide_stance_plank_with_diagonal_leg_lift" => {
                Some(PlankExerciseName::WideStancePlankWithDiagonalLegLift)
            }
            "weighted_wide_stance_plank_with_diagonal_leg_lift" => {
                Some(PlankExerciseName::WeightedWideStancePlankWithDiagonalLegLift)
            }
            "wide_stance_plank_with_leg_lift" => {
                Some(PlankExerciseName::WideStancePlankWithLegLift)
            }
            "weighted_wide_stance_plank_with_leg_lift" => {
                Some(PlankExerciseName::WeightedWideStancePlankWithLegLift)
            }
            "wide_stance_plank_with_opposite_arm_and_leg_lift" => {
                Some(PlankExerciseName::WideStancePlankWithOppositeArmAndLegLift)
            }
            "weighted_mountain_climber_with_hands_on_bench" => {
                Some(PlankExerciseName::WeightedMountainClimberWithHandsOnBench)
            }
            "weighted_swiss_ball_plank_leg_lift_and_hold" => {
                Some(PlankExerciseName::WeightedSwissBallPlankLegLiftAndHold)
            }
            "weighted_wide_stance_plank_with_opposite_arm_and_leg_lift" => {
                Some(PlankExerciseName::WeightedWideStancePlankWithOppositeArmAndLegLift)
            }
            "plank_with_feet_on_swiss_ball" => Some(PlankExerciseName::PlankWithFeetOnSwissBall),
            "side_plank_to_plank_with_reach_under" => {
                Some(PlankExerciseName::SidePlankToPlankWithReachUnder)
            }
            "bridge_with_glute_lower_lift" => Some(PlankExerciseName::BridgeWithGluteLowerLift),
            "bridge_one_leg_bridge" => Some(PlankExerciseName::BridgeOneLegBridge),
            "plank_with_arm_variations" => Some(PlankExerciseName::PlankWithArmVariations),
            "plank_with_leg_lift" => Some(PlankExerciseName::PlankWithLegLift),
            "reverse_plank_with_leg_pull" => Some(PlankExerciseName::ReversePlankWithLegPull),
            "ring_plank_sprawls" => Some(PlankExerciseName::RingPlankSprawls),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum PlyoExerciseName {
    AlternatingJumpLunge = 0,
    WeightedAlternatingJumpLunge = 1,
    BarbellJumpSquat = 2,
    BodyWeightJumpSquat = 3,
    WeightedJumpSquat = 4,
    CrossKneeStrike = 5,
    WeightedCrossKneeStrike = 6,
    DepthJump = 7,
    WeightedDepthJump = 8,
    DumbbellJumpSquat = 9,
    DumbbellSplitJump = 10,
    FrontKneeStrike = 11,
    WeightedFrontKneeStrike = 12,
    HighBoxJump = 13,
    WeightedHighBoxJump = 14,
    IsometricExplosiveBodyWeightJumpSquat = 15,
    WeightedIsometricExplosiveJumpSquat = 16,
    LateralLeapAndHop = 17,
    WeightedLateralLeapAndHop = 18,
    LateralPlyoSquats = 19,
    WeightedLateralPlyoSquats = 20,
    LateralSlide = 21,
    WeightedLateralSlide = 22,
    MedicineBallOverheadThrows = 23,
    MedicineBallSideThrow = 24,
    MedicineBallSlam = 25,
    SideToSideMedicineBallThrows = 26,
    SideToSideShuffleJump = 27,
    WeightedSideToSideShuffleJump = 28,
    SquatJumpOntoBox = 29,
    WeightedSquatJumpOntoBox = 30,
    SquatJumpsInAndOut = 31,
    WeightedSquatJumpsInAndOut = 32,
    BoxJump = 33,
    BoxJumpOvers = 34,
    BoxJumpOversOverTheBox = 35,
    StarJumpSquats = 36,
    JumpSquat = 37,
}

impl PlyoExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            PlyoExerciseName::AlternatingJumpLunge => "alternating_jump_lunge",
            PlyoExerciseName::WeightedAlternatingJumpLunge => "weighted_alternating_jump_lunge",
            PlyoExerciseName::BarbellJumpSquat => "barbell_jump_squat",
            PlyoExerciseName::BodyWeightJumpSquat => "body_weight_jump_squat",
            PlyoExerciseName::WeightedJumpSquat => "weighted_jump_squat",
            PlyoExerciseName::CrossKneeStrike => "cross_knee_strike",
            PlyoExerciseName::WeightedCrossKneeStrike => "weighted_cross_knee_strike",
            PlyoExerciseName::DepthJump => "depth_jump",
            PlyoExerciseName::WeightedDepthJump => "weighted_depth_jump",
            PlyoExerciseName::DumbbellJumpSquat => "dumbbell_jump_squat",
            PlyoExerciseName::DumbbellSplitJump => "dumbbell_split_jump",
            PlyoExerciseName::FrontKneeStrike => "front_knee_strike",
            PlyoExerciseName::WeightedFrontKneeStrike => "weighted_front_knee_strike",
            PlyoExerciseName::HighBoxJump => "high_box_jump",
            PlyoExerciseName::WeightedHighBoxJump => "weighted_high_box_jump",
            PlyoExerciseName::IsometricExplosiveBodyWeightJumpSquat => {
                "isometric_explosive_body_weight_jump_squat"
            }
            PlyoExerciseName::WeightedIsometricExplosiveJumpSquat => {
                "weighted_isometric_explosive_jump_squat"
            }
            PlyoExerciseName::LateralLeapAndHop => "lateral_leap_and_hop",
            PlyoExerciseName::WeightedLateralLeapAndHop => "weighted_lateral_leap_and_hop",
            PlyoExerciseName::LateralPlyoSquats => "lateral_plyo_squats",
            PlyoExerciseName::WeightedLateralPlyoSquats => "weighted_lateral_plyo_squats",
            PlyoExerciseName::LateralSlide => "lateral_slide",
            PlyoExerciseName::WeightedLateralSlide => "weighted_lateral_slide",
            PlyoExerciseName::MedicineBallOverheadThrows => "medicine_ball_overhead_throws",
            PlyoExerciseName::MedicineBallSideThrow => "medicine_ball_side_throw",
            PlyoExerciseName::MedicineBallSlam => "medicine_ball_slam",
            PlyoExerciseName::SideToSideMedicineBallThrows => "side_to_side_medicine_ball_throws",
            PlyoExerciseName::SideToSideShuffleJump => "side_to_side_shuffle_jump",
            PlyoExerciseName::WeightedSideToSideShuffleJump => "weighted_side_to_side_shuffle_jump",
            PlyoExerciseName::SquatJumpOntoBox => "squat_jump_onto_box",
            PlyoExerciseName::WeightedSquatJumpOntoBox => "weighted_squat_jump_onto_box",
            PlyoExerciseName::SquatJumpsInAndOut => "squat_jumps_in_and_out",
            PlyoExerciseName::WeightedSquatJumpsInAndOut => "weighted_squat_jumps_in_and_out",
            PlyoExerciseName::BoxJump => "box_jump",
            PlyoExerciseName::BoxJumpOvers => "box_jump_overs",
            PlyoExerciseName::BoxJumpOversOverTheBox => "box_jump_overs_over_the_box",
            PlyoExerciseName::StarJumpSquats => "star_jump_squats",
            PlyoExerciseName::JumpSquat => "jump_squat",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(PlyoExerciseName::AlternatingJumpLunge),
            1 => Some(PlyoExerciseName::WeightedAlternatingJumpLunge),
            2 => Some(PlyoExerciseName::BarbellJumpSquat),
            3 => Some(PlyoExerciseName::BodyWeightJumpSquat),
            4 => Some(PlyoExerciseName::WeightedJumpSquat),
            5 => Some(PlyoExerciseName::CrossKneeStrike),
            6 => Some(PlyoExerciseName::WeightedCrossKneeStrike),
            7 => Some(PlyoExerciseName::DepthJump),
            8 => Some(PlyoExerciseName::WeightedDepthJump),
            9 => Some(PlyoExerciseName::DumbbellJumpSquat),
            10 => Some(PlyoExerciseName::DumbbellSplitJump),
            11 => Some(PlyoExerciseName::FrontKneeStrike),
            12 => Some(PlyoExerciseName::WeightedFrontKneeStrike),
            13 => Some(PlyoExerciseName::HighBoxJump),
            14 => Some(PlyoExerciseName::WeightedHighBoxJump),
            15 => Some(PlyoExerciseName::IsometricExplosiveBodyWeightJumpSquat),
            16 => Some(PlyoExerciseName::WeightedIsometricExplosiveJumpSquat),
            17 => Some(PlyoExerciseName::LateralLeapAndHop),
            18 => Some(PlyoExerciseName::WeightedLateralLeapAndHop),
            19 => Some(PlyoExerciseName::LateralPlyoSquats),
            20 => Some(PlyoExerciseName::WeightedLateralPlyoSquats),
            21 => Some(PlyoExerciseName::LateralSlide),
            22 => Some(PlyoExerciseName::WeightedLateralSlide),
            23 => Some(PlyoExerciseName::MedicineBallOverheadThrows),
            24 => Some(PlyoExerciseName::MedicineBallSideThrow),
            25 => Some(PlyoExerciseName::MedicineBallSlam),
            26 => Some(PlyoExerciseName::SideToSideMedicineBallThrows),
            27 => Some(PlyoExerciseName::SideToSideShuffleJump),
            28 => Some(PlyoExerciseName::WeightedSideToSideShuffleJump),
            29 => Some(PlyoExerciseName::SquatJumpOntoBox),
            30 => Some(PlyoExerciseName::WeightedSquatJumpOntoBox),
            31 => Some(PlyoExerciseName::SquatJumpsInAndOut),
            32 => Some(PlyoExerciseName::WeightedSquatJumpsInAndOut),
            33 => Some(PlyoExerciseName::BoxJump),
            34 => Some(PlyoExerciseName::BoxJumpOvers),
            35 => Some(PlyoExerciseName::BoxJumpOversOverTheBox),
            36 => Some(PlyoExerciseName::StarJumpSquats),
            37 => Some(PlyoExerciseName::JumpSquat),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "alternating_jump_lunge" => Some(PlyoExerciseName::AlternatingJumpLunge),
            "weighted_alternating_jump_lunge" => {
                Some(PlyoExerciseName::WeightedAlternatingJumpLunge)
            }
            "barbell_jump_squat" => Some(PlyoExerciseName::BarbellJumpSquat),
            "body_weight_jump_squat" => Some(PlyoExerciseName::BodyWeightJumpSquat),
            "weighted_jump_squat" => Some(PlyoExerciseName::WeightedJumpSquat),
            "cross_knee_strike" => Some(PlyoExerciseName::CrossKneeStrike),
            "weighted_cross_knee_strike" => Some(PlyoExerciseName::WeightedCrossKneeStrike),
            "depth_jump" => Some(PlyoExerciseName::DepthJump),
            "weighted_depth_jump" => Some(PlyoExerciseName::WeightedDepthJump),
            "dumbbell_jump_squat" => Some(PlyoExerciseName::DumbbellJumpSquat),
            "dumbbell_split_jump" => Some(PlyoExerciseName::DumbbellSplitJump),
            "front_knee_strike" => Some(PlyoExerciseName::FrontKneeStrike),
            "weighted_front_knee_strike" => Some(PlyoExerciseName::WeightedFrontKneeStrike),
            "high_box_jump" => Some(PlyoExerciseName::HighBoxJump),
            "weighted_high_box_jump" => Some(PlyoExerciseName::WeightedHighBoxJump),
            "isometric_explosive_body_weight_jump_squat" => {
                Some(PlyoExerciseName::IsometricExplosiveBodyWeightJumpSquat)
            }
            "weighted_isometric_explosive_jump_squat" => {
                Some(PlyoExerciseName::WeightedIsometricExplosiveJumpSquat)
            }
            "lateral_leap_and_hop" => Some(PlyoExerciseName::LateralLeapAndHop),
            "weighted_lateral_leap_and_hop" => Some(PlyoExerciseName::WeightedLateralLeapAndHop),
            "lateral_plyo_squats" => Some(PlyoExerciseName::LateralPlyoSquats),
            "weighted_lateral_plyo_squats" => Some(PlyoExerciseName::WeightedLateralPlyoSquats),
            "lateral_slide" => Some(PlyoExerciseName::LateralSlide),
            "weighted_lateral_slide" => Some(PlyoExerciseName::WeightedLateralSlide),
            "medicine_ball_overhead_throws" => Some(PlyoExerciseName::MedicineBallOverheadThrows),
            "medicine_ball_side_throw" => Some(PlyoExerciseName::MedicineBallSideThrow),
            "medicine_ball_slam" => Some(PlyoExerciseName::MedicineBallSlam),
            "side_to_side_medicine_ball_throws" => {
                Some(PlyoExerciseName::SideToSideMedicineBallThrows)
            }
            "side_to_side_shuffle_jump" => Some(PlyoExerciseName::SideToSideShuffleJump),
            "weighted_side_to_side_shuffle_jump" => {
                Some(PlyoExerciseName::WeightedSideToSideShuffleJump)
            }
            "squat_jump_onto_box" => Some(PlyoExerciseName::SquatJumpOntoBox),
            "weighted_squat_jump_onto_box" => Some(PlyoExerciseName::WeightedSquatJumpOntoBox),
            "squat_jumps_in_and_out" => Some(PlyoExerciseName::SquatJumpsInAndOut),
            "weighted_squat_jumps_in_and_out" => Some(PlyoExerciseName::WeightedSquatJumpsInAndOut),
            "box_jump" => Some(PlyoExerciseName::BoxJump),
            "box_jump_overs" => Some(PlyoExerciseName::BoxJumpOvers),
            "box_jump_overs_over_the_box" => Some(PlyoExerciseName::BoxJumpOversOverTheBox),
            "star_jump_squats" => Some(PlyoExerciseName::StarJumpSquats),
            "jump_squat" => Some(PlyoExerciseName::JumpSquat),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum PullUpExerciseName {
    BandedPullUps = 0,
    _30DegreeLatPulldown = 1,
    BandAssistedChinUp = 2,
    CloseGripChinUp = 3,
    WeightedCloseGripChinUp = 4,
    CloseGripLatPulldown = 5,
    CrossoverChinUp = 6,
    WeightedCrossoverChinUp = 7,
    EzBarPullover = 8,
    HangingHurdle = 9,
    WeightedHangingHurdle = 10,
    KneelingLatPulldown = 11,
    KneelingUnderhandGripLatPulldown = 12,
    LatPulldown = 13,
    MixedGripChinUp = 14,
    WeightedMixedGripChinUp = 15,
    MixedGripPullUp = 16,
    WeightedMixedGripPullUp = 17,
    ReverseGripPulldown = 18,
    StandingCablePullover = 19,
    StraightArmPulldown = 20,
    SwissBallEzBarPullover = 21,
    TowelPullUp = 22,
    WeightedTowelPullUp = 23,
    WeightedPullUp = 24,
    WideGripLatPulldown = 25,
    WideGripPullUp = 26,
    WeightedWideGripPullUp = 27,
    BurpeePullUp = 28,
    WeightedBurpeePullUp = 29,
    JumpingPullUps = 30,
    WeightedJumpingPullUps = 31,
    KippingPullUp = 32,
    WeightedKippingPullUp = 33,
    LPullUp = 34,
    WeightedLPullUp = 35,
    SuspendedChinUp = 36,
    WeightedSuspendedChinUp = 37,
    PullUp = 38,
    ChinUp = 39,
    NeutralGripChinUp = 40,
    WeightedChinUp = 41,
    BandAssistedPullUp = 42,
    NeutralGripPullUp = 43,
    WeightedNeutralGripChinUp = 44,
    WeightedNeutralGripPullUp = 45,
}

impl PullUpExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            PullUpExerciseName::BandedPullUps => "banded_pull_ups",
            PullUpExerciseName::_30DegreeLatPulldown => "30_degree_lat_pulldown",
            PullUpExerciseName::BandAssistedChinUp => "band_assisted_chin_up",
            PullUpExerciseName::CloseGripChinUp => "close_grip_chin_up",
            PullUpExerciseName::WeightedCloseGripChinUp => "weighted_close_grip_chin_up",
            PullUpExerciseName::CloseGripLatPulldown => "close_grip_lat_pulldown",
            PullUpExerciseName::CrossoverChinUp => "crossover_chin_up",
            PullUpExerciseName::WeightedCrossoverChinUp => "weighted_crossover_chin_up",
            PullUpExerciseName::EzBarPullover => "ez_bar_pullover",
            PullUpExerciseName::HangingHurdle => "hanging_hurdle",
            PullUpExerciseName::WeightedHangingHurdle => "weighted_hanging_hurdle",
            PullUpExerciseName::KneelingLatPulldown => "kneeling_lat_pulldown",
            PullUpExerciseName::KneelingUnderhandGripLatPulldown => {
                "kneeling_underhand_grip_lat_pulldown"
            }
            PullUpExerciseName::LatPulldown => "lat_pulldown",
            PullUpExerciseName::MixedGripChinUp => "mixed_grip_chin_up",
            PullUpExerciseName::WeightedMixedGripChinUp => "weighted_mixed_grip_chin_up",
            PullUpExerciseName::MixedGripPullUp => "mixed_grip_pull_up",
            PullUpExerciseName::WeightedMixedGripPullUp => "weighted_mixed_grip_pull_up",
            PullUpExerciseName::ReverseGripPulldown => "reverse_grip_pulldown",
            PullUpExerciseName::StandingCablePullover => "standing_cable_pullover",
            PullUpExerciseName::StraightArmPulldown => "straight_arm_pulldown",
            PullUpExerciseName::SwissBallEzBarPullover => "swiss_ball_ez_bar_pullover",
            PullUpExerciseName::TowelPullUp => "towel_pull_up",
            PullUpExerciseName::WeightedTowelPullUp => "weighted_towel_pull_up",
            PullUpExerciseName::WeightedPullUp => "weighted_pull_up",
            PullUpExerciseName::WideGripLatPulldown => "wide_grip_lat_pulldown",
            PullUpExerciseName::WideGripPullUp => "wide_grip_pull_up",
            PullUpExerciseName::WeightedWideGripPullUp => "weighted_wide_grip_pull_up",
            PullUpExerciseName::BurpeePullUp => "burpee_pull_up",
            PullUpExerciseName::WeightedBurpeePullUp => "weighted_burpee_pull_up",
            PullUpExerciseName::JumpingPullUps => "jumping_pull_ups",
            PullUpExerciseName::WeightedJumpingPullUps => "weighted_jumping_pull_ups",
            PullUpExerciseName::KippingPullUp => "kipping_pull_up",
            PullUpExerciseName::WeightedKippingPullUp => "weighted_kipping_pull_up",
            PullUpExerciseName::LPullUp => "l_pull_up",
            PullUpExerciseName::WeightedLPullUp => "weighted_l_pull_up",
            PullUpExerciseName::SuspendedChinUp => "suspended_chin_up",
            PullUpExerciseName::WeightedSuspendedChinUp => "weighted_suspended_chin_up",
            PullUpExerciseName::PullUp => "pull_up",
            PullUpExerciseName::ChinUp => "chin_up",
            PullUpExerciseName::NeutralGripChinUp => "neutral_grip_chin_up",
            PullUpExerciseName::WeightedChinUp => "weighted_chin_up",
            PullUpExerciseName::BandAssistedPullUp => "band_assisted_pull_up",
            PullUpExerciseName::NeutralGripPullUp => "neutral_grip_pull_up",
            PullUpExerciseName::WeightedNeutralGripChinUp => "weighted_neutral_grip_chin_up",
            PullUpExerciseName::WeightedNeutralGripPullUp => "weighted_neutral_grip_pull_up",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(PullUpExerciseName::BandedPullUps),
            1 => Some(PullUpExerciseName::_30DegreeLatPulldown),
            2 => Some(PullUpExerciseName::BandAssistedChinUp),
            3 => Some(PullUpExerciseName::CloseGripChinUp),
            4 => Some(PullUpExerciseName::WeightedCloseGripChinUp),
            5 => Some(PullUpExerciseName::CloseGripLatPulldown),
            6 => Some(PullUpExerciseName::CrossoverChinUp),
            7 => Some(PullUpExerciseName::WeightedCrossoverChinUp),
            8 => Some(PullUpExerciseName::EzBarPullover),
            9 => Some(PullUpExerciseName::HangingHurdle),
            10 => Some(PullUpExerciseName::WeightedHangingHurdle),
            11 => Some(PullUpExerciseName::KneelingLatPulldown),
            12 => Some(PullUpExerciseName::KneelingUnderhandGripLatPulldown),
            13 => Some(PullUpExerciseName::LatPulldown),
            14 => Some(PullUpExerciseName::MixedGripChinUp),
            15 => Some(PullUpExerciseName::WeightedMixedGripChinUp),
            16 => Some(PullUpExerciseName::MixedGripPullUp),
            17 => Some(PullUpExerciseName::WeightedMixedGripPullUp),
            18 => Some(PullUpExerciseName::ReverseGripPulldown),
            19 => Some(PullUpExerciseName::StandingCablePullover),
            20 => Some(PullUpExerciseName::StraightArmPulldown),
            21 => Some(PullUpExerciseName::SwissBallEzBarPullover),
            22 => Some(PullUpExerciseName::TowelPullUp),
            23 => Some(PullUpExerciseName::WeightedTowelPullUp),
            24 => Some(PullUpExerciseName::WeightedPullUp),
            25 => Some(PullUpExerciseName::WideGripLatPulldown),
            26 => Some(PullUpExerciseName::WideGripPullUp),
            27 => Some(PullUpExerciseName::WeightedWideGripPullUp),
            28 => Some(PullUpExerciseName::BurpeePullUp),
            29 => Some(PullUpExerciseName::WeightedBurpeePullUp),
            30 => Some(PullUpExerciseName::JumpingPullUps),
            31 => Some(PullUpExerciseName::WeightedJumpingPullUps),
            32 => Some(PullUpExerciseName::KippingPullUp),
            33 => Some(PullUpExerciseName::WeightedKippingPullUp),
            34 => Some(PullUpExerciseName::LPullUp),
            35 => Some(PullUpExerciseName::WeightedLPullUp),
            36 => Some(PullUpExerciseName::SuspendedChinUp),
            37 => Some(PullUpExerciseName::WeightedSuspendedChinUp),
            38 => Some(PullUpExerciseName::PullUp),
            39 => Some(PullUpExerciseName::ChinUp),
            40 => Some(PullUpExerciseName::NeutralGripChinUp),
            41 => Some(PullUpExerciseName::WeightedChinUp),
            42 => Some(PullUpExerciseName::BandAssistedPullUp),
            43 => Some(PullUpExerciseName::NeutralGripPullUp),
            44 => Some(PullUpExerciseName::WeightedNeutralGripChinUp),
            45 => Some(PullUpExerciseName::WeightedNeutralGripPullUp),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "banded_pull_ups" => Some(PullUpExerciseName::BandedPullUps),
            "30_degree_lat_pulldown" => Some(PullUpExerciseName::_30DegreeLatPulldown),
            "band_assisted_chin_up" => Some(PullUpExerciseName::BandAssistedChinUp),
            "close_grip_chin_up" => Some(PullUpExerciseName::CloseGripChinUp),
            "weighted_close_grip_chin_up" => Some(PullUpExerciseName::WeightedCloseGripChinUp),
            "close_grip_lat_pulldown" => Some(PullUpExerciseName::CloseGripLatPulldown),
            "crossover_chin_up" => Some(PullUpExerciseName::CrossoverChinUp),
            "weighted_crossover_chin_up" => Some(PullUpExerciseName::WeightedCrossoverChinUp),
            "ez_bar_pullover" => Some(PullUpExerciseName::EzBarPullover),
            "hanging_hurdle" => Some(PullUpExerciseName::HangingHurdle),
            "weighted_hanging_hurdle" => Some(PullUpExerciseName::WeightedHangingHurdle),
            "kneeling_lat_pulldown" => Some(PullUpExerciseName::KneelingLatPulldown),
            "kneeling_underhand_grip_lat_pulldown" => {
                Some(PullUpExerciseName::KneelingUnderhandGripLatPulldown)
            }
            "lat_pulldown" => Some(PullUpExerciseName::LatPulldown),
            "mixed_grip_chin_up" => Some(PullUpExerciseName::MixedGripChinUp),
            "weighted_mixed_grip_chin_up" => Some(PullUpExerciseName::WeightedMixedGripChinUp),
            "mixed_grip_pull_up" => Some(PullUpExerciseName::MixedGripPullUp),
            "weighted_mixed_grip_pull_up" => Some(PullUpExerciseName::WeightedMixedGripPullUp),
            "reverse_grip_pulldown" => Some(PullUpExerciseName::ReverseGripPulldown),
            "standing_cable_pullover" => Some(PullUpExerciseName::StandingCablePullover),
            "straight_arm_pulldown" => Some(PullUpExerciseName::StraightArmPulldown),
            "swiss_ball_ez_bar_pullover" => Some(PullUpExerciseName::SwissBallEzBarPullover),
            "towel_pull_up" => Some(PullUpExerciseName::TowelPullUp),
            "weighted_towel_pull_up" => Some(PullUpExerciseName::WeightedTowelPullUp),
            "weighted_pull_up" => Some(PullUpExerciseName::WeightedPullUp),
            "wide_grip_lat_pulldown" => Some(PullUpExerciseName::WideGripLatPulldown),
            "wide_grip_pull_up" => Some(PullUpExerciseName::WideGripPullUp),
            "weighted_wide_grip_pull_up" => Some(PullUpExerciseName::WeightedWideGripPullUp),
            "burpee_pull_up" => Some(PullUpExerciseName::BurpeePullUp),
            "weighted_burpee_pull_up" => Some(PullUpExerciseName::WeightedBurpeePullUp),
            "jumping_pull_ups" => Some(PullUpExerciseName::JumpingPullUps),
            "weighted_jumping_pull_ups" => Some(PullUpExerciseName::WeightedJumpingPullUps),
            "kipping_pull_up" => Some(PullUpExerciseName::KippingPullUp),
            "weighted_kipping_pull_up" => Some(PullUpExerciseName::WeightedKippingPullUp),
            "l_pull_up" => Some(PullUpExerciseName::LPullUp),
            "weighted_l_pull_up" => Some(PullUpExerciseName::WeightedLPullUp),
            "suspended_chin_up" => Some(PullUpExerciseName::SuspendedChinUp),
            "weighted_suspended_chin_up" => Some(PullUpExerciseName::WeightedSuspendedChinUp),
            "pull_up" => Some(PullUpExerciseName::PullUp),
            "chin_up" => Some(PullUpExerciseName::ChinUp),
            "neutral_grip_chin_up" => Some(PullUpExerciseName::NeutralGripChinUp),
            "weighted_chin_up" => Some(PullUpExerciseName::WeightedChinUp),
            "band_assisted_pull_up" => Some(PullUpExerciseName::BandAssistedPullUp),
            "neutral_grip_pull_up" => Some(PullUpExerciseName::NeutralGripPullUp),
            "weighted_neutral_grip_chin_up" => Some(PullUpExerciseName::WeightedNeutralGripChinUp),
            "weighted_neutral_grip_pull_up" => Some(PullUpExerciseName::WeightedNeutralGripPullUp),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum PushUpExerciseName {
    ChestPressWithBand = 0,
    AlternatingStaggeredPushUp = 1,
    WeightedAlternatingStaggeredPushUp = 2,
    AlternatingHandsMedicineBallPushUp = 3,
    WeightedAlternatingHandsMedicineBallPushUp = 4,
    BosuBallPushUp = 5,
    WeightedBosuBallPushUp = 6,
    ClappingPushUp = 7,
    WeightedClappingPushUp = 8,
    CloseGripMedicineBallPushUp = 9,
    WeightedCloseGripMedicineBallPushUp = 10,
    CloseHandsPushUp = 11,
    WeightedCloseHandsPushUp = 12,
    DeclinePushUp = 13,
    WeightedDeclinePushUp = 14,
    DiamondPushUp = 15,
    WeightedDiamondPushUp = 16,
    ExplosiveCrossoverPushUp = 17,
    WeightedExplosiveCrossoverPushUp = 18,
    ExplosivePushUp = 19,
    WeightedExplosivePushUp = 20,
    FeetElevatedSideToSidePushUp = 21,
    WeightedFeetElevatedSideToSidePushUp = 22,
    HandReleasePushUp = 23,
    WeightedHandReleasePushUp = 24,
    HandstandPushUp = 25,
    WeightedHandstandPushUp = 26,
    InclinePushUp = 27,
    WeightedInclinePushUp = 28,
    IsometricExplosivePushUp = 29,
    WeightedIsometricExplosivePushUp = 30,
    JudoPushUp = 31,
    WeightedJudoPushUp = 32,
    KneelingPushUp = 33,
    WeightedKneelingPushUp = 34,
    MedicineBallChestPass = 35,
    MedicineBallPushUp = 36,
    WeightedMedicineBallPushUp = 37,
    OneArmPushUp = 38,
    WeightedOneArmPushUp = 39,
    WeightedPushUp = 40,
    PushUpAndRow = 41,
    WeightedPushUpAndRow = 42,
    PushUpPlus = 43,
    WeightedPushUpPlus = 44,
    PushUpWithFeetOnSwissBall = 45,
    WeightedPushUpWithFeetOnSwissBall = 46,
    PushUpWithOneHandOnMedicineBall = 47,
    WeightedPushUpWithOneHandOnMedicineBall = 48,
    ShoulderPushUp = 49,
    WeightedShoulderPushUp = 50,
    SingleArmMedicineBallPushUp = 51,
    WeightedSingleArmMedicineBallPushUp = 52,
    SpidermanPushUp = 53,
    WeightedSpidermanPushUp = 54,
    StackedFeetPushUp = 55,
    WeightedStackedFeetPushUp = 56,
    StaggeredHandsPushUp = 57,
    WeightedStaggeredHandsPushUp = 58,
    SuspendedPushUp = 59,
    WeightedSuspendedPushUp = 60,
    SwissBallPushUp = 61,
    WeightedSwissBallPushUp = 62,
    SwissBallPushUpPlus = 63,
    WeightedSwissBallPushUpPlus = 64,
    TPushUp = 65,
    WeightedTPushUp = 66,
    TripleStopPushUp = 67,
    WeightedTripleStopPushUp = 68,
    WideHandsPushUp = 69,
    WeightedWideHandsPushUp = 70,
    ParalletteHandstandPushUp = 71,
    WeightedParalletteHandstandPushUp = 72,
    RingHandstandPushUp = 73,
    WeightedRingHandstandPushUp = 74,
    RingPushUp = 75,
    WeightedRingPushUp = 76,
    PushUp = 77,
    PilatesPushup = 78,
    DynamicPushUp = 79,
    KippingHandstandPushUp = 80,
    ShoulderTappingPushUp = 81,
    BicepsPushUp = 82,
    HinduPushUp = 83,
    PikePushUp = 84,
    WideGripPushUp = 85,
    WeightedBicepsPushUp = 86,
    WeightedHinduPushUp = 87,
    WeightedPikePushUp = 88,
    KippingParalletteHandstandPushUp = 89,
    WallPushUp = 90,
}

impl PushUpExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            PushUpExerciseName::ChestPressWithBand => "chest_press_with_band",
            PushUpExerciseName::AlternatingStaggeredPushUp => "alternating_staggered_push_up",
            PushUpExerciseName::WeightedAlternatingStaggeredPushUp => {
                "weighted_alternating_staggered_push_up"
            }
            PushUpExerciseName::AlternatingHandsMedicineBallPushUp => {
                "alternating_hands_medicine_ball_push_up"
            }
            PushUpExerciseName::WeightedAlternatingHandsMedicineBallPushUp => {
                "weighted_alternating_hands_medicine_ball_push_up"
            }
            PushUpExerciseName::BosuBallPushUp => "bosu_ball_push_up",
            PushUpExerciseName::WeightedBosuBallPushUp => "weighted_bosu_ball_push_up",
            PushUpExerciseName::ClappingPushUp => "clapping_push_up",
            PushUpExerciseName::WeightedClappingPushUp => "weighted_clapping_push_up",
            PushUpExerciseName::CloseGripMedicineBallPushUp => "close_grip_medicine_ball_push_up",
            PushUpExerciseName::WeightedCloseGripMedicineBallPushUp => {
                "weighted_close_grip_medicine_ball_push_up"
            }
            PushUpExerciseName::CloseHandsPushUp => "close_hands_push_up",
            PushUpExerciseName::WeightedCloseHandsPushUp => "weighted_close_hands_push_up",
            PushUpExerciseName::DeclinePushUp => "decline_push_up",
            PushUpExerciseName::WeightedDeclinePushUp => "weighted_decline_push_up",
            PushUpExerciseName::DiamondPushUp => "diamond_push_up",
            PushUpExerciseName::WeightedDiamondPushUp => "weighted_diamond_push_up",
            PushUpExerciseName::ExplosiveCrossoverPushUp => "explosive_crossover_push_up",
            PushUpExerciseName::WeightedExplosiveCrossoverPushUp => {
                "weighted_explosive_crossover_push_up"
            }
            PushUpExerciseName::ExplosivePushUp => "explosive_push_up",
            PushUpExerciseName::WeightedExplosivePushUp => "weighted_explosive_push_up",
            PushUpExerciseName::FeetElevatedSideToSidePushUp => {
                "feet_elevated_side_to_side_push_up"
            }
            PushUpExerciseName::WeightedFeetElevatedSideToSidePushUp => {
                "weighted_feet_elevated_side_to_side_push_up"
            }
            PushUpExerciseName::HandReleasePushUp => "hand_release_push_up",
            PushUpExerciseName::WeightedHandReleasePushUp => "weighted_hand_release_push_up",
            PushUpExerciseName::HandstandPushUp => "handstand_push_up",
            PushUpExerciseName::WeightedHandstandPushUp => "weighted_handstand_push_up",
            PushUpExerciseName::InclinePushUp => "incline_push_up",
            PushUpExerciseName::WeightedInclinePushUp => "weighted_incline_push_up",
            PushUpExerciseName::IsometricExplosivePushUp => "isometric_explosive_push_up",
            PushUpExerciseName::WeightedIsometricExplosivePushUp => {
                "weighted_isometric_explosive_push_up"
            }
            PushUpExerciseName::JudoPushUp => "judo_push_up",
            PushUpExerciseName::WeightedJudoPushUp => "weighted_judo_push_up",
            PushUpExerciseName::KneelingPushUp => "kneeling_push_up",
            PushUpExerciseName::WeightedKneelingPushUp => "weighted_kneeling_push_up",
            PushUpExerciseName::MedicineBallChestPass => "medicine_ball_chest_pass",
            PushUpExerciseName::MedicineBallPushUp => "medicine_ball_push_up",
            PushUpExerciseName::WeightedMedicineBallPushUp => "weighted_medicine_ball_push_up",
            PushUpExerciseName::OneArmPushUp => "one_arm_push_up",
            PushUpExerciseName::WeightedOneArmPushUp => "weighted_one_arm_push_up",
            PushUpExerciseName::WeightedPushUp => "weighted_push_up",
            PushUpExerciseName::PushUpAndRow => "push_up_and_row",
            PushUpExerciseName::WeightedPushUpAndRow => "weighted_push_up_and_row",
            PushUpExerciseName::PushUpPlus => "push_up_plus",
            PushUpExerciseName::WeightedPushUpPlus => "weighted_push_up_plus",
            PushUpExerciseName::PushUpWithFeetOnSwissBall => "push_up_with_feet_on_swiss_ball",
            PushUpExerciseName::WeightedPushUpWithFeetOnSwissBall => {
                "weighted_push_up_with_feet_on_swiss_ball"
            }
            PushUpExerciseName::PushUpWithOneHandOnMedicineBall => {
                "push_up_with_one_hand_on_medicine_ball"
            }
            PushUpExerciseName::WeightedPushUpWithOneHandOnMedicineBall => {
                "weighted_push_up_with_one_hand_on_medicine_ball"
            }
            PushUpExerciseName::ShoulderPushUp => "shoulder_push_up",
            PushUpExerciseName::WeightedShoulderPushUp => "weighted_shoulder_push_up",
            PushUpExerciseName::SingleArmMedicineBallPushUp => "single_arm_medicine_ball_push_up",
            PushUpExerciseName::WeightedSingleArmMedicineBallPushUp => {
                "weighted_single_arm_medicine_ball_push_up"
            }
            PushUpExerciseName::SpidermanPushUp => "spiderman_push_up",
            PushUpExerciseName::WeightedSpidermanPushUp => "weighted_spiderman_push_up",
            PushUpExerciseName::StackedFeetPushUp => "stacked_feet_push_up",
            PushUpExerciseName::WeightedStackedFeetPushUp => "weighted_stacked_feet_push_up",
            PushUpExerciseName::StaggeredHandsPushUp => "staggered_hands_push_up",
            PushUpExerciseName::WeightedStaggeredHandsPushUp => "weighted_staggered_hands_push_up",
            PushUpExerciseName::SuspendedPushUp => "suspended_push_up",
            PushUpExerciseName::WeightedSuspendedPushUp => "weighted_suspended_push_up",
            PushUpExerciseName::SwissBallPushUp => "swiss_ball_push_up",
            PushUpExerciseName::WeightedSwissBallPushUp => "weighted_swiss_ball_push_up",
            PushUpExerciseName::SwissBallPushUpPlus => "swiss_ball_push_up_plus",
            PushUpExerciseName::WeightedSwissBallPushUpPlus => "weighted_swiss_ball_push_up_plus",
            PushUpExerciseName::TPushUp => "t_push_up",
            PushUpExerciseName::WeightedTPushUp => "weighted_t_push_up",
            PushUpExerciseName::TripleStopPushUp => "triple_stop_push_up",
            PushUpExerciseName::WeightedTripleStopPushUp => "weighted_triple_stop_push_up",
            PushUpExerciseName::WideHandsPushUp => "wide_hands_push_up",
            PushUpExerciseName::WeightedWideHandsPushUp => "weighted_wide_hands_push_up",
            PushUpExerciseName::ParalletteHandstandPushUp => "parallette_handstand_push_up",
            PushUpExerciseName::WeightedParalletteHandstandPushUp => {
                "weighted_parallette_handstand_push_up"
            }
            PushUpExerciseName::RingHandstandPushUp => "ring_handstand_push_up",
            PushUpExerciseName::WeightedRingHandstandPushUp => "weighted_ring_handstand_push_up",
            PushUpExerciseName::RingPushUp => "ring_push_up",
            PushUpExerciseName::WeightedRingPushUp => "weighted_ring_push_up",
            PushUpExerciseName::PushUp => "push_up",
            PushUpExerciseName::PilatesPushup => "pilates_pushup",
            PushUpExerciseName::DynamicPushUp => "dynamic_push_up",
            PushUpExerciseName::KippingHandstandPushUp => "kipping_handstand_push_up",
            PushUpExerciseName::ShoulderTappingPushUp => "shoulder_tapping_push_up",
            PushUpExerciseName::BicepsPushUp => "biceps_push_up",
            PushUpExerciseName::HinduPushUp => "hindu_push_up",
            PushUpExerciseName::PikePushUp => "pike_push_up",
            PushUpExerciseName::WideGripPushUp => "wide_grip_push_up",
            PushUpExerciseName::WeightedBicepsPushUp => "weighted_biceps_push_up",
            PushUpExerciseName::WeightedHinduPushUp => "weighted_hindu_push_up",
            PushUpExerciseName::WeightedPikePushUp => "weighted_pike_push_up",
            PushUpExerciseName::KippingParalletteHandstandPushUp => {
                "kipping_parallette_handstand_push_up"
            }
            PushUpExerciseName::WallPushUp => "wall_push_up",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(PushUpExerciseName::ChestPressWithBand),
            1 => Some(PushUpExerciseName::AlternatingStaggeredPushUp),
            2 => Some(PushUpExerciseName::WeightedAlternatingStaggeredPushUp),
            3 => Some(PushUpExerciseName::AlternatingHandsMedicineBallPushUp),
            4 => Some(PushUpExerciseName::WeightedAlternatingHandsMedicineBallPushUp),
            5 => Some(PushUpExerciseName::BosuBallPushUp),
            6 => Some(PushUpExerciseName::WeightedBosuBallPushUp),
            7 => Some(PushUpExerciseName::ClappingPushUp),
            8 => Some(PushUpExerciseName::WeightedClappingPushUp),
            9 => Some(PushUpExerciseName::CloseGripMedicineBallPushUp),
            10 => Some(PushUpExerciseName::WeightedCloseGripMedicineBallPushUp),
            11 => Some(PushUpExerciseName::CloseHandsPushUp),
            12 => Some(PushUpExerciseName::WeightedCloseHandsPushUp),
            13 => Some(PushUpExerciseName::DeclinePushUp),
            14 => Some(PushUpExerciseName::WeightedDeclinePushUp),
            15 => Some(PushUpExerciseName::DiamondPushUp),
            16 => Some(PushUpExerciseName::WeightedDiamondPushUp),
            17 => Some(PushUpExerciseName::ExplosiveCrossoverPushUp),
            18 => Some(PushUpExerciseName::WeightedExplosiveCrossoverPushUp),
            19 => Some(PushUpExerciseName::ExplosivePushUp),
            20 => Some(PushUpExerciseName::WeightedExplosivePushUp),
            21 => Some(PushUpExerciseName::FeetElevatedSideToSidePushUp),
            22 => Some(PushUpExerciseName::WeightedFeetElevatedSideToSidePushUp),
            23 => Some(PushUpExerciseName::HandReleasePushUp),
            24 => Some(PushUpExerciseName::WeightedHandReleasePushUp),
            25 => Some(PushUpExerciseName::HandstandPushUp),
            26 => Some(PushUpExerciseName::WeightedHandstandPushUp),
            27 => Some(PushUpExerciseName::InclinePushUp),
            28 => Some(PushUpExerciseName::WeightedInclinePushUp),
            29 => Some(PushUpExerciseName::IsometricExplosivePushUp),
            30 => Some(PushUpExerciseName::WeightedIsometricExplosivePushUp),
            31 => Some(PushUpExerciseName::JudoPushUp),
            32 => Some(PushUpExerciseName::WeightedJudoPushUp),
            33 => Some(PushUpExerciseName::KneelingPushUp),
            34 => Some(PushUpExerciseName::WeightedKneelingPushUp),
            35 => Some(PushUpExerciseName::MedicineBallChestPass),
            36 => Some(PushUpExerciseName::MedicineBallPushUp),
            37 => Some(PushUpExerciseName::WeightedMedicineBallPushUp),
            38 => Some(PushUpExerciseName::OneArmPushUp),
            39 => Some(PushUpExerciseName::WeightedOneArmPushUp),
            40 => Some(PushUpExerciseName::WeightedPushUp),
            41 => Some(PushUpExerciseName::PushUpAndRow),
            42 => Some(PushUpExerciseName::WeightedPushUpAndRow),
            43 => Some(PushUpExerciseName::PushUpPlus),
            44 => Some(PushUpExerciseName::WeightedPushUpPlus),
            45 => Some(PushUpExerciseName::PushUpWithFeetOnSwissBall),
            46 => Some(PushUpExerciseName::WeightedPushUpWithFeetOnSwissBall),
            47 => Some(PushUpExerciseName::PushUpWithOneHandOnMedicineBall),
            48 => Some(PushUpExerciseName::WeightedPushUpWithOneHandOnMedicineBall),
            49 => Some(PushUpExerciseName::ShoulderPushUp),
            50 => Some(PushUpExerciseName::WeightedShoulderPushUp),
            51 => Some(PushUpExerciseName::SingleArmMedicineBallPushUp),
            52 => Some(PushUpExerciseName::WeightedSingleArmMedicineBallPushUp),
            53 => Some(PushUpExerciseName::SpidermanPushUp),
            54 => Some(PushUpExerciseName::WeightedSpidermanPushUp),
            55 => Some(PushUpExerciseName::StackedFeetPushUp),
            56 => Some(PushUpExerciseName::WeightedStackedFeetPushUp),
            57 => Some(PushUpExerciseName::StaggeredHandsPushUp),
            58 => Some(PushUpExerciseName::WeightedStaggeredHandsPushUp),
            59 => Some(PushUpExerciseName::SuspendedPushUp),
            60 => Some(PushUpExerciseName::WeightedSuspendedPushUp),
            61 => Some(PushUpExerciseName::SwissBallPushUp),
            62 => Some(PushUpExerciseName::WeightedSwissBallPushUp),
            63 => Some(PushUpExerciseName::SwissBallPushUpPlus),
            64 => Some(PushUpExerciseName::WeightedSwissBallPushUpPlus),
            65 => Some(PushUpExerciseName::TPushUp),
            66 => Some(PushUpExerciseName::WeightedTPushUp),
            67 => Some(PushUpExerciseName::TripleStopPushUp),
            68 => Some(PushUpExerciseName::WeightedTripleStopPushUp),
            69 => Some(PushUpExerciseName::WideHandsPushUp),
            70 => Some(PushUpExerciseName::WeightedWideHandsPushUp),
            71 => Some(PushUpExerciseName::ParalletteHandstandPushUp),
            72 => Some(PushUpExerciseName::WeightedParalletteHandstandPushUp),
            73 => Some(PushUpExerciseName::RingHandstandPushUp),
            74 => Some(PushUpExerciseName::WeightedRingHandstandPushUp),
            75 => Some(PushUpExerciseName::RingPushUp),
            76 => Some(PushUpExerciseName::WeightedRingPushUp),
            77 => Some(PushUpExerciseName::PushUp),
            78 => Some(PushUpExerciseName::PilatesPushup),
            79 => Some(PushUpExerciseName::DynamicPushUp),
            80 => Some(PushUpExerciseName::KippingHandstandPushUp),
            81 => Some(PushUpExerciseName::ShoulderTappingPushUp),
            82 => Some(PushUpExerciseName::BicepsPushUp),
            83 => Some(PushUpExerciseName::HinduPushUp),
            84 => Some(PushUpExerciseName::PikePushUp),
            85 => Some(PushUpExerciseName::WideGripPushUp),
            86 => Some(PushUpExerciseName::WeightedBicepsPushUp),
            87 => Some(PushUpExerciseName::WeightedHinduPushUp),
            88 => Some(PushUpExerciseName::WeightedPikePushUp),
            89 => Some(PushUpExerciseName::KippingParalletteHandstandPushUp),
            90 => Some(PushUpExerciseName::WallPushUp),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "chest_press_with_band" => Some(PushUpExerciseName::ChestPressWithBand),
            "alternating_staggered_push_up" => Some(PushUpExerciseName::AlternatingStaggeredPushUp),
            "weighted_alternating_staggered_push_up" => {
                Some(PushUpExerciseName::WeightedAlternatingStaggeredPushUp)
            }
            "alternating_hands_medicine_ball_push_up" => {
                Some(PushUpExerciseName::AlternatingHandsMedicineBallPushUp)
            }
            "weighted_alternating_hands_medicine_ball_push_up" => {
                Some(PushUpExerciseName::WeightedAlternatingHandsMedicineBallPushUp)
            }
            "bosu_ball_push_up" => Some(PushUpExerciseName::BosuBallPushUp),
            "weighted_bosu_ball_push_up" => Some(PushUpExerciseName::WeightedBosuBallPushUp),
            "clapping_push_up" => Some(PushUpExerciseName::ClappingPushUp),
            "weighted_clapping_push_up" => Some(PushUpExerciseName::WeightedClappingPushUp),
            "close_grip_medicine_ball_push_up" => {
                Some(PushUpExerciseName::CloseGripMedicineBallPushUp)
            }
            "weighted_close_grip_medicine_ball_push_up" => {
                Some(PushUpExerciseName::WeightedCloseGripMedicineBallPushUp)
            }
            "close_hands_push_up" => Some(PushUpExerciseName::CloseHandsPushUp),
            "weighted_close_hands_push_up" => Some(PushUpExerciseName::WeightedCloseHandsPushUp),
            "decline_push_up" => Some(PushUpExerciseName::DeclinePushUp),
            "weighted_decline_push_up" => Some(PushUpExerciseName::WeightedDeclinePushUp),
            "diamond_push_up" => Some(PushUpExerciseName::DiamondPushUp),
            "weighted_diamond_push_up" => Some(PushUpExerciseName::WeightedDiamondPushUp),
            "explosive_crossover_push_up" => Some(PushUpExerciseName::ExplosiveCrossoverPushUp),
            "weighted_explosive_crossover_push_up" => {
                Some(PushUpExerciseName::WeightedExplosiveCrossoverPushUp)
            }
            "explosive_push_up" => Some(PushUpExerciseName::ExplosivePushUp),
            "weighted_explosive_push_up" => Some(PushUpExerciseName::WeightedExplosivePushUp),
            "feet_elevated_side_to_side_push_up" => {
                Some(PushUpExerciseName::FeetElevatedSideToSidePushUp)
            }
            "weighted_feet_elevated_side_to_side_push_up" => {
                Some(PushUpExerciseName::WeightedFeetElevatedSideToSidePushUp)
            }
            "hand_release_push_up" => Some(PushUpExerciseName::HandReleasePushUp),
            "weighted_hand_release_push_up" => Some(PushUpExerciseName::WeightedHandReleasePushUp),
            "handstand_push_up" => Some(PushUpExerciseName::HandstandPushUp),
            "weighted_handstand_push_up" => Some(PushUpExerciseName::WeightedHandstandPushUp),
            "incline_push_up" => Some(PushUpExerciseName::InclinePushUp),
            "weighted_incline_push_up" => Some(PushUpExerciseName::WeightedInclinePushUp),
            "isometric_explosive_push_up" => Some(PushUpExerciseName::IsometricExplosivePushUp),
            "weighted_isometric_explosive_push_up" => {
                Some(PushUpExerciseName::WeightedIsometricExplosivePushUp)
            }
            "judo_push_up" => Some(PushUpExerciseName::JudoPushUp),
            "weighted_judo_push_up" => Some(PushUpExerciseName::WeightedJudoPushUp),
            "kneeling_push_up" => Some(PushUpExerciseName::KneelingPushUp),
            "weighted_kneeling_push_up" => Some(PushUpExerciseName::WeightedKneelingPushUp),
            "medicine_ball_chest_pass" => Some(PushUpExerciseName::MedicineBallChestPass),
            "medicine_ball_push_up" => Some(PushUpExerciseName::MedicineBallPushUp),
            "weighted_medicine_ball_push_up" => {
                Some(PushUpExerciseName::WeightedMedicineBallPushUp)
            }
            "one_arm_push_up" => Some(PushUpExerciseName::OneArmPushUp),
            "weighted_one_arm_push_up" => Some(PushUpExerciseName::WeightedOneArmPushUp),
            "weighted_push_up" => Some(PushUpExerciseName::WeightedPushUp),
            "push_up_and_row" => Some(PushUpExerciseName::PushUpAndRow),
            "weighted_push_up_and_row" => Some(PushUpExerciseName::WeightedPushUpAndRow),
            "push_up_plus" => Some(PushUpExerciseName::PushUpPlus),
            "weighted_push_up_plus" => Some(PushUpExerciseName::WeightedPushUpPlus),
            "push_up_with_feet_on_swiss_ball" => {
                Some(PushUpExerciseName::PushUpWithFeetOnSwissBall)
            }
            "weighted_push_up_with_feet_on_swiss_ball" => {
                Some(PushUpExerciseName::WeightedPushUpWithFeetOnSwissBall)
            }
            "push_up_with_one_hand_on_medicine_ball" => {
                Some(PushUpExerciseName::PushUpWithOneHandOnMedicineBall)
            }
            "weighted_push_up_with_one_hand_on_medicine_ball" => {
                Some(PushUpExerciseName::WeightedPushUpWithOneHandOnMedicineBall)
            }
            "shoulder_push_up" => Some(PushUpExerciseName::ShoulderPushUp),
            "weighted_shoulder_push_up" => Some(PushUpExerciseName::WeightedShoulderPushUp),
            "single_arm_medicine_ball_push_up" => {
                Some(PushUpExerciseName::SingleArmMedicineBallPushUp)
            }
            "weighted_single_arm_medicine_ball_push_up" => {
                Some(PushUpExerciseName::WeightedSingleArmMedicineBallPushUp)
            }
            "spiderman_push_up" => Some(PushUpExerciseName::SpidermanPushUp),
            "weighted_spiderman_push_up" => Some(PushUpExerciseName::WeightedSpidermanPushUp),
            "stacked_feet_push_up" => Some(PushUpExerciseName::StackedFeetPushUp),
            "weighted_stacked_feet_push_up" => Some(PushUpExerciseName::WeightedStackedFeetPushUp),
            "staggered_hands_push_up" => Some(PushUpExerciseName::StaggeredHandsPushUp),
            "weighted_staggered_hands_push_up" => {
                Some(PushUpExerciseName::WeightedStaggeredHandsPushUp)
            }
            "suspended_push_up" => Some(PushUpExerciseName::SuspendedPushUp),
            "weighted_suspended_push_up" => Some(PushUpExerciseName::WeightedSuspendedPushUp),
            "swiss_ball_push_up" => Some(PushUpExerciseName::SwissBallPushUp),
            "weighted_swiss_ball_push_up" => Some(PushUpExerciseName::WeightedSwissBallPushUp),
            "swiss_ball_push_up_plus" => Some(PushUpExerciseName::SwissBallPushUpPlus),
            "weighted_swiss_ball_push_up_plus" => {
                Some(PushUpExerciseName::WeightedSwissBallPushUpPlus)
            }
            "t_push_up" => Some(PushUpExerciseName::TPushUp),
            "weighted_t_push_up" => Some(PushUpExerciseName::WeightedTPushUp),
            "triple_stop_push_up" => Some(PushUpExerciseName::TripleStopPushUp),
            "weighted_triple_stop_push_up" => Some(PushUpExerciseName::WeightedTripleStopPushUp),
            "wide_hands_push_up" => Some(PushUpExerciseName::WideHandsPushUp),
            "weighted_wide_hands_push_up" => Some(PushUpExerciseName::WeightedWideHandsPushUp),
            "parallette_handstand_push_up" => Some(PushUpExerciseName::ParalletteHandstandPushUp),
            "weighted_parallette_handstand_push_up" => {
                Some(PushUpExerciseName::WeightedParalletteHandstandPushUp)
            }
            "ring_handstand_push_up" => Some(PushUpExerciseName::RingHandstandPushUp),
            "weighted_ring_handstand_push_up" => {
                Some(PushUpExerciseName::WeightedRingHandstandPushUp)
            }
            "ring_push_up" => Some(PushUpExerciseName::RingPushUp),
            "weighted_ring_push_up" => Some(PushUpExerciseName::WeightedRingPushUp),
            "push_up" => Some(PushUpExerciseName::PushUp),
            "pilates_pushup" => Some(PushUpExerciseName::PilatesPushup),
            "dynamic_push_up" => Some(PushUpExerciseName::DynamicPushUp),
            "kipping_handstand_push_up" => Some(PushUpExerciseName::KippingHandstandPushUp),
            "shoulder_tapping_push_up" => Some(PushUpExerciseName::ShoulderTappingPushUp),
            "biceps_push_up" => Some(PushUpExerciseName::BicepsPushUp),
            "hindu_push_up" => Some(PushUpExerciseName::HinduPushUp),
            "pike_push_up" => Some(PushUpExerciseName::PikePushUp),
            "wide_grip_push_up" => Some(PushUpExerciseName::WideGripPushUp),
            "weighted_biceps_push_up" => Some(PushUpExerciseName::WeightedBicepsPushUp),
            "weighted_hindu_push_up" => Some(PushUpExerciseName::WeightedHinduPushUp),
            "weighted_pike_push_up" => Some(PushUpExerciseName::WeightedPikePushUp),
            "kipping_parallette_handstand_push_up" => {
                Some(PushUpExerciseName::KippingParalletteHandstandPushUp)
            }
            "wall_push_up" => Some(PushUpExerciseName::WallPushUp),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum RowExerciseName {
    BarbellStraightLegDeadliftToRow = 0,
    CableRowStanding = 1,
    DumbbellRow = 2,
    ElevatedFeetInvertedRow = 3,
    WeightedElevatedFeetInvertedRow = 4,
    FacePull = 5,
    FacePullWithExternalRotation = 6,
    InvertedRowWithFeetOnSwissBall = 7,
    WeightedInvertedRowWithFeetOnSwissBall = 8,
    KettlebellRow = 9,
    ModifiedInvertedRow = 10,
    WeightedModifiedInvertedRow = 11,
    NeutralGripAlternatingDumbbellRow = 12,
    OneArmBentOverRow = 13,
    OneLeggedDumbbellRow = 14,
    RenegadeRow = 15,
    ReverseGripBarbellRow = 16,
    RopeHandleCableRow = 17,
    SeatedCableRow = 18,
    SeatedDumbbellRow = 19,
    SingleArmCableRow = 20,
    SingleArmCableRowAndRotation = 21,
    SingleArmInvertedRow = 22,
    WeightedSingleArmInvertedRow = 23,
    SingleArmNeutralGripDumbbellRow = 24,
    SingleArmNeutralGripDumbbellRowAndRotation = 25,
    SuspendedInvertedRow = 26,
    WeightedSuspendedInvertedRow = 27,
    TBarRow = 28,
    TowelGripInvertedRow = 29,
    WeightedTowelGripInvertedRow = 30,
    UnderhandGripCableRow = 31,
    VGripCableRow = 32,
    WideGripSeatedCableRow = 33,
    AlternatingDumbbellRow = 34,
    InvertedRow = 35,
    Row = 36,
    WeightedRow = 37,
    IndoorRow = 38,
    BandedFacePulls = 39,
    ChestSupportedDumbbellRow = 40,
    DeclineRingRow = 41,
    ElevatedRingRow = 42,
    RdlBentOverRowWithBarbellDumbbell = 43,
    RingRow = 44,
    BarbellRow = 45,
    BentOverRowWithBarbell = 46,
    BentOverRowWithDumbell = 47,
    SeatedUnderhandGripCableRow = 48,
    TrxInvertedRow = 49,
    WeightedInvertedRow = 50,
    WeightedTrxInvertedRow = 51,
    DumbbellRowWheelchair = 52,
}

impl RowExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            RowExerciseName::BarbellStraightLegDeadliftToRow => {
                "barbell_straight_leg_deadlift_to_row"
            }
            RowExerciseName::CableRowStanding => "cable_row_standing",
            RowExerciseName::DumbbellRow => "dumbbell_row",
            RowExerciseName::ElevatedFeetInvertedRow => "elevated_feet_inverted_row",
            RowExerciseName::WeightedElevatedFeetInvertedRow => {
                "weighted_elevated_feet_inverted_row"
            }
            RowExerciseName::FacePull => "face_pull",
            RowExerciseName::FacePullWithExternalRotation => "face_pull_with_external_rotation",
            RowExerciseName::InvertedRowWithFeetOnSwissBall => {
                "inverted_row_with_feet_on_swiss_ball"
            }
            RowExerciseName::WeightedInvertedRowWithFeetOnSwissBall => {
                "weighted_inverted_row_with_feet_on_swiss_ball"
            }
            RowExerciseName::KettlebellRow => "kettlebell_row",
            RowExerciseName::ModifiedInvertedRow => "modified_inverted_row",
            RowExerciseName::WeightedModifiedInvertedRow => "weighted_modified_inverted_row",
            RowExerciseName::NeutralGripAlternatingDumbbellRow => {
                "neutral_grip_alternating_dumbbell_row"
            }
            RowExerciseName::OneArmBentOverRow => "one_arm_bent_over_row",
            RowExerciseName::OneLeggedDumbbellRow => "one_legged_dumbbell_row",
            RowExerciseName::RenegadeRow => "renegade_row",
            RowExerciseName::ReverseGripBarbellRow => "reverse_grip_barbell_row",
            RowExerciseName::RopeHandleCableRow => "rope_handle_cable_row",
            RowExerciseName::SeatedCableRow => "seated_cable_row",
            RowExerciseName::SeatedDumbbellRow => "seated_dumbbell_row",
            RowExerciseName::SingleArmCableRow => "single_arm_cable_row",
            RowExerciseName::SingleArmCableRowAndRotation => "single_arm_cable_row_and_rotation",
            RowExerciseName::SingleArmInvertedRow => "single_arm_inverted_row",
            RowExerciseName::WeightedSingleArmInvertedRow => "weighted_single_arm_inverted_row",
            RowExerciseName::SingleArmNeutralGripDumbbellRow => {
                "single_arm_neutral_grip_dumbbell_row"
            }
            RowExerciseName::SingleArmNeutralGripDumbbellRowAndRotation => {
                "single_arm_neutral_grip_dumbbell_row_and_rotation"
            }
            RowExerciseName::SuspendedInvertedRow => "suspended_inverted_row",
            RowExerciseName::WeightedSuspendedInvertedRow => "weighted_suspended_inverted_row",
            RowExerciseName::TBarRow => "t_bar_row",
            RowExerciseName::TowelGripInvertedRow => "towel_grip_inverted_row",
            RowExerciseName::WeightedTowelGripInvertedRow => "weighted_towel_grip_inverted_row",
            RowExerciseName::UnderhandGripCableRow => "underhand_grip_cable_row",
            RowExerciseName::VGripCableRow => "v_grip_cable_row",
            RowExerciseName::WideGripSeatedCableRow => "wide_grip_seated_cable_row",
            RowExerciseName::AlternatingDumbbellRow => "alternating_dumbbell_row",
            RowExerciseName::InvertedRow => "inverted_row",
            RowExerciseName::Row => "row",
            RowExerciseName::WeightedRow => "weighted_row",
            RowExerciseName::IndoorRow => "indoor_row",
            RowExerciseName::BandedFacePulls => "banded_face_pulls",
            RowExerciseName::ChestSupportedDumbbellRow => "chest_supported_dumbbell_row",
            RowExerciseName::DeclineRingRow => "decline_ring_row",
            RowExerciseName::ElevatedRingRow => "elevated_ring_row",
            RowExerciseName::RdlBentOverRowWithBarbellDumbbell => {
                "rdl_bent_over_row_with_barbell_dumbbell"
            }
            RowExerciseName::RingRow => "ring_row",
            RowExerciseName::BarbellRow => "barbell_row",
            RowExerciseName::BentOverRowWithBarbell => "bent_over_row_with_barbell",
            RowExerciseName::BentOverRowWithDumbell => "bent_over_row_with_dumbell",
            RowExerciseName::SeatedUnderhandGripCableRow => "seated_underhand_grip_cable_row",
            RowExerciseName::TrxInvertedRow => "trx_inverted_row",
            RowExerciseName::WeightedInvertedRow => "weighted_inverted_row",
            RowExerciseName::WeightedTrxInvertedRow => "weighted_trx_inverted_row",
            RowExerciseName::DumbbellRowWheelchair => "dumbbell_row_wheelchair",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(RowExerciseName::BarbellStraightLegDeadliftToRow),
            1 => Some(RowExerciseName::CableRowStanding),
            2 => Some(RowExerciseName::DumbbellRow),
            3 => Some(RowExerciseName::ElevatedFeetInvertedRow),
            4 => Some(RowExerciseName::WeightedElevatedFeetInvertedRow),
            5 => Some(RowExerciseName::FacePull),
            6 => Some(RowExerciseName::FacePullWithExternalRotation),
            7 => Some(RowExerciseName::InvertedRowWithFeetOnSwissBall),
            8 => Some(RowExerciseName::WeightedInvertedRowWithFeetOnSwissBall),
            9 => Some(RowExerciseName::KettlebellRow),
            10 => Some(RowExerciseName::ModifiedInvertedRow),
            11 => Some(RowExerciseName::WeightedModifiedInvertedRow),
            12 => Some(RowExerciseName::NeutralGripAlternatingDumbbellRow),
            13 => Some(RowExerciseName::OneArmBentOverRow),
            14 => Some(RowExerciseName::OneLeggedDumbbellRow),
            15 => Some(RowExerciseName::RenegadeRow),
            16 => Some(RowExerciseName::ReverseGripBarbellRow),
            17 => Some(RowExerciseName::RopeHandleCableRow),
            18 => Some(RowExerciseName::SeatedCableRow),
            19 => Some(RowExerciseName::SeatedDumbbellRow),
            20 => Some(RowExerciseName::SingleArmCableRow),
            21 => Some(RowExerciseName::SingleArmCableRowAndRotation),
            22 => Some(RowExerciseName::SingleArmInvertedRow),
            23 => Some(RowExerciseName::WeightedSingleArmInvertedRow),
            24 => Some(RowExerciseName::SingleArmNeutralGripDumbbellRow),
            25 => Some(RowExerciseName::SingleArmNeutralGripDumbbellRowAndRotation),
            26 => Some(RowExerciseName::SuspendedInvertedRow),
            27 => Some(RowExerciseName::WeightedSuspendedInvertedRow),
            28 => Some(RowExerciseName::TBarRow),
            29 => Some(RowExerciseName::TowelGripInvertedRow),
            30 => Some(RowExerciseName::WeightedTowelGripInvertedRow),
            31 => Some(RowExerciseName::UnderhandGripCableRow),
            32 => Some(RowExerciseName::VGripCableRow),
            33 => Some(RowExerciseName::WideGripSeatedCableRow),
            34 => Some(RowExerciseName::AlternatingDumbbellRow),
            35 => Some(RowExerciseName::InvertedRow),
            36 => Some(RowExerciseName::Row),
            37 => Some(RowExerciseName::WeightedRow),
            38 => Some(RowExerciseName::IndoorRow),
            39 => Some(RowExerciseName::BandedFacePulls),
            40 => Some(RowExerciseName::ChestSupportedDumbbellRow),
            41 => Some(RowExerciseName::DeclineRingRow),
            42 => Some(RowExerciseName::ElevatedRingRow),
            43 => Some(RowExerciseName::RdlBentOverRowWithBarbellDumbbell),
            44 => Some(RowExerciseName::RingRow),
            45 => Some(RowExerciseName::BarbellRow),
            46 => Some(RowExerciseName::BentOverRowWithBarbell),
            47 => Some(RowExerciseName::BentOverRowWithDumbell),
            48 => Some(RowExerciseName::SeatedUnderhandGripCableRow),
            49 => Some(RowExerciseName::TrxInvertedRow),
            50 => Some(RowExerciseName::WeightedInvertedRow),
            51 => Some(RowExerciseName::WeightedTrxInvertedRow),
            52 => Some(RowExerciseName::DumbbellRowWheelchair),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "barbell_straight_leg_deadlift_to_row" => {
                Some(RowExerciseName::BarbellStraightLegDeadliftToRow)
            }
            "cable_row_standing" => Some(RowExerciseName::CableRowStanding),
            "dumbbell_row" => Some(RowExerciseName::DumbbellRow),
            "elevated_feet_inverted_row" => Some(RowExerciseName::ElevatedFeetInvertedRow),
            "weighted_elevated_feet_inverted_row" => {
                Some(RowExerciseName::WeightedElevatedFeetInvertedRow)
            }
            "face_pull" => Some(RowExerciseName::FacePull),
            "face_pull_with_external_rotation" => {
                Some(RowExerciseName::FacePullWithExternalRotation)
            }
            "inverted_row_with_feet_on_swiss_ball" => {
                Some(RowExerciseName::InvertedRowWithFeetOnSwissBall)
            }
            "weighted_inverted_row_with_feet_on_swiss_ball" => {
                Some(RowExerciseName::WeightedInvertedRowWithFeetOnSwissBall)
            }
            "kettlebell_row" => Some(RowExerciseName::KettlebellRow),
            "modified_inverted_row" => Some(RowExerciseName::ModifiedInvertedRow),
            "weighted_modified_inverted_row" => Some(RowExerciseName::WeightedModifiedInvertedRow),
            "neutral_grip_alternating_dumbbell_row" => {
                Some(RowExerciseName::NeutralGripAlternatingDumbbellRow)
            }
            "one_arm_bent_over_row" => Some(RowExerciseName::OneArmBentOverRow),
            "one_legged_dumbbell_row" => Some(RowExerciseName::OneLeggedDumbbellRow),
            "renegade_row" => Some(RowExerciseName::RenegadeRow),
            "reverse_grip_barbell_row" => Some(RowExerciseName::ReverseGripBarbellRow),
            "rope_handle_cable_row" => Some(RowExerciseName::RopeHandleCableRow),
            "seated_cable_row" => Some(RowExerciseName::SeatedCableRow),
            "seated_dumbbell_row" => Some(RowExerciseName::SeatedDumbbellRow),
            "single_arm_cable_row" => Some(RowExerciseName::SingleArmCableRow),
            "single_arm_cable_row_and_rotation" => {
                Some(RowExerciseName::SingleArmCableRowAndRotation)
            }
            "single_arm_inverted_row" => Some(RowExerciseName::SingleArmInvertedRow),
            "weighted_single_arm_inverted_row" => {
                Some(RowExerciseName::WeightedSingleArmInvertedRow)
            }
            "single_arm_neutral_grip_dumbbell_row" => {
                Some(RowExerciseName::SingleArmNeutralGripDumbbellRow)
            }
            "single_arm_neutral_grip_dumbbell_row_and_rotation" => {
                Some(RowExerciseName::SingleArmNeutralGripDumbbellRowAndRotation)
            }
            "suspended_inverted_row" => Some(RowExerciseName::SuspendedInvertedRow),
            "weighted_suspended_inverted_row" => {
                Some(RowExerciseName::WeightedSuspendedInvertedRow)
            }
            "t_bar_row" => Some(RowExerciseName::TBarRow),
            "towel_grip_inverted_row" => Some(RowExerciseName::TowelGripInvertedRow),
            "weighted_towel_grip_inverted_row" => {
                Some(RowExerciseName::WeightedTowelGripInvertedRow)
            }
            "underhand_grip_cable_row" => Some(RowExerciseName::UnderhandGripCableRow),
            "v_grip_cable_row" => Some(RowExerciseName::VGripCableRow),
            "wide_grip_seated_cable_row" => Some(RowExerciseName::WideGripSeatedCableRow),
            "alternating_dumbbell_row" => Some(RowExerciseName::AlternatingDumbbellRow),
            "inverted_row" => Some(RowExerciseName::InvertedRow),
            "row" => Some(RowExerciseName::Row),
            "weighted_row" => Some(RowExerciseName::WeightedRow),
            "indoor_row" => Some(RowExerciseName::IndoorRow),
            "banded_face_pulls" => Some(RowExerciseName::BandedFacePulls),
            "chest_supported_dumbbell_row" => Some(RowExerciseName::ChestSupportedDumbbellRow),
            "decline_ring_row" => Some(RowExerciseName::DeclineRingRow),
            "elevated_ring_row" => Some(RowExerciseName::ElevatedRingRow),
            "rdl_bent_over_row_with_barbell_dumbbell" => {
                Some(RowExerciseName::RdlBentOverRowWithBarbellDumbbell)
            }
            "ring_row" => Some(RowExerciseName::RingRow),
            "barbell_row" => Some(RowExerciseName::BarbellRow),
            "bent_over_row_with_barbell" => Some(RowExerciseName::BentOverRowWithBarbell),
            "bent_over_row_with_dumbell" => Some(RowExerciseName::BentOverRowWithDumbell),
            "seated_underhand_grip_cable_row" => Some(RowExerciseName::SeatedUnderhandGripCableRow),
            "trx_inverted_row" => Some(RowExerciseName::TrxInvertedRow),
            "weighted_inverted_row" => Some(RowExerciseName::WeightedInvertedRow),
            "weighted_trx_inverted_row" => Some(RowExerciseName::WeightedTrxInvertedRow),
            "dumbbell_row_wheelchair" => Some(RowExerciseName::DumbbellRowWheelchair),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum ShoulderPressExerciseName {
    AlternatingDumbbellShoulderPress = 0,
    ArnoldPress = 1,
    BarbellFrontSquatToPushPress = 2,
    BarbellPushPress = 3,
    BarbellShoulderPress = 4,
    DeadCurlPress = 5,
    DumbbellAlternatingShoulderPressAndTwist = 6,
    DumbbellHammerCurlToLungeToPress = 7,
    DumbbellPushPress = 8,
    FloorInvertedShoulderPress = 9,
    WeightedFloorInvertedShoulderPress = 10,
    InvertedShoulderPress = 11,
    WeightedInvertedShoulderPress = 12,
    OneArmPushPress = 13,
    OverheadBarbellPress = 14,
    OverheadDumbbellPress = 15,
    SeatedBarbellShoulderPress = 16,
    SeatedDumbbellShoulderPress = 17,
    SingleArmDumbbellShoulderPress = 18,
    SingleArmStepUpAndPress = 19,
    SmithMachineOverheadPress = 20,
    SplitStanceHammerCurlToPress = 21,
    SwissBallDumbbellShoulderPress = 22,
    WeightPlateFrontRaise = 23,
    DumbbellShoulderPress = 24,
    MilitaryPress = 25,
    StrictPress = 27,
    DumbbellFrontRaise = 28,
    DumbbellCurlToOverheadPressWheelchair = 29,
    ArnoldPressWheelchair = 30,
    OverheadDumbbellPressWheelchair = 31,
}

impl ShoulderPressExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            ShoulderPressExerciseName::AlternatingDumbbellShoulderPress => {
                "alternating_dumbbell_shoulder_press"
            }
            ShoulderPressExerciseName::ArnoldPress => "arnold_press",
            ShoulderPressExerciseName::BarbellFrontSquatToPushPress => {
                "barbell_front_squat_to_push_press"
            }
            ShoulderPressExerciseName::BarbellPushPress => "barbell_push_press",
            ShoulderPressExerciseName::BarbellShoulderPress => "barbell_shoulder_press",
            ShoulderPressExerciseName::DeadCurlPress => "dead_curl_press",
            ShoulderPressExerciseName::DumbbellAlternatingShoulderPressAndTwist => {
                "dumbbell_alternating_shoulder_press_and_twist"
            }
            ShoulderPressExerciseName::DumbbellHammerCurlToLungeToPress => {
                "dumbbell_hammer_curl_to_lunge_to_press"
            }
            ShoulderPressExerciseName::DumbbellPushPress => "dumbbell_push_press",
            ShoulderPressExerciseName::FloorInvertedShoulderPress => {
                "floor_inverted_shoulder_press"
            }
            ShoulderPressExerciseName::WeightedFloorInvertedShoulderPress => {
                "weighted_floor_inverted_shoulder_press"
            }
            ShoulderPressExerciseName::InvertedShoulderPress => "inverted_shoulder_press",
            ShoulderPressExerciseName::WeightedInvertedShoulderPress => {
                "weighted_inverted_shoulder_press"
            }
            ShoulderPressExerciseName::OneArmPushPress => "one_arm_push_press",
            ShoulderPressExerciseName::OverheadBarbellPress => "overhead_barbell_press",
            ShoulderPressExerciseName::OverheadDumbbellPress => "overhead_dumbbell_press",
            ShoulderPressExerciseName::SeatedBarbellShoulderPress => {
                "seated_barbell_shoulder_press"
            }
            ShoulderPressExerciseName::SeatedDumbbellShoulderPress => {
                "seated_dumbbell_shoulder_press"
            }
            ShoulderPressExerciseName::SingleArmDumbbellShoulderPress => {
                "single_arm_dumbbell_shoulder_press"
            }
            ShoulderPressExerciseName::SingleArmStepUpAndPress => "single_arm_step_up_and_press",
            ShoulderPressExerciseName::SmithMachineOverheadPress => "smith_machine_overhead_press",
            ShoulderPressExerciseName::SplitStanceHammerCurlToPress => {
                "split_stance_hammer_curl_to_press"
            }
            ShoulderPressExerciseName::SwissBallDumbbellShoulderPress => {
                "swiss_ball_dumbbell_shoulder_press"
            }
            ShoulderPressExerciseName::WeightPlateFrontRaise => "weight_plate_front_raise",
            ShoulderPressExerciseName::DumbbellShoulderPress => "dumbbell_shoulder_press",
            ShoulderPressExerciseName::MilitaryPress => "military_press",
            ShoulderPressExerciseName::StrictPress => "strict_press",
            ShoulderPressExerciseName::DumbbellFrontRaise => "dumbbell_front_raise",
            ShoulderPressExerciseName::DumbbellCurlToOverheadPressWheelchair => {
                "dumbbell_curl_to_overhead_press_wheelchair"
            }
            ShoulderPressExerciseName::ArnoldPressWheelchair => "arnold_press_wheelchair",
            ShoulderPressExerciseName::OverheadDumbbellPressWheelchair => {
                "overhead_dumbbell_press_wheelchair"
            }
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(ShoulderPressExerciseName::AlternatingDumbbellShoulderPress),
            1 => Some(ShoulderPressExerciseName::ArnoldPress),
            2 => Some(ShoulderPressExerciseName::BarbellFrontSquatToPushPress),
            3 => Some(ShoulderPressExerciseName::BarbellPushPress),
            4 => Some(ShoulderPressExerciseName::BarbellShoulderPress),
            5 => Some(ShoulderPressExerciseName::DeadCurlPress),
            6 => Some(ShoulderPressExerciseName::DumbbellAlternatingShoulderPressAndTwist),
            7 => Some(ShoulderPressExerciseName::DumbbellHammerCurlToLungeToPress),
            8 => Some(ShoulderPressExerciseName::DumbbellPushPress),
            9 => Some(ShoulderPressExerciseName::FloorInvertedShoulderPress),
            10 => Some(ShoulderPressExerciseName::WeightedFloorInvertedShoulderPress),
            11 => Some(ShoulderPressExerciseName::InvertedShoulderPress),
            12 => Some(ShoulderPressExerciseName::WeightedInvertedShoulderPress),
            13 => Some(ShoulderPressExerciseName::OneArmPushPress),
            14 => Some(ShoulderPressExerciseName::OverheadBarbellPress),
            15 => Some(ShoulderPressExerciseName::OverheadDumbbellPress),
            16 => Some(ShoulderPressExerciseName::SeatedBarbellShoulderPress),
            17 => Some(ShoulderPressExerciseName::SeatedDumbbellShoulderPress),
            18 => Some(ShoulderPressExerciseName::SingleArmDumbbellShoulderPress),
            19 => Some(ShoulderPressExerciseName::SingleArmStepUpAndPress),
            20 => Some(ShoulderPressExerciseName::SmithMachineOverheadPress),
            21 => Some(ShoulderPressExerciseName::SplitStanceHammerCurlToPress),
            22 => Some(ShoulderPressExerciseName::SwissBallDumbbellShoulderPress),
            23 => Some(ShoulderPressExerciseName::WeightPlateFrontRaise),
            24 => Some(ShoulderPressExerciseName::DumbbellShoulderPress),
            25 => Some(ShoulderPressExerciseName::MilitaryPress),
            27 => Some(ShoulderPressExerciseName::StrictPress),
            28 => Some(ShoulderPressExerciseName::DumbbellFrontRaise),
            29 => Some(ShoulderPressExerciseName::DumbbellCurlToOverheadPressWheelchair),
            30 => Some(ShoulderPressExerciseName::ArnoldPressWheelchair),
            31 => Some(ShoulderPressExerciseName::OverheadDumbbellPressWheelchair),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "alternating_dumbbell_shoulder_press" => {
                Some(ShoulderPressExerciseName::AlternatingDumbbellShoulderPress)
            }
            "arnold_press" => Some(ShoulderPressExerciseName::ArnoldPress),
            "barbell_front_squat_to_push_press" => {
                Some(ShoulderPressExerciseName::BarbellFrontSquatToPushPress)
            }
            "barbell_push_press" => Some(ShoulderPressExerciseName::BarbellPushPress),
            "barbell_shoulder_press" => Some(ShoulderPressExerciseName::BarbellShoulderPress),
            "dead_curl_press" => Some(ShoulderPressExerciseName::DeadCurlPress),
            "dumbbell_alternating_shoulder_press_and_twist" => {
                Some(ShoulderPressExerciseName::DumbbellAlternatingShoulderPressAndTwist)
            }
            "dumbbell_hammer_curl_to_lunge_to_press" => {
                Some(ShoulderPressExerciseName::DumbbellHammerCurlToLungeToPress)
            }
            "dumbbell_push_press" => Some(ShoulderPressExerciseName::DumbbellPushPress),
            "floor_inverted_shoulder_press" => {
                Some(ShoulderPressExerciseName::FloorInvertedShoulderPress)
            }
            "weighted_floor_inverted_shoulder_press" => {
                Some(ShoulderPressExerciseName::WeightedFloorInvertedShoulderPress)
            }
            "inverted_shoulder_press" => Some(ShoulderPressExerciseName::InvertedShoulderPress),
            "weighted_inverted_shoulder_press" => {
                Some(ShoulderPressExerciseName::WeightedInvertedShoulderPress)
            }
            "one_arm_push_press" => Some(ShoulderPressExerciseName::OneArmPushPress),
            "overhead_barbell_press" => Some(ShoulderPressExerciseName::OverheadBarbellPress),
            "overhead_dumbbell_press" => Some(ShoulderPressExerciseName::OverheadDumbbellPress),
            "seated_barbell_shoulder_press" => {
                Some(ShoulderPressExerciseName::SeatedBarbellShoulderPress)
            }
            "seated_dumbbell_shoulder_press" => {
                Some(ShoulderPressExerciseName::SeatedDumbbellShoulderPress)
            }
            "single_arm_dumbbell_shoulder_press" => {
                Some(ShoulderPressExerciseName::SingleArmDumbbellShoulderPress)
            }
            "single_arm_step_up_and_press" => {
                Some(ShoulderPressExerciseName::SingleArmStepUpAndPress)
            }
            "smith_machine_overhead_press" => {
                Some(ShoulderPressExerciseName::SmithMachineOverheadPress)
            }
            "split_stance_hammer_curl_to_press" => {
                Some(ShoulderPressExerciseName::SplitStanceHammerCurlToPress)
            }
            "swiss_ball_dumbbell_shoulder_press" => {
                Some(ShoulderPressExerciseName::SwissBallDumbbellShoulderPress)
            }
            "weight_plate_front_raise" => Some(ShoulderPressExerciseName::WeightPlateFrontRaise),
            "dumbbell_shoulder_press" => Some(ShoulderPressExerciseName::DumbbellShoulderPress),
            "military_press" => Some(ShoulderPressExerciseName::MilitaryPress),
            "strict_press" => Some(ShoulderPressExerciseName::StrictPress),
            "dumbbell_front_raise" => Some(ShoulderPressExerciseName::DumbbellFrontRaise),
            "dumbbell_curl_to_overhead_press_wheelchair" => {
                Some(ShoulderPressExerciseName::DumbbellCurlToOverheadPressWheelchair)
            }
            "arnold_press_wheelchair" => Some(ShoulderPressExerciseName::ArnoldPressWheelchair),
            "overhead_dumbbell_press_wheelchair" => {
                Some(ShoulderPressExerciseName::OverheadDumbbellPressWheelchair)
            }
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum ShoulderStabilityExerciseName {
    _90DegreeCableExternalRotation = 0,
    BandExternalRotation = 1,
    BandInternalRotation = 2,
    BentArmLateralRaiseAndExternalRotation = 3,
    CableExternalRotation = 4,
    DumbbellFacePullWithExternalRotation = 5,
    FloorIRaise = 6,
    WeightedFloorIRaise = 7,
    FloorTRaise = 8,
    WeightedFloorTRaise = 9,
    FloorYRaise = 10,
    WeightedFloorYRaise = 11,
    InclineIRaise = 12,
    WeightedInclineIRaise = 13,
    InclineLRaise = 14,
    WeightedInclineLRaise = 15,
    InclineTRaise = 16,
    WeightedInclineTRaise = 17,
    InclineWRaise = 18,
    WeightedInclineWRaise = 19,
    InclineYRaise = 20,
    WeightedInclineYRaise = 21,
    LyingExternalRotation = 22,
    SeatedDumbbellExternalRotation = 23,
    StandingLRaise = 24,
    SwissBallIRaise = 25,
    WeightedSwissBallIRaise = 26,
    SwissBallTRaise = 27,
    WeightedSwissBallTRaise = 28,
    SwissBallWRaise = 29,
    WeightedSwissBallWRaise = 30,
    SwissBallYRaise = 31,
    WeightedSwissBallYRaise = 32,
    CableInternalRotation = 33,
    LyingInternalRotation = 34,
    SeatedDumbbellInternalRotation = 35,
}

impl ShoulderStabilityExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            ShoulderStabilityExerciseName::_90DegreeCableExternalRotation => {
                "90_degree_cable_external_rotation"
            }
            ShoulderStabilityExerciseName::BandExternalRotation => "band_external_rotation",
            ShoulderStabilityExerciseName::BandInternalRotation => "band_internal_rotation",
            ShoulderStabilityExerciseName::BentArmLateralRaiseAndExternalRotation => {
                "bent_arm_lateral_raise_and_external_rotation"
            }
            ShoulderStabilityExerciseName::CableExternalRotation => "cable_external_rotation",
            ShoulderStabilityExerciseName::DumbbellFacePullWithExternalRotation => {
                "dumbbell_face_pull_with_external_rotation"
            }
            ShoulderStabilityExerciseName::FloorIRaise => "floor_i_raise",
            ShoulderStabilityExerciseName::WeightedFloorIRaise => "weighted_floor_i_raise",
            ShoulderStabilityExerciseName::FloorTRaise => "floor_t_raise",
            ShoulderStabilityExerciseName::WeightedFloorTRaise => "weighted_floor_t_raise",
            ShoulderStabilityExerciseName::FloorYRaise => "floor_y_raise",
            ShoulderStabilityExerciseName::WeightedFloorYRaise => "weighted_floor_y_raise",
            ShoulderStabilityExerciseName::InclineIRaise => "incline_i_raise",
            ShoulderStabilityExerciseName::WeightedInclineIRaise => "weighted_incline_i_raise",
            ShoulderStabilityExerciseName::InclineLRaise => "incline_l_raise",
            ShoulderStabilityExerciseName::WeightedInclineLRaise => "weighted_incline_l_raise",
            ShoulderStabilityExerciseName::InclineTRaise => "incline_t_raise",
            ShoulderStabilityExerciseName::WeightedInclineTRaise => "weighted_incline_t_raise",
            ShoulderStabilityExerciseName::InclineWRaise => "incline_w_raise",
            ShoulderStabilityExerciseName::WeightedInclineWRaise => "weighted_incline_w_raise",
            ShoulderStabilityExerciseName::InclineYRaise => "incline_y_raise",
            ShoulderStabilityExerciseName::WeightedInclineYRaise => "weighted_incline_y_raise",
            ShoulderStabilityExerciseName::LyingExternalRotation => "lying_external_rotation",
            ShoulderStabilityExerciseName::SeatedDumbbellExternalRotation => {
                "seated_dumbbell_external_rotation"
            }
            ShoulderStabilityExerciseName::StandingLRaise => "standing_l_raise",
            ShoulderStabilityExerciseName::SwissBallIRaise => "swiss_ball_i_raise",
            ShoulderStabilityExerciseName::WeightedSwissBallIRaise => "weighted_swiss_ball_i_raise",
            ShoulderStabilityExerciseName::SwissBallTRaise => "swiss_ball_t_raise",
            ShoulderStabilityExerciseName::WeightedSwissBallTRaise => "weighted_swiss_ball_t_raise",
            ShoulderStabilityExerciseName::SwissBallWRaise => "swiss_ball_w_raise",
            ShoulderStabilityExerciseName::WeightedSwissBallWRaise => "weighted_swiss_ball_w_raise",
            ShoulderStabilityExerciseName::SwissBallYRaise => "swiss_ball_y_raise",
            ShoulderStabilityExerciseName::WeightedSwissBallYRaise => "weighted_swiss_ball_y_raise",
            ShoulderStabilityExerciseName::CableInternalRotation => "cable_internal_rotation",
            ShoulderStabilityExerciseName::LyingInternalRotation => "lying_internal_rotation",
            ShoulderStabilityExerciseName::SeatedDumbbellInternalRotation => {
                "seated_dumbbell_internal_rotation"
            }
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(ShoulderStabilityExerciseName::_90DegreeCableExternalRotation),
            1 => Some(ShoulderStabilityExerciseName::BandExternalRotation),
            2 => Some(ShoulderStabilityExerciseName::BandInternalRotation),
            3 => Some(ShoulderStabilityExerciseName::BentArmLateralRaiseAndExternalRotation),
            4 => Some(ShoulderStabilityExerciseName::CableExternalRotation),
            5 => Some(ShoulderStabilityExerciseName::DumbbellFacePullWithExternalRotation),
            6 => Some(ShoulderStabilityExerciseName::FloorIRaise),
            7 => Some(ShoulderStabilityExerciseName::WeightedFloorIRaise),
            8 => Some(ShoulderStabilityExerciseName::FloorTRaise),
            9 => Some(ShoulderStabilityExerciseName::WeightedFloorTRaise),
            10 => Some(ShoulderStabilityExerciseName::FloorYRaise),
            11 => Some(ShoulderStabilityExerciseName::WeightedFloorYRaise),
            12 => Some(ShoulderStabilityExerciseName::InclineIRaise),
            13 => Some(ShoulderStabilityExerciseName::WeightedInclineIRaise),
            14 => Some(ShoulderStabilityExerciseName::InclineLRaise),
            15 => Some(ShoulderStabilityExerciseName::WeightedInclineLRaise),
            16 => Some(ShoulderStabilityExerciseName::InclineTRaise),
            17 => Some(ShoulderStabilityExerciseName::WeightedInclineTRaise),
            18 => Some(ShoulderStabilityExerciseName::InclineWRaise),
            19 => Some(ShoulderStabilityExerciseName::WeightedInclineWRaise),
            20 => Some(ShoulderStabilityExerciseName::InclineYRaise),
            21 => Some(ShoulderStabilityExerciseName::WeightedInclineYRaise),
            22 => Some(ShoulderStabilityExerciseName::LyingExternalRotation),
            23 => Some(ShoulderStabilityExerciseName::SeatedDumbbellExternalRotation),
            24 => Some(ShoulderStabilityExerciseName::StandingLRaise),
            25 => Some(ShoulderStabilityExerciseName::SwissBallIRaise),
            26 => Some(ShoulderStabilityExerciseName::WeightedSwissBallIRaise),
            27 => Some(ShoulderStabilityExerciseName::SwissBallTRaise),
            28 => Some(ShoulderStabilityExerciseName::WeightedSwissBallTRaise),
            29 => Some(ShoulderStabilityExerciseName::SwissBallWRaise),
            30 => Some(ShoulderStabilityExerciseName::WeightedSwissBallWRaise),
            31 => Some(ShoulderStabilityExerciseName::SwissBallYRaise),
            32 => Some(ShoulderStabilityExerciseName::WeightedSwissBallYRaise),
            33 => Some(ShoulderStabilityExerciseName::CableInternalRotation),
            34 => Some(ShoulderStabilityExerciseName::LyingInternalRotation),
            35 => Some(ShoulderStabilityExerciseName::SeatedDumbbellInternalRotation),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "90_degree_cable_external_rotation" => {
                Some(ShoulderStabilityExerciseName::_90DegreeCableExternalRotation)
            }
            "band_external_rotation" => Some(ShoulderStabilityExerciseName::BandExternalRotation),
            "band_internal_rotation" => Some(ShoulderStabilityExerciseName::BandInternalRotation),
            "bent_arm_lateral_raise_and_external_rotation" => {
                Some(ShoulderStabilityExerciseName::BentArmLateralRaiseAndExternalRotation)
            }
            "cable_external_rotation" => Some(ShoulderStabilityExerciseName::CableExternalRotation),
            "dumbbell_face_pull_with_external_rotation" => {
                Some(ShoulderStabilityExerciseName::DumbbellFacePullWithExternalRotation)
            }
            "floor_i_raise" => Some(ShoulderStabilityExerciseName::FloorIRaise),
            "weighted_floor_i_raise" => Some(ShoulderStabilityExerciseName::WeightedFloorIRaise),
            "floor_t_raise" => Some(ShoulderStabilityExerciseName::FloorTRaise),
            "weighted_floor_t_raise" => Some(ShoulderStabilityExerciseName::WeightedFloorTRaise),
            "floor_y_raise" => Some(ShoulderStabilityExerciseName::FloorYRaise),
            "weighted_floor_y_raise" => Some(ShoulderStabilityExerciseName::WeightedFloorYRaise),
            "incline_i_raise" => Some(ShoulderStabilityExerciseName::InclineIRaise),
            "weighted_incline_i_raise" => {
                Some(ShoulderStabilityExerciseName::WeightedInclineIRaise)
            }
            "incline_l_raise" => Some(ShoulderStabilityExerciseName::InclineLRaise),
            "weighted_incline_l_raise" => {
                Some(ShoulderStabilityExerciseName::WeightedInclineLRaise)
            }
            "incline_t_raise" => Some(ShoulderStabilityExerciseName::InclineTRaise),
            "weighted_incline_t_raise" => {
                Some(ShoulderStabilityExerciseName::WeightedInclineTRaise)
            }
            "incline_w_raise" => Some(ShoulderStabilityExerciseName::InclineWRaise),
            "weighted_incline_w_raise" => {
                Some(ShoulderStabilityExerciseName::WeightedInclineWRaise)
            }
            "incline_y_raise" => Some(ShoulderStabilityExerciseName::InclineYRaise),
            "weighted_incline_y_raise" => {
                Some(ShoulderStabilityExerciseName::WeightedInclineYRaise)
            }
            "lying_external_rotation" => Some(ShoulderStabilityExerciseName::LyingExternalRotation),
            "seated_dumbbell_external_rotation" => {
                Some(ShoulderStabilityExerciseName::SeatedDumbbellExternalRotation)
            }
            "standing_l_raise" => Some(ShoulderStabilityExerciseName::StandingLRaise),
            "swiss_ball_i_raise" => Some(ShoulderStabilityExerciseName::SwissBallIRaise),
            "weighted_swiss_ball_i_raise" => {
                Some(ShoulderStabilityExerciseName::WeightedSwissBallIRaise)
            }
            "swiss_ball_t_raise" => Some(ShoulderStabilityExerciseName::SwissBallTRaise),
            "weighted_swiss_ball_t_raise" => {
                Some(ShoulderStabilityExerciseName::WeightedSwissBallTRaise)
            }
            "swiss_ball_w_raise" => Some(ShoulderStabilityExerciseName::SwissBallWRaise),
            "weighted_swiss_ball_w_raise" => {
                Some(ShoulderStabilityExerciseName::WeightedSwissBallWRaise)
            }
            "swiss_ball_y_raise" => Some(ShoulderStabilityExerciseName::SwissBallYRaise),
            "weighted_swiss_ball_y_raise" => {
                Some(ShoulderStabilityExerciseName::WeightedSwissBallYRaise)
            }
            "cable_internal_rotation" => Some(ShoulderStabilityExerciseName::CableInternalRotation),
            "lying_internal_rotation" => Some(ShoulderStabilityExerciseName::LyingInternalRotation),
            "seated_dumbbell_internal_rotation" => {
                Some(ShoulderStabilityExerciseName::SeatedDumbbellInternalRotation)
            }
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum ShrugExerciseName {
    BarbellJumpShrug = 0,
    BarbellShrug = 1,
    BarbellUprightRow = 2,
    BehindTheBackSmithMachineShrug = 3,
    DumbbellJumpShrug = 4,
    DumbbellShrug = 5,
    DumbbellUprightRow = 6,
    InclineDumbbellShrug = 7,
    OverheadBarbellShrug = 8,
    OverheadDumbbellShrug = 9,
    ScaptionAndShrug = 10,
    ScapularRetraction = 11,
    SerratusChairShrug = 12,
    WeightedSerratusChairShrug = 13,
    SerratusShrug = 14,
    WeightedSerratusShrug = 15,
    WideGripJumpShrug = 16,
    WideGripBarbellShrug = 17,
    BehindTheBackShrug = 18,
    DumbbellShrugWheelchair = 19,
    ShrugWheelchair = 20,
    ShrugArmDownWheelchair = 21,
    ShrugArmMidWheelchair = 22,
    ShrugArmUpWheelchair = 23,
    UprightRow = 24,
}

impl ShrugExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            ShrugExerciseName::BarbellJumpShrug => "barbell_jump_shrug",
            ShrugExerciseName::BarbellShrug => "barbell_shrug",
            ShrugExerciseName::BarbellUprightRow => "barbell_upright_row",
            ShrugExerciseName::BehindTheBackSmithMachineShrug => {
                "behind_the_back_smith_machine_shrug"
            }
            ShrugExerciseName::DumbbellJumpShrug => "dumbbell_jump_shrug",
            ShrugExerciseName::DumbbellShrug => "dumbbell_shrug",
            ShrugExerciseName::DumbbellUprightRow => "dumbbell_upright_row",
            ShrugExerciseName::InclineDumbbellShrug => "incline_dumbbell_shrug",
            ShrugExerciseName::OverheadBarbellShrug => "overhead_barbell_shrug",
            ShrugExerciseName::OverheadDumbbellShrug => "overhead_dumbbell_shrug",
            ShrugExerciseName::ScaptionAndShrug => "scaption_and_shrug",
            ShrugExerciseName::ScapularRetraction => "scapular_retraction",
            ShrugExerciseName::SerratusChairShrug => "serratus_chair_shrug",
            ShrugExerciseName::WeightedSerratusChairShrug => "weighted_serratus_chair_shrug",
            ShrugExerciseName::SerratusShrug => "serratus_shrug",
            ShrugExerciseName::WeightedSerratusShrug => "weighted_serratus_shrug",
            ShrugExerciseName::WideGripJumpShrug => "wide_grip_jump_shrug",
            ShrugExerciseName::WideGripBarbellShrug => "wide_grip_barbell_shrug",
            ShrugExerciseName::BehindTheBackShrug => "behind_the_back_shrug",
            ShrugExerciseName::DumbbellShrugWheelchair => "dumbbell_shrug_wheelchair",
            ShrugExerciseName::ShrugWheelchair => "shrug_wheelchair",
            ShrugExerciseName::ShrugArmDownWheelchair => "shrug_arm_down_wheelchair",
            ShrugExerciseName::ShrugArmMidWheelchair => "shrug_arm_mid_wheelchair",
            ShrugExerciseName::ShrugArmUpWheelchair => "shrug_arm_up_wheelchair",
            ShrugExerciseName::UprightRow => "upright_row",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(ShrugExerciseName::BarbellJumpShrug),
            1 => Some(ShrugExerciseName::BarbellShrug),
            2 => Some(ShrugExerciseName::BarbellUprightRow),
            3 => Some(ShrugExerciseName::BehindTheBackSmithMachineShrug),
            4 => Some(ShrugExerciseName::DumbbellJumpShrug),
            5 => Some(ShrugExerciseName::DumbbellShrug),
            6 => Some(ShrugExerciseName::DumbbellUprightRow),
            7 => Some(ShrugExerciseName::InclineDumbbellShrug),
            8 => Some(ShrugExerciseName::OverheadBarbellShrug),
            9 => Some(ShrugExerciseName::OverheadDumbbellShrug),
            10 => Some(ShrugExerciseName::ScaptionAndShrug),
            11 => Some(ShrugExerciseName::ScapularRetraction),
            12 => Some(ShrugExerciseName::SerratusChairShrug),
            13 => Some(ShrugExerciseName::WeightedSerratusChairShrug),
            14 => Some(ShrugExerciseName::SerratusShrug),
            15 => Some(ShrugExerciseName::WeightedSerratusShrug),
            16 => Some(ShrugExerciseName::WideGripJumpShrug),
            17 => Some(ShrugExerciseName::WideGripBarbellShrug),
            18 => Some(ShrugExerciseName::BehindTheBackShrug),
            19 => Some(ShrugExerciseName::DumbbellShrugWheelchair),
            20 => Some(ShrugExerciseName::ShrugWheelchair),
            21 => Some(ShrugExerciseName::ShrugArmDownWheelchair),
            22 => Some(ShrugExerciseName::ShrugArmMidWheelchair),
            23 => Some(ShrugExerciseName::ShrugArmUpWheelchair),
            24 => Some(ShrugExerciseName::UprightRow),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "barbell_jump_shrug" => Some(ShrugExerciseName::BarbellJumpShrug),
            "barbell_shrug" => Some(ShrugExerciseName::BarbellShrug),
            "barbell_upright_row" => Some(ShrugExerciseName::BarbellUprightRow),
            "behind_the_back_smith_machine_shrug" => {
                Some(ShrugExerciseName::BehindTheBackSmithMachineShrug)
            }
            "dumbbell_jump_shrug" => Some(ShrugExerciseName::DumbbellJumpShrug),
            "dumbbell_shrug" => Some(ShrugExerciseName::DumbbellShrug),
            "dumbbell_upright_row" => Some(ShrugExerciseName::DumbbellUprightRow),
            "incline_dumbbell_shrug" => Some(ShrugExerciseName::InclineDumbbellShrug),
            "overhead_barbell_shrug" => Some(ShrugExerciseName::OverheadBarbellShrug),
            "overhead_dumbbell_shrug" => Some(ShrugExerciseName::OverheadDumbbellShrug),
            "scaption_and_shrug" => Some(ShrugExerciseName::ScaptionAndShrug),
            "scapular_retraction" => Some(ShrugExerciseName::ScapularRetraction),
            "serratus_chair_shrug" => Some(ShrugExerciseName::SerratusChairShrug),
            "weighted_serratus_chair_shrug" => Some(ShrugExerciseName::WeightedSerratusChairShrug),
            "serratus_shrug" => Some(ShrugExerciseName::SerratusShrug),
            "weighted_serratus_shrug" => Some(ShrugExerciseName::WeightedSerratusShrug),
            "wide_grip_jump_shrug" => Some(ShrugExerciseName::WideGripJumpShrug),
            "wide_grip_barbell_shrug" => Some(ShrugExerciseName::WideGripBarbellShrug),
            "behind_the_back_shrug" => Some(ShrugExerciseName::BehindTheBackShrug),
            "dumbbell_shrug_wheelchair" => Some(ShrugExerciseName::DumbbellShrugWheelchair),
            "shrug_wheelchair" => Some(ShrugExerciseName::ShrugWheelchair),
            "shrug_arm_down_wheelchair" => Some(ShrugExerciseName::ShrugArmDownWheelchair),
            "shrug_arm_mid_wheelchair" => Some(ShrugExerciseName::ShrugArmMidWheelchair),
            "shrug_arm_up_wheelchair" => Some(ShrugExerciseName::ShrugArmUpWheelchair),
            "upright_row" => Some(ShrugExerciseName::UprightRow),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum SitUpExerciseName {
    AlternatingSitUp = 0,
    WeightedAlternatingSitUp = 1,
    BentKneeVUp = 2,
    WeightedBentKneeVUp = 3,
    ButterflySitUp = 4,
    WeightedButterflySitup = 5,
    CrossPunchRollUp = 6,
    WeightedCrossPunchRollUp = 7,
    CrossedArmsSitUp = 8,
    WeightedCrossedArmsSitUp = 9,
    GetUpSitUp = 10,
    WeightedGetUpSitUp = 11,
    HoveringSitUp = 12,
    WeightedHoveringSitUp = 13,
    KettlebellSitUp = 14,
    MedicineBallAlternatingVUp = 15,
    MedicineBallSitUp = 16,
    MedicineBallVUp = 17,
    ModifiedSitUp = 18,
    NegativeSitUp = 19,
    OneArmFullSitUp = 20,
    RecliningCircle = 21,
    WeightedRecliningCircle = 22,
    ReverseCurlUp = 23,
    WeightedReverseCurlUp = 24,
    SingleLegSwissBallJackknife = 25,
    WeightedSingleLegSwissBallJackknife = 26,
    TheTeaser = 27,
    TheTeaserWeighted = 28,
    ThreePartRollDown = 29,
    WeightedThreePartRollDown = 30,
    VUp = 31,
    WeightedVUp = 32,
    WeightedRussianTwistOnSwissBall = 33,
    WeightedSitUp = 34,
    XAbs = 35,
    WeightedXAbs = 36,
    SitUp = 37,
    GhdSitUps = 38,
    SitUpTurkishGetUp = 39,
    RussianTwistOnSwissBall = 40,
}

impl SitUpExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            SitUpExerciseName::AlternatingSitUp => "alternating_sit_up",
            SitUpExerciseName::WeightedAlternatingSitUp => "weighted_alternating_sit_up",
            SitUpExerciseName::BentKneeVUp => "bent_knee_v_up",
            SitUpExerciseName::WeightedBentKneeVUp => "weighted_bent_knee_v_up",
            SitUpExerciseName::ButterflySitUp => "butterfly_sit_up",
            SitUpExerciseName::WeightedButterflySitup => "weighted_butterfly_situp",
            SitUpExerciseName::CrossPunchRollUp => "cross_punch_roll_up",
            SitUpExerciseName::WeightedCrossPunchRollUp => "weighted_cross_punch_roll_up",
            SitUpExerciseName::CrossedArmsSitUp => "crossed_arms_sit_up",
            SitUpExerciseName::WeightedCrossedArmsSitUp => "weighted_crossed_arms_sit_up",
            SitUpExerciseName::GetUpSitUp => "get_up_sit_up",
            SitUpExerciseName::WeightedGetUpSitUp => "weighted_get_up_sit_up",
            SitUpExerciseName::HoveringSitUp => "hovering_sit_up",
            SitUpExerciseName::WeightedHoveringSitUp => "weighted_hovering_sit_up",
            SitUpExerciseName::KettlebellSitUp => "kettlebell_sit_up",
            SitUpExerciseName::MedicineBallAlternatingVUp => "medicine_ball_alternating_v_up",
            SitUpExerciseName::MedicineBallSitUp => "medicine_ball_sit_up",
            SitUpExerciseName::MedicineBallVUp => "medicine_ball_v_up",
            SitUpExerciseName::ModifiedSitUp => "modified_sit_up",
            SitUpExerciseName::NegativeSitUp => "negative_sit_up",
            SitUpExerciseName::OneArmFullSitUp => "one_arm_full_sit_up",
            SitUpExerciseName::RecliningCircle => "reclining_circle",
            SitUpExerciseName::WeightedRecliningCircle => "weighted_reclining_circle",
            SitUpExerciseName::ReverseCurlUp => "reverse_curl_up",
            SitUpExerciseName::WeightedReverseCurlUp => "weighted_reverse_curl_up",
            SitUpExerciseName::SingleLegSwissBallJackknife => "single_leg_swiss_ball_jackknife",
            SitUpExerciseName::WeightedSingleLegSwissBallJackknife => {
                "weighted_single_leg_swiss_ball_jackknife"
            }
            SitUpExerciseName::TheTeaser => "the_teaser",
            SitUpExerciseName::TheTeaserWeighted => "the_teaser_weighted",
            SitUpExerciseName::ThreePartRollDown => "three_part_roll_down",
            SitUpExerciseName::WeightedThreePartRollDown => "weighted_three_part_roll_down",
            SitUpExerciseName::VUp => "v_up",
            SitUpExerciseName::WeightedVUp => "weighted_v_up",
            SitUpExerciseName::WeightedRussianTwistOnSwissBall => {
                "weighted_russian_twist_on_swiss_ball"
            }
            SitUpExerciseName::WeightedSitUp => "weighted_sit_up",
            SitUpExerciseName::XAbs => "x_abs",
            SitUpExerciseName::WeightedXAbs => "weighted_x_abs",
            SitUpExerciseName::SitUp => "sit_up",
            SitUpExerciseName::GhdSitUps => "ghd_sit_ups",
            SitUpExerciseName::SitUpTurkishGetUp => "sit_up_turkish_get_up",
            SitUpExerciseName::RussianTwistOnSwissBall => "russian_twist_on_swiss_ball",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(SitUpExerciseName::AlternatingSitUp),
            1 => Some(SitUpExerciseName::WeightedAlternatingSitUp),
            2 => Some(SitUpExerciseName::BentKneeVUp),
            3 => Some(SitUpExerciseName::WeightedBentKneeVUp),
            4 => Some(SitUpExerciseName::ButterflySitUp),
            5 => Some(SitUpExerciseName::WeightedButterflySitup),
            6 => Some(SitUpExerciseName::CrossPunchRollUp),
            7 => Some(SitUpExerciseName::WeightedCrossPunchRollUp),
            8 => Some(SitUpExerciseName::CrossedArmsSitUp),
            9 => Some(SitUpExerciseName::WeightedCrossedArmsSitUp),
            10 => Some(SitUpExerciseName::GetUpSitUp),
            11 => Some(SitUpExerciseName::WeightedGetUpSitUp),
            12 => Some(SitUpExerciseName::HoveringSitUp),
            13 => Some(SitUpExerciseName::WeightedHoveringSitUp),
            14 => Some(SitUpExerciseName::KettlebellSitUp),
            15 => Some(SitUpExerciseName::MedicineBallAlternatingVUp),
            16 => Some(SitUpExerciseName::MedicineBallSitUp),
            17 => Some(SitUpExerciseName::MedicineBallVUp),
            18 => Some(SitUpExerciseName::ModifiedSitUp),
            19 => Some(SitUpExerciseName::NegativeSitUp),
            20 => Some(SitUpExerciseName::OneArmFullSitUp),
            21 => Some(SitUpExerciseName::RecliningCircle),
            22 => Some(SitUpExerciseName::WeightedRecliningCircle),
            23 => Some(SitUpExerciseName::ReverseCurlUp),
            24 => Some(SitUpExerciseName::WeightedReverseCurlUp),
            25 => Some(SitUpExerciseName::SingleLegSwissBallJackknife),
            26 => Some(SitUpExerciseName::WeightedSingleLegSwissBallJackknife),
            27 => Some(SitUpExerciseName::TheTeaser),
            28 => Some(SitUpExerciseName::TheTeaserWeighted),
            29 => Some(SitUpExerciseName::ThreePartRollDown),
            30 => Some(SitUpExerciseName::WeightedThreePartRollDown),
            31 => Some(SitUpExerciseName::VUp),
            32 => Some(SitUpExerciseName::WeightedVUp),
            33 => Some(SitUpExerciseName::WeightedRussianTwistOnSwissBall),
            34 => Some(SitUpExerciseName::WeightedSitUp),
            35 => Some(SitUpExerciseName::XAbs),
            36 => Some(SitUpExerciseName::WeightedXAbs),
            37 => Some(SitUpExerciseName::SitUp),
            38 => Some(SitUpExerciseName::GhdSitUps),
            39 => Some(SitUpExerciseName::SitUpTurkishGetUp),
            40 => Some(SitUpExerciseName::RussianTwistOnSwissBall),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "alternating_sit_up" => Some(SitUpExerciseName::AlternatingSitUp),
            "weighted_alternating_sit_up" => Some(SitUpExerciseName::WeightedAlternatingSitUp),
            "bent_knee_v_up" => Some(SitUpExerciseName::BentKneeVUp),
            "weighted_bent_knee_v_up" => Some(SitUpExerciseName::WeightedBentKneeVUp),
            "butterfly_sit_up" => Some(SitUpExerciseName::ButterflySitUp),
            "weighted_butterfly_situp" => Some(SitUpExerciseName::WeightedButterflySitup),
            "cross_punch_roll_up" => Some(SitUpExerciseName::CrossPunchRollUp),
            "weighted_cross_punch_roll_up" => Some(SitUpExerciseName::WeightedCrossPunchRollUp),
            "crossed_arms_sit_up" => Some(SitUpExerciseName::CrossedArmsSitUp),
            "weighted_crossed_arms_sit_up" => Some(SitUpExerciseName::WeightedCrossedArmsSitUp),
            "get_up_sit_up" => Some(SitUpExerciseName::GetUpSitUp),
            "weighted_get_up_sit_up" => Some(SitUpExerciseName::WeightedGetUpSitUp),
            "hovering_sit_up" => Some(SitUpExerciseName::HoveringSitUp),
            "weighted_hovering_sit_up" => Some(SitUpExerciseName::WeightedHoveringSitUp),
            "kettlebell_sit_up" => Some(SitUpExerciseName::KettlebellSitUp),
            "medicine_ball_alternating_v_up" => Some(SitUpExerciseName::MedicineBallAlternatingVUp),
            "medicine_ball_sit_up" => Some(SitUpExerciseName::MedicineBallSitUp),
            "medicine_ball_v_up" => Some(SitUpExerciseName::MedicineBallVUp),
            "modified_sit_up" => Some(SitUpExerciseName::ModifiedSitUp),
            "negative_sit_up" => Some(SitUpExerciseName::NegativeSitUp),
            "one_arm_full_sit_up" => Some(SitUpExerciseName::OneArmFullSitUp),
            "reclining_circle" => Some(SitUpExerciseName::RecliningCircle),
            "weighted_reclining_circle" => Some(SitUpExerciseName::WeightedRecliningCircle),
            "reverse_curl_up" => Some(SitUpExerciseName::ReverseCurlUp),
            "weighted_reverse_curl_up" => Some(SitUpExerciseName::WeightedReverseCurlUp),
            "single_leg_swiss_ball_jackknife" => {
                Some(SitUpExerciseName::SingleLegSwissBallJackknife)
            }
            "weighted_single_leg_swiss_ball_jackknife" => {
                Some(SitUpExerciseName::WeightedSingleLegSwissBallJackknife)
            }
            "the_teaser" => Some(SitUpExerciseName::TheTeaser),
            "the_teaser_weighted" => Some(SitUpExerciseName::TheTeaserWeighted),
            "three_part_roll_down" => Some(SitUpExerciseName::ThreePartRollDown),
            "weighted_three_part_roll_down" => Some(SitUpExerciseName::WeightedThreePartRollDown),
            "v_up" => Some(SitUpExerciseName::VUp),
            "weighted_v_up" => Some(SitUpExerciseName::WeightedVUp),
            "weighted_russian_twist_on_swiss_ball" => {
                Some(SitUpExerciseName::WeightedRussianTwistOnSwissBall)
            }
            "weighted_sit_up" => Some(SitUpExerciseName::WeightedSitUp),
            "x_abs" => Some(SitUpExerciseName::XAbs),
            "weighted_x_abs" => Some(SitUpExerciseName::WeightedXAbs),
            "sit_up" => Some(SitUpExerciseName::SitUp),
            "ghd_sit_ups" => Some(SitUpExerciseName::GhdSitUps),
            "sit_up_turkish_get_up" => Some(SitUpExerciseName::SitUpTurkishGetUp),
            "russian_twist_on_swiss_ball" => Some(SitUpExerciseName::RussianTwistOnSwissBall),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum SquatExerciseName {
    LegPress = 0,
    BackSquatWithBodyBar = 1,
    BackSquats = 2,
    WeightedBackSquats = 3,
    BalancingSquat = 4,
    WeightedBalancingSquat = 5,
    BarbellBackSquat = 6,
    BarbellBoxSquat = 7,
    BarbellFrontSquat = 8,
    BarbellHackSquat = 9,
    BarbellHangSquatSnatch = 10,
    BarbellLateralStepUp = 11,
    BarbellQuarterSquat = 12,
    BarbellSiffSquat = 13,
    BarbellSquatSnatch = 14,
    BarbellSquatWithHeelsRaised = 15,
    BarbellStepover = 16,
    BarbellStepUp = 17,
    BenchSquatWithRotationalChop = 18,
    WeightedBenchSquatWithRotationalChop = 19,
    BodyWeightWallSquat = 20,
    WeightedWallSquat = 21,
    BoxStepSquat = 22,
    WeightedBoxStepSquat = 23,
    BracedSquat = 24,
    CrossedArmBarbellFrontSquat = 25,
    CrossoverDumbbellStepUp = 26,
    DumbbellFrontSquat = 27,
    DumbbellSplitSquat = 28,
    DumbbellSquat = 29,
    DumbbellSquatClean = 30,
    DumbbellStepover = 31,
    DumbbellStepUp = 32,
    ElevatedSingleLegSquat = 33,
    WeightedElevatedSingleLegSquat = 34,
    FigureFourSquats = 35,
    WeightedFigureFourSquats = 36,
    GobletSquat = 37,
    KettlebellSquat = 38,
    KettlebellSwingOverhead = 39,
    KettlebellSwingWithFlipToSquat = 40,
    LateralDumbbellStepUp = 41,
    OneLeggedSquat = 42,
    OverheadDumbbellSquat = 43,
    OverheadSquat = 44,
    PartialSingleLegSquat = 45,
    WeightedPartialSingleLegSquat = 46,
    PistolSquat = 47,
    WeightedPistolSquat = 48,
    PlieSlides = 49,
    WeightedPlieSlides = 50,
    PlieSquat = 51,
    WeightedPlieSquat = 52,
    PrisonerSquat = 53,
    WeightedPrisonerSquat = 54,
    SingleLegBenchGetUp = 55,
    WeightedSingleLegBenchGetUp = 56,
    SingleLegBenchSquat = 57,
    WeightedSingleLegBenchSquat = 58,
    SingleLegSquatOnSwissBall = 59,
    WeightedSingleLegSquatOnSwissBall = 60,
    Squat = 61,
    WeightedSquat = 62,
    SquatsWithBand = 63,
    StaggeredSquat = 64,
    WeightedStaggeredSquat = 65,
    StepUp = 66,
    WeightedStepUp = 67,
    SuitcaseSquats = 68,
    SumoSquat = 69,
    SumoSquatSlideIn = 70,
    WeightedSumoSquatSlideIn = 71,
    SumoSquatToHighPull = 72,
    SumoSquatToStand = 73,
    WeightedSumoSquatToStand = 74,
    SumoSquatWithRotation = 75,
    WeightedSumoSquatWithRotation = 76,
    SwissBallBodyWeightWallSquat = 77,
    WeightedSwissBallWallSquat = 78,
    Thrusters = 79,
    UnevenSquat = 80,
    WeightedUnevenSquat = 81,
    WaistSlimmingSquat = 82,
    WallBall = 83,
    WideStanceBarbellSquat = 84,
    WideStanceGobletSquat = 85,
    ZercherSquat = 86,
    KbsOverhead = 87,
    SquatAndSideKick = 88,
    SquatJumpsInNOut = 89,
    PilatesPlieSquatsParallelTurnedOutFlatAndHeels = 90,
    ReleveStraightLegAndKneeBentWithOneLegVariation = 91,
    AlternatingBoxDumbbellStepUps = 92,
    DumbbellOverheadSquatSingleArm = 93,
    DumbbellSquatSnatch = 94,
    MedicineBallSquat = 95,
    WallBallSquatAndPress = 97,
    SquatAmericanSwing = 98,
    AirSquat = 100,
    DumbbellThrusters = 101,
    OverheadBarbellSquat = 102,
}

impl SquatExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            SquatExerciseName::LegPress => "leg_press",
            SquatExerciseName::BackSquatWithBodyBar => "back_squat_with_body_bar",
            SquatExerciseName::BackSquats => "back_squats",
            SquatExerciseName::WeightedBackSquats => "weighted_back_squats",
            SquatExerciseName::BalancingSquat => "balancing_squat",
            SquatExerciseName::WeightedBalancingSquat => "weighted_balancing_squat",
            SquatExerciseName::BarbellBackSquat => "barbell_back_squat",
            SquatExerciseName::BarbellBoxSquat => "barbell_box_squat",
            SquatExerciseName::BarbellFrontSquat => "barbell_front_squat",
            SquatExerciseName::BarbellHackSquat => "barbell_hack_squat",
            SquatExerciseName::BarbellHangSquatSnatch => "barbell_hang_squat_snatch",
            SquatExerciseName::BarbellLateralStepUp => "barbell_lateral_step_up",
            SquatExerciseName::BarbellQuarterSquat => "barbell_quarter_squat",
            SquatExerciseName::BarbellSiffSquat => "barbell_siff_squat",
            SquatExerciseName::BarbellSquatSnatch => "barbell_squat_snatch",
            SquatExerciseName::BarbellSquatWithHeelsRaised => "barbell_squat_with_heels_raised",
            SquatExerciseName::BarbellStepover => "barbell_stepover",
            SquatExerciseName::BarbellStepUp => "barbell_step_up",
            SquatExerciseName::BenchSquatWithRotationalChop => "bench_squat_with_rotational_chop",
            SquatExerciseName::WeightedBenchSquatWithRotationalChop => {
                "weighted_bench_squat_with_rotational_chop"
            }
            SquatExerciseName::BodyWeightWallSquat => "body_weight_wall_squat",
            SquatExerciseName::WeightedWallSquat => "weighted_wall_squat",
            SquatExerciseName::BoxStepSquat => "box_step_squat",
            SquatExerciseName::WeightedBoxStepSquat => "weighted_box_step_squat",
            SquatExerciseName::BracedSquat => "braced_squat",
            SquatExerciseName::CrossedArmBarbellFrontSquat => "crossed_arm_barbell_front_squat",
            SquatExerciseName::CrossoverDumbbellStepUp => "crossover_dumbbell_step_up",
            SquatExerciseName::DumbbellFrontSquat => "dumbbell_front_squat",
            SquatExerciseName::DumbbellSplitSquat => "dumbbell_split_squat",
            SquatExerciseName::DumbbellSquat => "dumbbell_squat",
            SquatExerciseName::DumbbellSquatClean => "dumbbell_squat_clean",
            SquatExerciseName::DumbbellStepover => "dumbbell_stepover",
            SquatExerciseName::DumbbellStepUp => "dumbbell_step_up",
            SquatExerciseName::ElevatedSingleLegSquat => "elevated_single_leg_squat",
            SquatExerciseName::WeightedElevatedSingleLegSquat => {
                "weighted_elevated_single_leg_squat"
            }
            SquatExerciseName::FigureFourSquats => "figure_four_squats",
            SquatExerciseName::WeightedFigureFourSquats => "weighted_figure_four_squats",
            SquatExerciseName::GobletSquat => "goblet_squat",
            SquatExerciseName::KettlebellSquat => "kettlebell_squat",
            SquatExerciseName::KettlebellSwingOverhead => "kettlebell_swing_overhead",
            SquatExerciseName::KettlebellSwingWithFlipToSquat => {
                "kettlebell_swing_with_flip_to_squat"
            }
            SquatExerciseName::LateralDumbbellStepUp => "lateral_dumbbell_step_up",
            SquatExerciseName::OneLeggedSquat => "one_legged_squat",
            SquatExerciseName::OverheadDumbbellSquat => "overhead_dumbbell_squat",
            SquatExerciseName::OverheadSquat => "overhead_squat",
            SquatExerciseName::PartialSingleLegSquat => "partial_single_leg_squat",
            SquatExerciseName::WeightedPartialSingleLegSquat => "weighted_partial_single_leg_squat",
            SquatExerciseName::PistolSquat => "pistol_squat",
            SquatExerciseName::WeightedPistolSquat => "weighted_pistol_squat",
            SquatExerciseName::PlieSlides => "plie_slides",
            SquatExerciseName::WeightedPlieSlides => "weighted_plie_slides",
            SquatExerciseName::PlieSquat => "plie_squat",
            SquatExerciseName::WeightedPlieSquat => "weighted_plie_squat",
            SquatExerciseName::PrisonerSquat => "prisoner_squat",
            SquatExerciseName::WeightedPrisonerSquat => "weighted_prisoner_squat",
            SquatExerciseName::SingleLegBenchGetUp => "single_leg_bench_get_up",
            SquatExerciseName::WeightedSingleLegBenchGetUp => "weighted_single_leg_bench_get_up",
            SquatExerciseName::SingleLegBenchSquat => "single_leg_bench_squat",
            SquatExerciseName::WeightedSingleLegBenchSquat => "weighted_single_leg_bench_squat",
            SquatExerciseName::SingleLegSquatOnSwissBall => "single_leg_squat_on_swiss_ball",
            SquatExerciseName::WeightedSingleLegSquatOnSwissBall => {
                "weighted_single_leg_squat_on_swiss_ball"
            }
            SquatExerciseName::Squat => "squat",
            SquatExerciseName::WeightedSquat => "weighted_squat",
            SquatExerciseName::SquatsWithBand => "squats_with_band",
            SquatExerciseName::StaggeredSquat => "staggered_squat",
            SquatExerciseName::WeightedStaggeredSquat => "weighted_staggered_squat",
            SquatExerciseName::StepUp => "step_up",
            SquatExerciseName::WeightedStepUp => "weighted_step_up",
            SquatExerciseName::SuitcaseSquats => "suitcase_squats",
            SquatExerciseName::SumoSquat => "sumo_squat",
            SquatExerciseName::SumoSquatSlideIn => "sumo_squat_slide_in",
            SquatExerciseName::WeightedSumoSquatSlideIn => "weighted_sumo_squat_slide_in",
            SquatExerciseName::SumoSquatToHighPull => "sumo_squat_to_high_pull",
            SquatExerciseName::SumoSquatToStand => "sumo_squat_to_stand",
            SquatExerciseName::WeightedSumoSquatToStand => "weighted_sumo_squat_to_stand",
            SquatExerciseName::SumoSquatWithRotation => "sumo_squat_with_rotation",
            SquatExerciseName::WeightedSumoSquatWithRotation => "weighted_sumo_squat_with_rotation",
            SquatExerciseName::SwissBallBodyWeightWallSquat => "swiss_ball_body_weight_wall_squat",
            SquatExerciseName::WeightedSwissBallWallSquat => "weighted_swiss_ball_wall_squat",
            SquatExerciseName::Thrusters => "thrusters",
            SquatExerciseName::UnevenSquat => "uneven_squat",
            SquatExerciseName::WeightedUnevenSquat => "weighted_uneven_squat",
            SquatExerciseName::WaistSlimmingSquat => "waist_slimming_squat",
            SquatExerciseName::WallBall => "wall_ball",
            SquatExerciseName::WideStanceBarbellSquat => "wide_stance_barbell_squat",
            SquatExerciseName::WideStanceGobletSquat => "wide_stance_goblet_squat",
            SquatExerciseName::ZercherSquat => "zercher_squat",
            SquatExerciseName::KbsOverhead => "kbs_overhead",
            SquatExerciseName::SquatAndSideKick => "squat_and_side_kick",
            SquatExerciseName::SquatJumpsInNOut => "squat_jumps_in_n_out",
            SquatExerciseName::PilatesPlieSquatsParallelTurnedOutFlatAndHeels => {
                "pilates_plie_squats_parallel_turned_out_flat_and_heels"
            }
            SquatExerciseName::ReleveStraightLegAndKneeBentWithOneLegVariation => {
                "releve_straight_leg_and_knee_bent_with_one_leg_variation"
            }
            SquatExerciseName::AlternatingBoxDumbbellStepUps => "alternating_box_dumbbell_step_ups",
            SquatExerciseName::DumbbellOverheadSquatSingleArm => {
                "dumbbell_overhead_squat_single_arm"
            }
            SquatExerciseName::DumbbellSquatSnatch => "dumbbell_squat_snatch",
            SquatExerciseName::MedicineBallSquat => "medicine_ball_squat",
            SquatExerciseName::WallBallSquatAndPress => "wall_ball_squat_and_press",
            SquatExerciseName::SquatAmericanSwing => "squat_american_swing",
            SquatExerciseName::AirSquat => "air_squat",
            SquatExerciseName::DumbbellThrusters => "dumbbell_thrusters",
            SquatExerciseName::OverheadBarbellSquat => "overhead_barbell_squat",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(SquatExerciseName::LegPress),
            1 => Some(SquatExerciseName::BackSquatWithBodyBar),
            2 => Some(SquatExerciseName::BackSquats),
            3 => Some(SquatExerciseName::WeightedBackSquats),
            4 => Some(SquatExerciseName::BalancingSquat),
            5 => Some(SquatExerciseName::WeightedBalancingSquat),
            6 => Some(SquatExerciseName::BarbellBackSquat),
            7 => Some(SquatExerciseName::BarbellBoxSquat),
            8 => Some(SquatExerciseName::BarbellFrontSquat),
            9 => Some(SquatExerciseName::BarbellHackSquat),
            10 => Some(SquatExerciseName::BarbellHangSquatSnatch),
            11 => Some(SquatExerciseName::BarbellLateralStepUp),
            12 => Some(SquatExerciseName::BarbellQuarterSquat),
            13 => Some(SquatExerciseName::BarbellSiffSquat),
            14 => Some(SquatExerciseName::BarbellSquatSnatch),
            15 => Some(SquatExerciseName::BarbellSquatWithHeelsRaised),
            16 => Some(SquatExerciseName::BarbellStepover),
            17 => Some(SquatExerciseName::BarbellStepUp),
            18 => Some(SquatExerciseName::BenchSquatWithRotationalChop),
            19 => Some(SquatExerciseName::WeightedBenchSquatWithRotationalChop),
            20 => Some(SquatExerciseName::BodyWeightWallSquat),
            21 => Some(SquatExerciseName::WeightedWallSquat),
            22 => Some(SquatExerciseName::BoxStepSquat),
            23 => Some(SquatExerciseName::WeightedBoxStepSquat),
            24 => Some(SquatExerciseName::BracedSquat),
            25 => Some(SquatExerciseName::CrossedArmBarbellFrontSquat),
            26 => Some(SquatExerciseName::CrossoverDumbbellStepUp),
            27 => Some(SquatExerciseName::DumbbellFrontSquat),
            28 => Some(SquatExerciseName::DumbbellSplitSquat),
            29 => Some(SquatExerciseName::DumbbellSquat),
            30 => Some(SquatExerciseName::DumbbellSquatClean),
            31 => Some(SquatExerciseName::DumbbellStepover),
            32 => Some(SquatExerciseName::DumbbellStepUp),
            33 => Some(SquatExerciseName::ElevatedSingleLegSquat),
            34 => Some(SquatExerciseName::WeightedElevatedSingleLegSquat),
            35 => Some(SquatExerciseName::FigureFourSquats),
            36 => Some(SquatExerciseName::WeightedFigureFourSquats),
            37 => Some(SquatExerciseName::GobletSquat),
            38 => Some(SquatExerciseName::KettlebellSquat),
            39 => Some(SquatExerciseName::KettlebellSwingOverhead),
            40 => Some(SquatExerciseName::KettlebellSwingWithFlipToSquat),
            41 => Some(SquatExerciseName::LateralDumbbellStepUp),
            42 => Some(SquatExerciseName::OneLeggedSquat),
            43 => Some(SquatExerciseName::OverheadDumbbellSquat),
            44 => Some(SquatExerciseName::OverheadSquat),
            45 => Some(SquatExerciseName::PartialSingleLegSquat),
            46 => Some(SquatExerciseName::WeightedPartialSingleLegSquat),
            47 => Some(SquatExerciseName::PistolSquat),
            48 => Some(SquatExerciseName::WeightedPistolSquat),
            49 => Some(SquatExerciseName::PlieSlides),
            50 => Some(SquatExerciseName::WeightedPlieSlides),
            51 => Some(SquatExerciseName::PlieSquat),
            52 => Some(SquatExerciseName::WeightedPlieSquat),
            53 => Some(SquatExerciseName::PrisonerSquat),
            54 => Some(SquatExerciseName::WeightedPrisonerSquat),
            55 => Some(SquatExerciseName::SingleLegBenchGetUp),
            56 => Some(SquatExerciseName::WeightedSingleLegBenchGetUp),
            57 => Some(SquatExerciseName::SingleLegBenchSquat),
            58 => Some(SquatExerciseName::WeightedSingleLegBenchSquat),
            59 => Some(SquatExerciseName::SingleLegSquatOnSwissBall),
            60 => Some(SquatExerciseName::WeightedSingleLegSquatOnSwissBall),
            61 => Some(SquatExerciseName::Squat),
            62 => Some(SquatExerciseName::WeightedSquat),
            63 => Some(SquatExerciseName::SquatsWithBand),
            64 => Some(SquatExerciseName::StaggeredSquat),
            65 => Some(SquatExerciseName::WeightedStaggeredSquat),
            66 => Some(SquatExerciseName::StepUp),
            67 => Some(SquatExerciseName::WeightedStepUp),
            68 => Some(SquatExerciseName::SuitcaseSquats),
            69 => Some(SquatExerciseName::SumoSquat),
            70 => Some(SquatExerciseName::SumoSquatSlideIn),
            71 => Some(SquatExerciseName::WeightedSumoSquatSlideIn),
            72 => Some(SquatExerciseName::SumoSquatToHighPull),
            73 => Some(SquatExerciseName::SumoSquatToStand),
            74 => Some(SquatExerciseName::WeightedSumoSquatToStand),
            75 => Some(SquatExerciseName::SumoSquatWithRotation),
            76 => Some(SquatExerciseName::WeightedSumoSquatWithRotation),
            77 => Some(SquatExerciseName::SwissBallBodyWeightWallSquat),
            78 => Some(SquatExerciseName::WeightedSwissBallWallSquat),
            79 => Some(SquatExerciseName::Thrusters),
            80 => Some(SquatExerciseName::UnevenSquat),
            81 => Some(SquatExerciseName::WeightedUnevenSquat),
            82 => Some(SquatExerciseName::WaistSlimmingSquat),
            83 => Some(SquatExerciseName::WallBall),
            84 => Some(SquatExerciseName::WideStanceBarbellSquat),
            85 => Some(SquatExerciseName::WideStanceGobletSquat),
            86 => Some(SquatExerciseName::ZercherSquat),
            87 => Some(SquatExerciseName::KbsOverhead),
            88 => Some(SquatExerciseName::SquatAndSideKick),
            89 => Some(SquatExerciseName::SquatJumpsInNOut),
            90 => Some(SquatExerciseName::PilatesPlieSquatsParallelTurnedOutFlatAndHeels),
            91 => Some(SquatExerciseName::ReleveStraightLegAndKneeBentWithOneLegVariation),
            92 => Some(SquatExerciseName::AlternatingBoxDumbbellStepUps),
            93 => Some(SquatExerciseName::DumbbellOverheadSquatSingleArm),
            94 => Some(SquatExerciseName::DumbbellSquatSnatch),
            95 => Some(SquatExerciseName::MedicineBallSquat),
            97 => Some(SquatExerciseName::WallBallSquatAndPress),
            98 => Some(SquatExerciseName::SquatAmericanSwing),
            100 => Some(SquatExerciseName::AirSquat),
            101 => Some(SquatExerciseName::DumbbellThrusters),
            102 => Some(SquatExerciseName::OverheadBarbellSquat),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "leg_press" => Some(SquatExerciseName::LegPress),
            "back_squat_with_body_bar" => Some(SquatExerciseName::BackSquatWithBodyBar),
            "back_squats" => Some(SquatExerciseName::BackSquats),
            "weighted_back_squats" => Some(SquatExerciseName::WeightedBackSquats),
            "balancing_squat" => Some(SquatExerciseName::BalancingSquat),
            "weighted_balancing_squat" => Some(SquatExerciseName::WeightedBalancingSquat),
            "barbell_back_squat" => Some(SquatExerciseName::BarbellBackSquat),
            "barbell_box_squat" => Some(SquatExerciseName::BarbellBoxSquat),
            "barbell_front_squat" => Some(SquatExerciseName::BarbellFrontSquat),
            "barbell_hack_squat" => Some(SquatExerciseName::BarbellHackSquat),
            "barbell_hang_squat_snatch" => Some(SquatExerciseName::BarbellHangSquatSnatch),
            "barbell_lateral_step_up" => Some(SquatExerciseName::BarbellLateralStepUp),
            "barbell_quarter_squat" => Some(SquatExerciseName::BarbellQuarterSquat),
            "barbell_siff_squat" => Some(SquatExerciseName::BarbellSiffSquat),
            "barbell_squat_snatch" => Some(SquatExerciseName::BarbellSquatSnatch),
            "barbell_squat_with_heels_raised" => {
                Some(SquatExerciseName::BarbellSquatWithHeelsRaised)
            }
            "barbell_stepover" => Some(SquatExerciseName::BarbellStepover),
            "barbell_step_up" => Some(SquatExerciseName::BarbellStepUp),
            "bench_squat_with_rotational_chop" => {
                Some(SquatExerciseName::BenchSquatWithRotationalChop)
            }
            "weighted_bench_squat_with_rotational_chop" => {
                Some(SquatExerciseName::WeightedBenchSquatWithRotationalChop)
            }
            "body_weight_wall_squat" => Some(SquatExerciseName::BodyWeightWallSquat),
            "weighted_wall_squat" => Some(SquatExerciseName::WeightedWallSquat),
            "box_step_squat" => Some(SquatExerciseName::BoxStepSquat),
            "weighted_box_step_squat" => Some(SquatExerciseName::WeightedBoxStepSquat),
            "braced_squat" => Some(SquatExerciseName::BracedSquat),
            "crossed_arm_barbell_front_squat" => {
                Some(SquatExerciseName::CrossedArmBarbellFrontSquat)
            }
            "crossover_dumbbell_step_up" => Some(SquatExerciseName::CrossoverDumbbellStepUp),
            "dumbbell_front_squat" => Some(SquatExerciseName::DumbbellFrontSquat),
            "dumbbell_split_squat" => Some(SquatExerciseName::DumbbellSplitSquat),
            "dumbbell_squat" => Some(SquatExerciseName::DumbbellSquat),
            "dumbbell_squat_clean" => Some(SquatExerciseName::DumbbellSquatClean),
            "dumbbell_stepover" => Some(SquatExerciseName::DumbbellStepover),
            "dumbbell_step_up" => Some(SquatExerciseName::DumbbellStepUp),
            "elevated_single_leg_squat" => Some(SquatExerciseName::ElevatedSingleLegSquat),
            "weighted_elevated_single_leg_squat" => {
                Some(SquatExerciseName::WeightedElevatedSingleLegSquat)
            }
            "figure_four_squats" => Some(SquatExerciseName::FigureFourSquats),
            "weighted_figure_four_squats" => Some(SquatExerciseName::WeightedFigureFourSquats),
            "goblet_squat" => Some(SquatExerciseName::GobletSquat),
            "kettlebell_squat" => Some(SquatExerciseName::KettlebellSquat),
            "kettlebell_swing_overhead" => Some(SquatExerciseName::KettlebellSwingOverhead),
            "kettlebell_swing_with_flip_to_squat" => {
                Some(SquatExerciseName::KettlebellSwingWithFlipToSquat)
            }
            "lateral_dumbbell_step_up" => Some(SquatExerciseName::LateralDumbbellStepUp),
            "one_legged_squat" => Some(SquatExerciseName::OneLeggedSquat),
            "overhead_dumbbell_squat" => Some(SquatExerciseName::OverheadDumbbellSquat),
            "overhead_squat" => Some(SquatExerciseName::OverheadSquat),
            "partial_single_leg_squat" => Some(SquatExerciseName::PartialSingleLegSquat),
            "weighted_partial_single_leg_squat" => {
                Some(SquatExerciseName::WeightedPartialSingleLegSquat)
            }
            "pistol_squat" => Some(SquatExerciseName::PistolSquat),
            "weighted_pistol_squat" => Some(SquatExerciseName::WeightedPistolSquat),
            "plie_slides" => Some(SquatExerciseName::PlieSlides),
            "weighted_plie_slides" => Some(SquatExerciseName::WeightedPlieSlides),
            "plie_squat" => Some(SquatExerciseName::PlieSquat),
            "weighted_plie_squat" => Some(SquatExerciseName::WeightedPlieSquat),
            "prisoner_squat" => Some(SquatExerciseName::PrisonerSquat),
            "weighted_prisoner_squat" => Some(SquatExerciseName::WeightedPrisonerSquat),
            "single_leg_bench_get_up" => Some(SquatExerciseName::SingleLegBenchGetUp),
            "weighted_single_leg_bench_get_up" => {
                Some(SquatExerciseName::WeightedSingleLegBenchGetUp)
            }
            "single_leg_bench_squat" => Some(SquatExerciseName::SingleLegBenchSquat),
            "weighted_single_leg_bench_squat" => {
                Some(SquatExerciseName::WeightedSingleLegBenchSquat)
            }
            "single_leg_squat_on_swiss_ball" => Some(SquatExerciseName::SingleLegSquatOnSwissBall),
            "weighted_single_leg_squat_on_swiss_ball" => {
                Some(SquatExerciseName::WeightedSingleLegSquatOnSwissBall)
            }
            "squat" => Some(SquatExerciseName::Squat),
            "weighted_squat" => Some(SquatExerciseName::WeightedSquat),
            "squats_with_band" => Some(SquatExerciseName::SquatsWithBand),
            "staggered_squat" => Some(SquatExerciseName::StaggeredSquat),
            "weighted_staggered_squat" => Some(SquatExerciseName::WeightedStaggeredSquat),
            "step_up" => Some(SquatExerciseName::StepUp),
            "weighted_step_up" => Some(SquatExerciseName::WeightedStepUp),
            "suitcase_squats" => Some(SquatExerciseName::SuitcaseSquats),
            "sumo_squat" => Some(SquatExerciseName::SumoSquat),
            "sumo_squat_slide_in" => Some(SquatExerciseName::SumoSquatSlideIn),
            "weighted_sumo_squat_slide_in" => Some(SquatExerciseName::WeightedSumoSquatSlideIn),
            "sumo_squat_to_high_pull" => Some(SquatExerciseName::SumoSquatToHighPull),
            "sumo_squat_to_stand" => Some(SquatExerciseName::SumoSquatToStand),
            "weighted_sumo_squat_to_stand" => Some(SquatExerciseName::WeightedSumoSquatToStand),
            "sumo_squat_with_rotation" => Some(SquatExerciseName::SumoSquatWithRotation),
            "weighted_sumo_squat_with_rotation" => {
                Some(SquatExerciseName::WeightedSumoSquatWithRotation)
            }
            "swiss_ball_body_weight_wall_squat" => {
                Some(SquatExerciseName::SwissBallBodyWeightWallSquat)
            }
            "weighted_swiss_ball_wall_squat" => Some(SquatExerciseName::WeightedSwissBallWallSquat),
            "thrusters" => Some(SquatExerciseName::Thrusters),
            "uneven_squat" => Some(SquatExerciseName::UnevenSquat),
            "weighted_uneven_squat" => Some(SquatExerciseName::WeightedUnevenSquat),
            "waist_slimming_squat" => Some(SquatExerciseName::WaistSlimmingSquat),
            "wall_ball" => Some(SquatExerciseName::WallBall),
            "wide_stance_barbell_squat" => Some(SquatExerciseName::WideStanceBarbellSquat),
            "wide_stance_goblet_squat" => Some(SquatExerciseName::WideStanceGobletSquat),
            "zercher_squat" => Some(SquatExerciseName::ZercherSquat),
            "kbs_overhead" => Some(SquatExerciseName::KbsOverhead),
            "squat_and_side_kick" => Some(SquatExerciseName::SquatAndSideKick),
            "squat_jumps_in_n_out" => Some(SquatExerciseName::SquatJumpsInNOut),
            "pilates_plie_squats_parallel_turned_out_flat_and_heels" => {
                Some(SquatExerciseName::PilatesPlieSquatsParallelTurnedOutFlatAndHeels)
            }
            "releve_straight_leg_and_knee_bent_with_one_leg_variation" => {
                Some(SquatExerciseName::ReleveStraightLegAndKneeBentWithOneLegVariation)
            }
            "alternating_box_dumbbell_step_ups" => {
                Some(SquatExerciseName::AlternatingBoxDumbbellStepUps)
            }
            "dumbbell_overhead_squat_single_arm" => {
                Some(SquatExerciseName::DumbbellOverheadSquatSingleArm)
            }
            "dumbbell_squat_snatch" => Some(SquatExerciseName::DumbbellSquatSnatch),
            "medicine_ball_squat" => Some(SquatExerciseName::MedicineBallSquat),
            "wall_ball_squat_and_press" => Some(SquatExerciseName::WallBallSquatAndPress),
            "squat_american_swing" => Some(SquatExerciseName::SquatAmericanSwing),
            "air_squat" => Some(SquatExerciseName::AirSquat),
            "dumbbell_thrusters" => Some(SquatExerciseName::DumbbellThrusters),
            "overhead_barbell_squat" => Some(SquatExerciseName::OverheadBarbellSquat),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum TotalBodyExerciseName {
    Burpee = 0,
    WeightedBurpee = 1,
    BurpeeBoxJump = 2,
    WeightedBurpeeBoxJump = 3,
    HighPullBurpee = 4,
    ManMakers = 5,
    OneArmBurpee = 6,
    SquatThrusts = 7,
    WeightedSquatThrusts = 8,
    SquatPlankPushUp = 9,
    WeightedSquatPlankPushUp = 10,
    StandingTRotationBalance = 11,
    WeightedStandingTRotationBalance = 12,
    BarbellBurpee = 13,
    BurpeeBoxJumpOverYesLiterallyJumpingOverTheBox = 15,
    BurpeeBoxJumpStepUpOver = 16,
    LateralBarbellBurpee = 17,
    TotalBodyBurpeeOverBar = 18,
    BurpeeBoxJumpOver = 19,
    BurpeeWheelchair = 20,
}

impl TotalBodyExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            TotalBodyExerciseName::Burpee => "burpee",
            TotalBodyExerciseName::WeightedBurpee => "weighted_burpee",
            TotalBodyExerciseName::BurpeeBoxJump => "burpee_box_jump",
            TotalBodyExerciseName::WeightedBurpeeBoxJump => "weighted_burpee_box_jump",
            TotalBodyExerciseName::HighPullBurpee => "high_pull_burpee",
            TotalBodyExerciseName::ManMakers => "man_makers",
            TotalBodyExerciseName::OneArmBurpee => "one_arm_burpee",
            TotalBodyExerciseName::SquatThrusts => "squat_thrusts",
            TotalBodyExerciseName::WeightedSquatThrusts => "weighted_squat_thrusts",
            TotalBodyExerciseName::SquatPlankPushUp => "squat_plank_push_up",
            TotalBodyExerciseName::WeightedSquatPlankPushUp => "weighted_squat_plank_push_up",
            TotalBodyExerciseName::StandingTRotationBalance => "standing_t_rotation_balance",
            TotalBodyExerciseName::WeightedStandingTRotationBalance => {
                "weighted_standing_t_rotation_balance"
            }
            TotalBodyExerciseName::BarbellBurpee => "barbell_burpee",
            TotalBodyExerciseName::BurpeeBoxJumpOverYesLiterallyJumpingOverTheBox => {
                "burpee_box_jump_over_yes_literally_jumping_over_the_box"
            }
            TotalBodyExerciseName::BurpeeBoxJumpStepUpOver => "burpee_box_jump_step_up_over",
            TotalBodyExerciseName::LateralBarbellBurpee => "lateral_barbell_burpee",
            TotalBodyExerciseName::TotalBodyBurpeeOverBar => "total_body_burpee_over_bar",
            TotalBodyExerciseName::BurpeeBoxJumpOver => "burpee_box_jump_over",
            TotalBodyExerciseName::BurpeeWheelchair => "burpee_wheelchair",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(TotalBodyExerciseName::Burpee),
            1 => Some(TotalBodyExerciseName::WeightedBurpee),
            2 => Some(TotalBodyExerciseName::BurpeeBoxJump),
            3 => Some(TotalBodyExerciseName::WeightedBurpeeBoxJump),
            4 => Some(TotalBodyExerciseName::HighPullBurpee),
            5 => Some(TotalBodyExerciseName::ManMakers),
            6 => Some(TotalBodyExerciseName::OneArmBurpee),
            7 => Some(TotalBodyExerciseName::SquatThrusts),
            8 => Some(TotalBodyExerciseName::WeightedSquatThrusts),
            9 => Some(TotalBodyExerciseName::SquatPlankPushUp),
            10 => Some(TotalBodyExerciseName::WeightedSquatPlankPushUp),
            11 => Some(TotalBodyExerciseName::StandingTRotationBalance),
            12 => Some(TotalBodyExerciseName::WeightedStandingTRotationBalance),
            13 => Some(TotalBodyExerciseName::BarbellBurpee),
            15 => Some(TotalBodyExerciseName::BurpeeBoxJumpOverYesLiterallyJumpingOverTheBox),
            16 => Some(TotalBodyExerciseName::BurpeeBoxJumpStepUpOver),
            17 => Some(TotalBodyExerciseName::LateralBarbellBurpee),
            18 => Some(TotalBodyExerciseName::TotalBodyBurpeeOverBar),
            19 => Some(TotalBodyExerciseName::BurpeeBoxJumpOver),
            20 => Some(TotalBodyExerciseName::BurpeeWheelchair),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "burpee" => Some(TotalBodyExerciseName::Burpee),
            "weighted_burpee" => Some(TotalBodyExerciseName::WeightedBurpee),
            "burpee_box_jump" => Some(TotalBodyExerciseName::BurpeeBoxJump),
            "weighted_burpee_box_jump" => Some(TotalBodyExerciseName::WeightedBurpeeBoxJump),
            "high_pull_burpee" => Some(TotalBodyExerciseName::HighPullBurpee),
            "man_makers" => Some(TotalBodyExerciseName::ManMakers),
            "one_arm_burpee" => Some(TotalBodyExerciseName::OneArmBurpee),
            "squat_thrusts" => Some(TotalBodyExerciseName::SquatThrusts),
            "weighted_squat_thrusts" => Some(TotalBodyExerciseName::WeightedSquatThrusts),
            "squat_plank_push_up" => Some(TotalBodyExerciseName::SquatPlankPushUp),
            "weighted_squat_plank_push_up" => Some(TotalBodyExerciseName::WeightedSquatPlankPushUp),
            "standing_t_rotation_balance" => Some(TotalBodyExerciseName::StandingTRotationBalance),
            "weighted_standing_t_rotation_balance" => {
                Some(TotalBodyExerciseName::WeightedStandingTRotationBalance)
            }
            "barbell_burpee" => Some(TotalBodyExerciseName::BarbellBurpee),
            "burpee_box_jump_over_yes_literally_jumping_over_the_box" => {
                Some(TotalBodyExerciseName::BurpeeBoxJumpOverYesLiterallyJumpingOverTheBox)
            }
            "burpee_box_jump_step_up_over" => Some(TotalBodyExerciseName::BurpeeBoxJumpStepUpOver),
            "lateral_barbell_burpee" => Some(TotalBodyExerciseName::LateralBarbellBurpee),
            "total_body_burpee_over_bar" => Some(TotalBodyExerciseName::TotalBodyBurpeeOverBar),
            "burpee_box_jump_over" => Some(TotalBodyExerciseName::BurpeeBoxJumpOver),
            "burpee_wheelchair" => Some(TotalBodyExerciseName::BurpeeWheelchair),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum MoveExerciseName {
    ArchAndCurl = 0,
    ArmCirclesWithBallBandAndWeight = 1,
    ArmStretch = 2,
    BackMassage = 3,
    BellyBreathing = 4,
    BridgeWithBall = 5,
    DiamondLegCrunch = 6,
    DiamondLegLift = 7,
    EightPointShoulderOpener = 8,
    FootRolling = 9,
    Footwork = 10,
    FootworkOnDisc = 11,
    ForwardFold = 12,
    FrogWithBand = 13,
    HalfRollUp = 14,
    HamstringCurl = 15,
    HamstringStretch = 16,
    HipStretch = 17,
    HugATreeWithBallBandAndWeight = 18,
    KneeCircles = 19,
    KneeFoldsOnDisc = 20,
    LateralFlexion = 21,
    LegStretchWithBand = 22,
    LegStretchWithLegCircles = 23,
    LowerLiftOnDisc = 24,
    LungeSquat = 25,
    LungesWithKneeLift = 26,
    MermaidStretch = 27,
    NeutralPelvicPosition = 28,
    PelvicClocksOnDisc = 29,
    PilatesPlieSquatsParallelTurnedOutFlatAndHeelsWithChair = 30,
    PiriformisStretch = 31,
    PlankKneeCrosses = 32,
    PlankKneePulls = 33,
    PlankUpDowns = 34,
    PrayerMudra = 35,
    PsoasLungeStretch = 36,
    RibcageBreathing = 37,
    RollDown = 38,
    RollUpWithWeightAndBand = 39,
    Saw = 40,
    ScapularStabilization = 41,
    ScissorsOnDisc = 42,
    SeatedHipStretchup = 43,
    SeatedTwist = 44,
    ShavingTheHeadWithBallBandAndWeight = 45,
    SpinalTwist = 46,
    SpinalTwistStretch = 47,
    SpineStretchForward = 48,
    SquatOpenArmTwistPose = 49,
    SquatsWithBall = 50,
    StandAndHang = 51,
    StandingSideStretch = 52,
    StandingSingleLegForwardBendWithItBandOpener = 53,
    StraightLegCrunchWithLegLift = 54,
    StraightLegCrunchWithLegLiftWithBall = 55,
    StraightLegCrunchWithLegsCrossed = 56,
    StraightLegCrunchWithLegsCrossedWithBall = 57,
    StraightLegDiagonalCrunch = 58,
    StraightLegDiagonalCrunchWithBall = 59,
    TailboneCurl = 60,
    ThroatLock = 61,
    TickTockSideRoll = 62,
    Twist = 63,
    VLegCrunches = 64,
    VSit = 65,
    ForwardFoldWheelchair = 66,
    ForwardFoldPlusWheelchair = 67,
    ArmCirclesLowForwardWheelchair = 68,
    ArmCirclesMidForwardWheelchair = 69,
    ArmCirclesHighForwardWheelchair = 70,
    ArmCirclesLowBackwardWheelchair = 71,
    ArmCirclesMidBackwardWheelchair = 72,
    ArmCirclesHighBackwardWheelchair = 73,
    CoreTwistsWheelchair = 74,
    ArmRaiseWheelchair = 75,
    ChestExpandWheelchair = 76,
    ArmExtendWheelchair = 77,
    ForwardBendWheelchair = 78,
    ToeTouchWheelchair = 79,
    ExtendedToeTouchWheelchair = 80,
    SeatedArmCircles = 81,
    TrunkRotations = 82,
    SeatedTrunkRotations = 83,
    ToeTouch = 84,
}

impl MoveExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            MoveExerciseName::ArchAndCurl => "arch_and_curl",
            MoveExerciseName::ArmCirclesWithBallBandAndWeight => {
                "arm_circles_with_ball_band_and_weight"
            }
            MoveExerciseName::ArmStretch => "arm_stretch",
            MoveExerciseName::BackMassage => "back_massage",
            MoveExerciseName::BellyBreathing => "belly_breathing",
            MoveExerciseName::BridgeWithBall => "bridge_with_ball",
            MoveExerciseName::DiamondLegCrunch => "diamond_leg_crunch",
            MoveExerciseName::DiamondLegLift => "diamond_leg_lift",
            MoveExerciseName::EightPointShoulderOpener => "eight_point_shoulder_opener",
            MoveExerciseName::FootRolling => "foot_rolling",
            MoveExerciseName::Footwork => "footwork",
            MoveExerciseName::FootworkOnDisc => "footwork_on_disc",
            MoveExerciseName::ForwardFold => "forward_fold",
            MoveExerciseName::FrogWithBand => "frog_with_band",
            MoveExerciseName::HalfRollUp => "half_roll_up",
            MoveExerciseName::HamstringCurl => "hamstring_curl",
            MoveExerciseName::HamstringStretch => "hamstring_stretch",
            MoveExerciseName::HipStretch => "hip_stretch",
            MoveExerciseName::HugATreeWithBallBandAndWeight => {
                "hug_a_tree_with_ball_band_and_weight"
            }
            MoveExerciseName::KneeCircles => "knee_circles",
            MoveExerciseName::KneeFoldsOnDisc => "knee_folds_on_disc",
            MoveExerciseName::LateralFlexion => "lateral_flexion",
            MoveExerciseName::LegStretchWithBand => "leg_stretch_with_band",
            MoveExerciseName::LegStretchWithLegCircles => "leg_stretch_with_leg_circles",
            MoveExerciseName::LowerLiftOnDisc => "lower_lift_on_disc",
            MoveExerciseName::LungeSquat => "lunge_squat",
            MoveExerciseName::LungesWithKneeLift => "lunges_with_knee_lift",
            MoveExerciseName::MermaidStretch => "mermaid_stretch",
            MoveExerciseName::NeutralPelvicPosition => "neutral_pelvic_position",
            MoveExerciseName::PelvicClocksOnDisc => "pelvic_clocks_on_disc",
            MoveExerciseName::PilatesPlieSquatsParallelTurnedOutFlatAndHeelsWithChair => {
                "pilates_plie_squats_parallel_turned_out_flat_and_heels_with_chair"
            }
            MoveExerciseName::PiriformisStretch => "piriformis_stretch",
            MoveExerciseName::PlankKneeCrosses => "plank_knee_crosses",
            MoveExerciseName::PlankKneePulls => "plank_knee_pulls",
            MoveExerciseName::PlankUpDowns => "plank_up_downs",
            MoveExerciseName::PrayerMudra => "prayer_mudra",
            MoveExerciseName::PsoasLungeStretch => "psoas_lunge_stretch",
            MoveExerciseName::RibcageBreathing => "ribcage_breathing",
            MoveExerciseName::RollDown => "roll_down",
            MoveExerciseName::RollUpWithWeightAndBand => "roll_up_with_weight_and_band",
            MoveExerciseName::Saw => "saw",
            MoveExerciseName::ScapularStabilization => "scapular_stabilization",
            MoveExerciseName::ScissorsOnDisc => "scissors_on_disc",
            MoveExerciseName::SeatedHipStretchup => "seated_hip_stretchup",
            MoveExerciseName::SeatedTwist => "seated_twist",
            MoveExerciseName::ShavingTheHeadWithBallBandAndWeight => {
                "shaving_the_head_with_ball_band_and_weight"
            }
            MoveExerciseName::SpinalTwist => "spinal_twist",
            MoveExerciseName::SpinalTwistStretch => "spinal_twist_stretch",
            MoveExerciseName::SpineStretchForward => "spine_stretch_forward",
            MoveExerciseName::SquatOpenArmTwistPose => "squat_open_arm_twist_pose",
            MoveExerciseName::SquatsWithBall => "squats_with_ball",
            MoveExerciseName::StandAndHang => "stand_and_hang",
            MoveExerciseName::StandingSideStretch => "standing_side_stretch",
            MoveExerciseName::StandingSingleLegForwardBendWithItBandOpener => {
                "standing_single_leg_forward_bend_with_it_band_opener"
            }
            MoveExerciseName::StraightLegCrunchWithLegLift => "straight_leg_crunch_with_leg_lift",
            MoveExerciseName::StraightLegCrunchWithLegLiftWithBall => {
                "straight_leg_crunch_with_leg_lift_with_ball"
            }
            MoveExerciseName::StraightLegCrunchWithLegsCrossed => {
                "straight_leg_crunch_with_legs_crossed"
            }
            MoveExerciseName::StraightLegCrunchWithLegsCrossedWithBall => {
                "straight_leg_crunch_with_legs_crossed_with_ball"
            }
            MoveExerciseName::StraightLegDiagonalCrunch => "straight_leg_diagonal_crunch",
            MoveExerciseName::StraightLegDiagonalCrunchWithBall => {
                "straight_leg_diagonal_crunch_with_ball"
            }
            MoveExerciseName::TailboneCurl => "tailbone_curl",
            MoveExerciseName::ThroatLock => "throat_lock",
            MoveExerciseName::TickTockSideRoll => "tick_tock_side_roll",
            MoveExerciseName::Twist => "twist",
            MoveExerciseName::VLegCrunches => "v_leg_crunches",
            MoveExerciseName::VSit => "v_sit",
            MoveExerciseName::ForwardFoldWheelchair => "forward_fold_wheelchair",
            MoveExerciseName::ForwardFoldPlusWheelchair => "forward_fold_plus_wheelchair",
            MoveExerciseName::ArmCirclesLowForwardWheelchair => {
                "arm_circles_low_forward_wheelchair"
            }
            MoveExerciseName::ArmCirclesMidForwardWheelchair => {
                "arm_circles_mid_forward_wheelchair"
            }
            MoveExerciseName::ArmCirclesHighForwardWheelchair => {
                "arm_circles_high_forward_wheelchair"
            }
            MoveExerciseName::ArmCirclesLowBackwardWheelchair => {
                "arm_circles_low_backward_wheelchair"
            }
            MoveExerciseName::ArmCirclesMidBackwardWheelchair => {
                "arm_circles_mid_backward_wheelchair"
            }
            MoveExerciseName::ArmCirclesHighBackwardWheelchair => {
                "arm_circles_high_backward_wheelchair"
            }
            MoveExerciseName::CoreTwistsWheelchair => "core_twists_wheelchair",
            MoveExerciseName::ArmRaiseWheelchair => "arm_raise_wheelchair",
            MoveExerciseName::ChestExpandWheelchair => "chest_expand_wheelchair",
            MoveExerciseName::ArmExtendWheelchair => "arm_extend_wheelchair",
            MoveExerciseName::ForwardBendWheelchair => "forward_bend_wheelchair",
            MoveExerciseName::ToeTouchWheelchair => "toe_touch_wheelchair",
            MoveExerciseName::ExtendedToeTouchWheelchair => "extended_toe_touch_wheelchair",
            MoveExerciseName::SeatedArmCircles => "seated_arm_circles",
            MoveExerciseName::TrunkRotations => "trunk_rotations",
            MoveExerciseName::SeatedTrunkRotations => "seated_trunk_rotations",
            MoveExerciseName::ToeTouch => "toe_touch",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(MoveExerciseName::ArchAndCurl),
            1 => Some(MoveExerciseName::ArmCirclesWithBallBandAndWeight),
            2 => Some(MoveExerciseName::ArmStretch),
            3 => Some(MoveExerciseName::BackMassage),
            4 => Some(MoveExerciseName::BellyBreathing),
            5 => Some(MoveExerciseName::BridgeWithBall),
            6 => Some(MoveExerciseName::DiamondLegCrunch),
            7 => Some(MoveExerciseName::DiamondLegLift),
            8 => Some(MoveExerciseName::EightPointShoulderOpener),
            9 => Some(MoveExerciseName::FootRolling),
            10 => Some(MoveExerciseName::Footwork),
            11 => Some(MoveExerciseName::FootworkOnDisc),
            12 => Some(MoveExerciseName::ForwardFold),
            13 => Some(MoveExerciseName::FrogWithBand),
            14 => Some(MoveExerciseName::HalfRollUp),
            15 => Some(MoveExerciseName::HamstringCurl),
            16 => Some(MoveExerciseName::HamstringStretch),
            17 => Some(MoveExerciseName::HipStretch),
            18 => Some(MoveExerciseName::HugATreeWithBallBandAndWeight),
            19 => Some(MoveExerciseName::KneeCircles),
            20 => Some(MoveExerciseName::KneeFoldsOnDisc),
            21 => Some(MoveExerciseName::LateralFlexion),
            22 => Some(MoveExerciseName::LegStretchWithBand),
            23 => Some(MoveExerciseName::LegStretchWithLegCircles),
            24 => Some(MoveExerciseName::LowerLiftOnDisc),
            25 => Some(MoveExerciseName::LungeSquat),
            26 => Some(MoveExerciseName::LungesWithKneeLift),
            27 => Some(MoveExerciseName::MermaidStretch),
            28 => Some(MoveExerciseName::NeutralPelvicPosition),
            29 => Some(MoveExerciseName::PelvicClocksOnDisc),
            30 => Some(MoveExerciseName::PilatesPlieSquatsParallelTurnedOutFlatAndHeelsWithChair),
            31 => Some(MoveExerciseName::PiriformisStretch),
            32 => Some(MoveExerciseName::PlankKneeCrosses),
            33 => Some(MoveExerciseName::PlankKneePulls),
            34 => Some(MoveExerciseName::PlankUpDowns),
            35 => Some(MoveExerciseName::PrayerMudra),
            36 => Some(MoveExerciseName::PsoasLungeStretch),
            37 => Some(MoveExerciseName::RibcageBreathing),
            38 => Some(MoveExerciseName::RollDown),
            39 => Some(MoveExerciseName::RollUpWithWeightAndBand),
            40 => Some(MoveExerciseName::Saw),
            41 => Some(MoveExerciseName::ScapularStabilization),
            42 => Some(MoveExerciseName::ScissorsOnDisc),
            43 => Some(MoveExerciseName::SeatedHipStretchup),
            44 => Some(MoveExerciseName::SeatedTwist),
            45 => Some(MoveExerciseName::ShavingTheHeadWithBallBandAndWeight),
            46 => Some(MoveExerciseName::SpinalTwist),
            47 => Some(MoveExerciseName::SpinalTwistStretch),
            48 => Some(MoveExerciseName::SpineStretchForward),
            49 => Some(MoveExerciseName::SquatOpenArmTwistPose),
            50 => Some(MoveExerciseName::SquatsWithBall),
            51 => Some(MoveExerciseName::StandAndHang),
            52 => Some(MoveExerciseName::StandingSideStretch),
            53 => Some(MoveExerciseName::StandingSingleLegForwardBendWithItBandOpener),
            54 => Some(MoveExerciseName::StraightLegCrunchWithLegLift),
            55 => Some(MoveExerciseName::StraightLegCrunchWithLegLiftWithBall),
            56 => Some(MoveExerciseName::StraightLegCrunchWithLegsCrossed),
            57 => Some(MoveExerciseName::StraightLegCrunchWithLegsCrossedWithBall),
            58 => Some(MoveExerciseName::StraightLegDiagonalCrunch),
            59 => Some(MoveExerciseName::StraightLegDiagonalCrunchWithBall),
            60 => Some(MoveExerciseName::TailboneCurl),
            61 => Some(MoveExerciseName::ThroatLock),
            62 => Some(MoveExerciseName::TickTockSideRoll),
            63 => Some(MoveExerciseName::Twist),
            64 => Some(MoveExerciseName::VLegCrunches),
            65 => Some(MoveExerciseName::VSit),
            66 => Some(MoveExerciseName::ForwardFoldWheelchair),
            67 => Some(MoveExerciseName::ForwardFoldPlusWheelchair),
            68 => Some(MoveExerciseName::ArmCirclesLowForwardWheelchair),
            69 => Some(MoveExerciseName::ArmCirclesMidForwardWheelchair),
            70 => Some(MoveExerciseName::ArmCirclesHighForwardWheelchair),
            71 => Some(MoveExerciseName::ArmCirclesLowBackwardWheelchair),
            72 => Some(MoveExerciseName::ArmCirclesMidBackwardWheelchair),
            73 => Some(MoveExerciseName::ArmCirclesHighBackwardWheelchair),
            74 => Some(MoveExerciseName::CoreTwistsWheelchair),
            75 => Some(MoveExerciseName::ArmRaiseWheelchair),
            76 => Some(MoveExerciseName::ChestExpandWheelchair),
            77 => Some(MoveExerciseName::ArmExtendWheelchair),
            78 => Some(MoveExerciseName::ForwardBendWheelchair),
            79 => Some(MoveExerciseName::ToeTouchWheelchair),
            80 => Some(MoveExerciseName::ExtendedToeTouchWheelchair),
            81 => Some(MoveExerciseName::SeatedArmCircles),
            82 => Some(MoveExerciseName::TrunkRotations),
            83 => Some(MoveExerciseName::SeatedTrunkRotations),
            84 => Some(MoveExerciseName::ToeTouch),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "arch_and_curl" => Some(MoveExerciseName::ArchAndCurl),
            "arm_circles_with_ball_band_and_weight" => {
                Some(MoveExerciseName::ArmCirclesWithBallBandAndWeight)
            }
            "arm_stretch" => Some(MoveExerciseName::ArmStretch),
            "back_massage" => Some(MoveExerciseName::BackMassage),
            "belly_breathing" => Some(MoveExerciseName::BellyBreathing),
            "bridge_with_ball" => Some(MoveExerciseName::BridgeWithBall),
            "diamond_leg_crunch" => Some(MoveExerciseName::DiamondLegCrunch),
            "diamond_leg_lift" => Some(MoveExerciseName::DiamondLegLift),
            "eight_point_shoulder_opener" => Some(MoveExerciseName::EightPointShoulderOpener),
            "foot_rolling" => Some(MoveExerciseName::FootRolling),
            "footwork" => Some(MoveExerciseName::Footwork),
            "footwork_on_disc" => Some(MoveExerciseName::FootworkOnDisc),
            "forward_fold" => Some(MoveExerciseName::ForwardFold),
            "frog_with_band" => Some(MoveExerciseName::FrogWithBand),
            "half_roll_up" => Some(MoveExerciseName::HalfRollUp),
            "hamstring_curl" => Some(MoveExerciseName::HamstringCurl),
            "hamstring_stretch" => Some(MoveExerciseName::HamstringStretch),
            "hip_stretch" => Some(MoveExerciseName::HipStretch),
            "hug_a_tree_with_ball_band_and_weight" => {
                Some(MoveExerciseName::HugATreeWithBallBandAndWeight)
            }
            "knee_circles" => Some(MoveExerciseName::KneeCircles),
            "knee_folds_on_disc" => Some(MoveExerciseName::KneeFoldsOnDisc),
            "lateral_flexion" => Some(MoveExerciseName::LateralFlexion),
            "leg_stretch_with_band" => Some(MoveExerciseName::LegStretchWithBand),
            "leg_stretch_with_leg_circles" => Some(MoveExerciseName::LegStretchWithLegCircles),
            "lower_lift_on_disc" => Some(MoveExerciseName::LowerLiftOnDisc),
            "lunge_squat" => Some(MoveExerciseName::LungeSquat),
            "lunges_with_knee_lift" => Some(MoveExerciseName::LungesWithKneeLift),
            "mermaid_stretch" => Some(MoveExerciseName::MermaidStretch),
            "neutral_pelvic_position" => Some(MoveExerciseName::NeutralPelvicPosition),
            "pelvic_clocks_on_disc" => Some(MoveExerciseName::PelvicClocksOnDisc),
            "pilates_plie_squats_parallel_turned_out_flat_and_heels_with_chair" => {
                Some(MoveExerciseName::PilatesPlieSquatsParallelTurnedOutFlatAndHeelsWithChair)
            }
            "piriformis_stretch" => Some(MoveExerciseName::PiriformisStretch),
            "plank_knee_crosses" => Some(MoveExerciseName::PlankKneeCrosses),
            "plank_knee_pulls" => Some(MoveExerciseName::PlankKneePulls),
            "plank_up_downs" => Some(MoveExerciseName::PlankUpDowns),
            "prayer_mudra" => Some(MoveExerciseName::PrayerMudra),
            "psoas_lunge_stretch" => Some(MoveExerciseName::PsoasLungeStretch),
            "ribcage_breathing" => Some(MoveExerciseName::RibcageBreathing),
            "roll_down" => Some(MoveExerciseName::RollDown),
            "roll_up_with_weight_and_band" => Some(MoveExerciseName::RollUpWithWeightAndBand),
            "saw" => Some(MoveExerciseName::Saw),
            "scapular_stabilization" => Some(MoveExerciseName::ScapularStabilization),
            "scissors_on_disc" => Some(MoveExerciseName::ScissorsOnDisc),
            "seated_hip_stretchup" => Some(MoveExerciseName::SeatedHipStretchup),
            "seated_twist" => Some(MoveExerciseName::SeatedTwist),
            "shaving_the_head_with_ball_band_and_weight" => {
                Some(MoveExerciseName::ShavingTheHeadWithBallBandAndWeight)
            }
            "spinal_twist" => Some(MoveExerciseName::SpinalTwist),
            "spinal_twist_stretch" => Some(MoveExerciseName::SpinalTwistStretch),
            "spine_stretch_forward" => Some(MoveExerciseName::SpineStretchForward),
            "squat_open_arm_twist_pose" => Some(MoveExerciseName::SquatOpenArmTwistPose),
            "squats_with_ball" => Some(MoveExerciseName::SquatsWithBall),
            "stand_and_hang" => Some(MoveExerciseName::StandAndHang),
            "standing_side_stretch" => Some(MoveExerciseName::StandingSideStretch),
            "standing_single_leg_forward_bend_with_it_band_opener" => {
                Some(MoveExerciseName::StandingSingleLegForwardBendWithItBandOpener)
            }
            "straight_leg_crunch_with_leg_lift" => {
                Some(MoveExerciseName::StraightLegCrunchWithLegLift)
            }
            "straight_leg_crunch_with_leg_lift_with_ball" => {
                Some(MoveExerciseName::StraightLegCrunchWithLegLiftWithBall)
            }
            "straight_leg_crunch_with_legs_crossed" => {
                Some(MoveExerciseName::StraightLegCrunchWithLegsCrossed)
            }
            "straight_leg_crunch_with_legs_crossed_with_ball" => {
                Some(MoveExerciseName::StraightLegCrunchWithLegsCrossedWithBall)
            }
            "straight_leg_diagonal_crunch" => Some(MoveExerciseName::StraightLegDiagonalCrunch),
            "straight_leg_diagonal_crunch_with_ball" => {
                Some(MoveExerciseName::StraightLegDiagonalCrunchWithBall)
            }
            "tailbone_curl" => Some(MoveExerciseName::TailboneCurl),
            "throat_lock" => Some(MoveExerciseName::ThroatLock),
            "tick_tock_side_roll" => Some(MoveExerciseName::TickTockSideRoll),
            "twist" => Some(MoveExerciseName::Twist),
            "v_leg_crunches" => Some(MoveExerciseName::VLegCrunches),
            "v_sit" => Some(MoveExerciseName::VSit),
            "forward_fold_wheelchair" => Some(MoveExerciseName::ForwardFoldWheelchair),
            "forward_fold_plus_wheelchair" => Some(MoveExerciseName::ForwardFoldPlusWheelchair),
            "arm_circles_low_forward_wheelchair" => {
                Some(MoveExerciseName::ArmCirclesLowForwardWheelchair)
            }
            "arm_circles_mid_forward_wheelchair" => {
                Some(MoveExerciseName::ArmCirclesMidForwardWheelchair)
            }
            "arm_circles_high_forward_wheelchair" => {
                Some(MoveExerciseName::ArmCirclesHighForwardWheelchair)
            }
            "arm_circles_low_backward_wheelchair" => {
                Some(MoveExerciseName::ArmCirclesLowBackwardWheelchair)
            }
            "arm_circles_mid_backward_wheelchair" => {
                Some(MoveExerciseName::ArmCirclesMidBackwardWheelchair)
            }
            "arm_circles_high_backward_wheelchair" => {
                Some(MoveExerciseName::ArmCirclesHighBackwardWheelchair)
            }
            "core_twists_wheelchair" => Some(MoveExerciseName::CoreTwistsWheelchair),
            "arm_raise_wheelchair" => Some(MoveExerciseName::ArmRaiseWheelchair),
            "chest_expand_wheelchair" => Some(MoveExerciseName::ChestExpandWheelchair),
            "arm_extend_wheelchair" => Some(MoveExerciseName::ArmExtendWheelchair),
            "forward_bend_wheelchair" => Some(MoveExerciseName::ForwardBendWheelchair),
            "toe_touch_wheelchair" => Some(MoveExerciseName::ToeTouchWheelchair),
            "extended_toe_touch_wheelchair" => Some(MoveExerciseName::ExtendedToeTouchWheelchair),
            "seated_arm_circles" => Some(MoveExerciseName::SeatedArmCircles),
            "trunk_rotations" => Some(MoveExerciseName::TrunkRotations),
            "seated_trunk_rotations" => Some(MoveExerciseName::SeatedTrunkRotations),
            "toe_touch" => Some(MoveExerciseName::ToeTouch),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum PoseExerciseName {
    AllFours = 0,
    AnkleToKnee = 1,
    BabyCobra = 2,
    Boat = 3,
    BoundAngle = 4,
    BoundSeatedSingleLegForwardBend = 5,
    Bow = 6,
    BowedHalfMoon = 7,
    Bridge = 8,
    Cat = 9,
    Chair = 10,
    Childs = 11,
    Corpse = 12,
    CowFace = 13,
    Cow = 14,
    DevotionalWarrior = 15,
    DolphinPlank = 16,
    Dolphin = 17,
    DownDogKneeToNose = 18,
    DownDogSplit = 19,
    DownDogSplitOpenHipBentKnee = 20,
    DownwardFacingDog = 21,
    Eagle = 22,
    EasySeated = 23,
    ExtendedPuppy = 24,
    ExtendedSideAngle = 25,
    Fish = 26,
    FourLimbedStaff = 27,
    FullSplit = 28,
    Gate = 29,
    HalfChairHalfAnkleToKnee = 30,
    HalfMoon = 31,
    HeadToKnee = 32,
    Heron = 33,
    Heros = 34,
    HighLunge = 35,
    KneesChestChin = 36,
    Lizard = 37,
    Locust = 38,
    LowLunge = 39,
    LowLungeTwist = 40,
    LowLungeWithKneeDown = 41,
    Mermaid = 42,
    Mountain = 43,
    OneLeggedDownwardFacingPoseOpenHipBentKnee = 44,
    OneLeggedPigeon = 45,
    PeacefulWarrior = 46,
    Plank = 47,
    Plow = 48,
    ReclinedHandToFoot = 49,
    RevolvedHalfMoon = 50,
    RevolvedHeadToKnee = 51,
    RevolvedTriangle = 52,
    RunnersLunge = 53,
    SeatedEasySideBend = 54,
    SeatedEasyTwist = 55,
    SeatedLongLegForwardBend = 56,
    SeatedWideLegForwardBend = 57,
    ShoulderStand = 58,
    SideBoat = 59,
    SidePlank = 60,
    Sphinx = 61,
    SquatOpenArmTwist = 62,
    SquatPalmPress = 63,
    Staff = 64,
    StandingArmsUp = 65,
    StandingForwardBendHalfwayUp = 66,
    StandingForwardBend = 67,
    StandingSideOpener = 68,
    StandingSingleLegForwardBend = 69,
    StandingSplit = 70,
    StandingWideLegForwardBend = 71,
    StandingWideLegForwardBendWithTwist = 72,
    SupineSpinalTwist = 73,
    TableTop = 74,
    ThreadTheNeedle = 75,
    Thunderbolt = 76,
    ThunderboltPoseBothSidesArmStretch = 77,
    Tree = 78,
    Triangle = 79,
    UpDog = 80,
    UpwardFacingPlank = 81,
    WarriorOne = 82,
    WarriorThree = 83,
    WarriorTwo = 84,
    Wheel = 85,
    WideSideLunge = 86,
    DeepBreathingWheelchair = 87,
    DeepBreathingLowWheelchair = 88,
    DeepBreathingMidWheelchair = 89,
    DeepBreathingHighWheelchair = 90,
    PrayerWheelchair = 91,
    OverheadPrayerWheelchair = 92,
    CactusWheelchair = 93,
    BreathingPunchesWheelchair = 94,
    BreathingPunchesExtendedWheelchair = 95,
    BreathingPunchesOverheadWheelchair = 96,
    BreathingPunchesOverheadAndDownWheelchair = 97,
    BreathingPunchesSideWheelchair = 98,
    BreathingPunchesExtendedSideWheelchair = 99,
    BreathingPunchesOverheadSideWheelchair = 100,
    BreathingPunchesOverheadAndDownSideWheelchair = 101,
    LeftHandBackWheelchair = 102,
    TriangleWheelchair = 103,
    ThreadTheNeedleWheelchair = 104,
    NeckFlexionAndExtensionWheelchair = 105,
    NeckLateralFlexionWheelchair = 106,
    SpineFlexionAndExtensionWheelchair = 107,
    SpineRotationWheelchair = 108,
    SpineLateralFlexionWheelchair = 109,
    AlternativeSkiingWheelchair = 110,
    ReachForwardWheelchair = 111,
    WarriorWheelchair = 112,
    ReverseWarriorWheelchair = 113,
    DownwardFacingDogToCobra = 114,
    SeatedCatCow = 115,
}

impl PoseExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            PoseExerciseName::AllFours => "all_fours",
            PoseExerciseName::AnkleToKnee => "ankle_to_knee",
            PoseExerciseName::BabyCobra => "baby_cobra",
            PoseExerciseName::Boat => "boat",
            PoseExerciseName::BoundAngle => "bound_angle",
            PoseExerciseName::BoundSeatedSingleLegForwardBend => {
                "bound_seated_single_leg_forward_bend"
            }
            PoseExerciseName::Bow => "bow",
            PoseExerciseName::BowedHalfMoon => "bowed_half_moon",
            PoseExerciseName::Bridge => "bridge",
            PoseExerciseName::Cat => "cat",
            PoseExerciseName::Chair => "chair",
            PoseExerciseName::Childs => "childs",
            PoseExerciseName::Corpse => "corpse",
            PoseExerciseName::CowFace => "cow_face",
            PoseExerciseName::Cow => "cow",
            PoseExerciseName::DevotionalWarrior => "devotional_warrior",
            PoseExerciseName::DolphinPlank => "dolphin_plank",
            PoseExerciseName::Dolphin => "dolphin",
            PoseExerciseName::DownDogKneeToNose => "down_dog_knee_to_nose",
            PoseExerciseName::DownDogSplit => "down_dog_split",
            PoseExerciseName::DownDogSplitOpenHipBentKnee => "down_dog_split_open_hip_bent_knee",
            PoseExerciseName::DownwardFacingDog => "downward_facing_dog",
            PoseExerciseName::Eagle => "eagle",
            PoseExerciseName::EasySeated => "easy_seated",
            PoseExerciseName::ExtendedPuppy => "extended_puppy",
            PoseExerciseName::ExtendedSideAngle => "extended_side_angle",
            PoseExerciseName::Fish => "fish",
            PoseExerciseName::FourLimbedStaff => "four_limbed_staff",
            PoseExerciseName::FullSplit => "full_split",
            PoseExerciseName::Gate => "gate",
            PoseExerciseName::HalfChairHalfAnkleToKnee => "half_chair_half_ankle_to_knee",
            PoseExerciseName::HalfMoon => "half_moon",
            PoseExerciseName::HeadToKnee => "head_to_knee",
            PoseExerciseName::Heron => "heron",
            PoseExerciseName::Heros => "heros",
            PoseExerciseName::HighLunge => "high_lunge",
            PoseExerciseName::KneesChestChin => "knees_chest_chin",
            PoseExerciseName::Lizard => "lizard",
            PoseExerciseName::Locust => "locust",
            PoseExerciseName::LowLunge => "low_lunge",
            PoseExerciseName::LowLungeTwist => "low_lunge_twist",
            PoseExerciseName::LowLungeWithKneeDown => "low_lunge_with_knee_down",
            PoseExerciseName::Mermaid => "mermaid",
            PoseExerciseName::Mountain => "mountain",
            PoseExerciseName::OneLeggedDownwardFacingPoseOpenHipBentKnee => {
                "one_legged_downward_facing_pose_open_hip_bent_knee"
            }
            PoseExerciseName::OneLeggedPigeon => "one_legged_pigeon",
            PoseExerciseName::PeacefulWarrior => "peaceful_warrior",
            PoseExerciseName::Plank => "plank",
            PoseExerciseName::Plow => "plow",
            PoseExerciseName::ReclinedHandToFoot => "reclined_hand_to_foot",
            PoseExerciseName::RevolvedHalfMoon => "revolved_half_moon",
            PoseExerciseName::RevolvedHeadToKnee => "revolved_head_to_knee",
            PoseExerciseName::RevolvedTriangle => "revolved_triangle",
            PoseExerciseName::RunnersLunge => "runners_lunge",
            PoseExerciseName::SeatedEasySideBend => "seated_easy_side_bend",
            PoseExerciseName::SeatedEasyTwist => "seated_easy_twist",
            PoseExerciseName::SeatedLongLegForwardBend => "seated_long_leg_forward_bend",
            PoseExerciseName::SeatedWideLegForwardBend => "seated_wide_leg_forward_bend",
            PoseExerciseName::ShoulderStand => "shoulder_stand",
            PoseExerciseName::SideBoat => "side_boat",
            PoseExerciseName::SidePlank => "side_plank",
            PoseExerciseName::Sphinx => "sphinx",
            PoseExerciseName::SquatOpenArmTwist => "squat_open_arm_twist",
            PoseExerciseName::SquatPalmPress => "squat_palm_press",
            PoseExerciseName::Staff => "staff",
            PoseExerciseName::StandingArmsUp => "standing_arms_up",
            PoseExerciseName::StandingForwardBendHalfwayUp => "standing_forward_bend_halfway_up",
            PoseExerciseName::StandingForwardBend => "standing_forward_bend",
            PoseExerciseName::StandingSideOpener => "standing_side_opener",
            PoseExerciseName::StandingSingleLegForwardBend => "standing_single_leg_forward_bend",
            PoseExerciseName::StandingSplit => "standing_split",
            PoseExerciseName::StandingWideLegForwardBend => "standing_wide_leg_forward_bend",
            PoseExerciseName::StandingWideLegForwardBendWithTwist => {
                "standing_wide_leg_forward_bend_with_twist"
            }
            PoseExerciseName::SupineSpinalTwist => "supine_spinal_twist",
            PoseExerciseName::TableTop => "table_top",
            PoseExerciseName::ThreadTheNeedle => "thread_the_needle",
            PoseExerciseName::Thunderbolt => "thunderbolt",
            PoseExerciseName::ThunderboltPoseBothSidesArmStretch => {
                "thunderbolt_pose_both_sides_arm_stretch"
            }
            PoseExerciseName::Tree => "tree",
            PoseExerciseName::Triangle => "triangle",
            PoseExerciseName::UpDog => "up_dog",
            PoseExerciseName::UpwardFacingPlank => "upward_facing_plank",
            PoseExerciseName::WarriorOne => "warrior_one",
            PoseExerciseName::WarriorThree => "warrior_three",
            PoseExerciseName::WarriorTwo => "warrior_two",
            PoseExerciseName::Wheel => "wheel",
            PoseExerciseName::WideSideLunge => "wide_side_lunge",
            PoseExerciseName::DeepBreathingWheelchair => "deep_breathing_wheelchair",
            PoseExerciseName::DeepBreathingLowWheelchair => "deep_breathing_low_wheelchair",
            PoseExerciseName::DeepBreathingMidWheelchair => "deep_breathing_mid_wheelchair",
            PoseExerciseName::DeepBreathingHighWheelchair => "deep_breathing_high_wheelchair",
            PoseExerciseName::PrayerWheelchair => "prayer_wheelchair",
            PoseExerciseName::OverheadPrayerWheelchair => "overhead_prayer_wheelchair",
            PoseExerciseName::CactusWheelchair => "cactus_wheelchair",
            PoseExerciseName::BreathingPunchesWheelchair => "breathing_punches_wheelchair",
            PoseExerciseName::BreathingPunchesExtendedWheelchair => {
                "breathing_punches_extended_wheelchair"
            }
            PoseExerciseName::BreathingPunchesOverheadWheelchair => {
                "breathing_punches_overhead_wheelchair"
            }
            PoseExerciseName::BreathingPunchesOverheadAndDownWheelchair => {
                "breathing_punches_overhead_and_down_wheelchair"
            }
            PoseExerciseName::BreathingPunchesSideWheelchair => "breathing_punches_side_wheelchair",
            PoseExerciseName::BreathingPunchesExtendedSideWheelchair => {
                "breathing_punches_extended_side_wheelchair"
            }
            PoseExerciseName::BreathingPunchesOverheadSideWheelchair => {
                "breathing_punches_overhead_side_wheelchair"
            }
            PoseExerciseName::BreathingPunchesOverheadAndDownSideWheelchair => {
                "breathing_punches_overhead_and_down_side_wheelchair"
            }
            PoseExerciseName::LeftHandBackWheelchair => "left_hand_back_wheelchair",
            PoseExerciseName::TriangleWheelchair => "triangle_wheelchair",
            PoseExerciseName::ThreadTheNeedleWheelchair => "thread_the_needle_wheelchair",
            PoseExerciseName::NeckFlexionAndExtensionWheelchair => {
                "neck_flexion_and_extension_wheelchair"
            }
            PoseExerciseName::NeckLateralFlexionWheelchair => "neck_lateral_flexion_wheelchair",
            PoseExerciseName::SpineFlexionAndExtensionWheelchair => {
                "spine_flexion_and_extension_wheelchair"
            }
            PoseExerciseName::SpineRotationWheelchair => "spine_rotation_wheelchair",
            PoseExerciseName::SpineLateralFlexionWheelchair => "spine_lateral_flexion_wheelchair",
            PoseExerciseName::AlternativeSkiingWheelchair => "alternative_skiing_wheelchair",
            PoseExerciseName::ReachForwardWheelchair => "reach_forward_wheelchair",
            PoseExerciseName::WarriorWheelchair => "warrior_wheelchair",
            PoseExerciseName::ReverseWarriorWheelchair => "reverse_warrior_wheelchair",
            PoseExerciseName::DownwardFacingDogToCobra => "downward_facing_dog_to_cobra",
            PoseExerciseName::SeatedCatCow => "seated_cat_cow",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(PoseExerciseName::AllFours),
            1 => Some(PoseExerciseName::AnkleToKnee),
            2 => Some(PoseExerciseName::BabyCobra),
            3 => Some(PoseExerciseName::Boat),
            4 => Some(PoseExerciseName::BoundAngle),
            5 => Some(PoseExerciseName::BoundSeatedSingleLegForwardBend),
            6 => Some(PoseExerciseName::Bow),
            7 => Some(PoseExerciseName::BowedHalfMoon),
            8 => Some(PoseExerciseName::Bridge),
            9 => Some(PoseExerciseName::Cat),
            10 => Some(PoseExerciseName::Chair),
            11 => Some(PoseExerciseName::Childs),
            12 => Some(PoseExerciseName::Corpse),
            13 => Some(PoseExerciseName::CowFace),
            14 => Some(PoseExerciseName::Cow),
            15 => Some(PoseExerciseName::DevotionalWarrior),
            16 => Some(PoseExerciseName::DolphinPlank),
            17 => Some(PoseExerciseName::Dolphin),
            18 => Some(PoseExerciseName::DownDogKneeToNose),
            19 => Some(PoseExerciseName::DownDogSplit),
            20 => Some(PoseExerciseName::DownDogSplitOpenHipBentKnee),
            21 => Some(PoseExerciseName::DownwardFacingDog),
            22 => Some(PoseExerciseName::Eagle),
            23 => Some(PoseExerciseName::EasySeated),
            24 => Some(PoseExerciseName::ExtendedPuppy),
            25 => Some(PoseExerciseName::ExtendedSideAngle),
            26 => Some(PoseExerciseName::Fish),
            27 => Some(PoseExerciseName::FourLimbedStaff),
            28 => Some(PoseExerciseName::FullSplit),
            29 => Some(PoseExerciseName::Gate),
            30 => Some(PoseExerciseName::HalfChairHalfAnkleToKnee),
            31 => Some(PoseExerciseName::HalfMoon),
            32 => Some(PoseExerciseName::HeadToKnee),
            33 => Some(PoseExerciseName::Heron),
            34 => Some(PoseExerciseName::Heros),
            35 => Some(PoseExerciseName::HighLunge),
            36 => Some(PoseExerciseName::KneesChestChin),
            37 => Some(PoseExerciseName::Lizard),
            38 => Some(PoseExerciseName::Locust),
            39 => Some(PoseExerciseName::LowLunge),
            40 => Some(PoseExerciseName::LowLungeTwist),
            41 => Some(PoseExerciseName::LowLungeWithKneeDown),
            42 => Some(PoseExerciseName::Mermaid),
            43 => Some(PoseExerciseName::Mountain),
            44 => Some(PoseExerciseName::OneLeggedDownwardFacingPoseOpenHipBentKnee),
            45 => Some(PoseExerciseName::OneLeggedPigeon),
            46 => Some(PoseExerciseName::PeacefulWarrior),
            47 => Some(PoseExerciseName::Plank),
            48 => Some(PoseExerciseName::Plow),
            49 => Some(PoseExerciseName::ReclinedHandToFoot),
            50 => Some(PoseExerciseName::RevolvedHalfMoon),
            51 => Some(PoseExerciseName::RevolvedHeadToKnee),
            52 => Some(PoseExerciseName::RevolvedTriangle),
            53 => Some(PoseExerciseName::RunnersLunge),
            54 => Some(PoseExerciseName::SeatedEasySideBend),
            55 => Some(PoseExerciseName::SeatedEasyTwist),
            56 => Some(PoseExerciseName::SeatedLongLegForwardBend),
            57 => Some(PoseExerciseName::SeatedWideLegForwardBend),
            58 => Some(PoseExerciseName::ShoulderStand),
            59 => Some(PoseExerciseName::SideBoat),
            60 => Some(PoseExerciseName::SidePlank),
            61 => Some(PoseExerciseName::Sphinx),
            62 => Some(PoseExerciseName::SquatOpenArmTwist),
            63 => Some(PoseExerciseName::SquatPalmPress),
            64 => Some(PoseExerciseName::Staff),
            65 => Some(PoseExerciseName::StandingArmsUp),
            66 => Some(PoseExerciseName::StandingForwardBendHalfwayUp),
            67 => Some(PoseExerciseName::StandingForwardBend),
            68 => Some(PoseExerciseName::StandingSideOpener),
            69 => Some(PoseExerciseName::StandingSingleLegForwardBend),
            70 => Some(PoseExerciseName::StandingSplit),
            71 => Some(PoseExerciseName::StandingWideLegForwardBend),
            72 => Some(PoseExerciseName::StandingWideLegForwardBendWithTwist),
            73 => Some(PoseExerciseName::SupineSpinalTwist),
            74 => Some(PoseExerciseName::TableTop),
            75 => Some(PoseExerciseName::ThreadTheNeedle),
            76 => Some(PoseExerciseName::Thunderbolt),
            77 => Some(PoseExerciseName::ThunderboltPoseBothSidesArmStretch),
            78 => Some(PoseExerciseName::Tree),
            79 => Some(PoseExerciseName::Triangle),
            80 => Some(PoseExerciseName::UpDog),
            81 => Some(PoseExerciseName::UpwardFacingPlank),
            82 => Some(PoseExerciseName::WarriorOne),
            83 => Some(PoseExerciseName::WarriorThree),
            84 => Some(PoseExerciseName::WarriorTwo),
            85 => Some(PoseExerciseName::Wheel),
            86 => Some(PoseExerciseName::WideSideLunge),
            87 => Some(PoseExerciseName::DeepBreathingWheelchair),
            88 => Some(PoseExerciseName::DeepBreathingLowWheelchair),
            89 => Some(PoseExerciseName::DeepBreathingMidWheelchair),
            90 => Some(PoseExerciseName::DeepBreathingHighWheelchair),
            91 => Some(PoseExerciseName::PrayerWheelchair),
            92 => Some(PoseExerciseName::OverheadPrayerWheelchair),
            93 => Some(PoseExerciseName::CactusWheelchair),
            94 => Some(PoseExerciseName::BreathingPunchesWheelchair),
            95 => Some(PoseExerciseName::BreathingPunchesExtendedWheelchair),
            96 => Some(PoseExerciseName::BreathingPunchesOverheadWheelchair),
            97 => Some(PoseExerciseName::BreathingPunchesOverheadAndDownWheelchair),
            98 => Some(PoseExerciseName::BreathingPunchesSideWheelchair),
            99 => Some(PoseExerciseName::BreathingPunchesExtendedSideWheelchair),
            100 => Some(PoseExerciseName::BreathingPunchesOverheadSideWheelchair),
            101 => Some(PoseExerciseName::BreathingPunchesOverheadAndDownSideWheelchair),
            102 => Some(PoseExerciseName::LeftHandBackWheelchair),
            103 => Some(PoseExerciseName::TriangleWheelchair),
            104 => Some(PoseExerciseName::ThreadTheNeedleWheelchair),
            105 => Some(PoseExerciseName::NeckFlexionAndExtensionWheelchair),
            106 => Some(PoseExerciseName::NeckLateralFlexionWheelchair),
            107 => Some(PoseExerciseName::SpineFlexionAndExtensionWheelchair),
            108 => Some(PoseExerciseName::SpineRotationWheelchair),
            109 => Some(PoseExerciseName::SpineLateralFlexionWheelchair),
            110 => Some(PoseExerciseName::AlternativeSkiingWheelchair),
            111 => Some(PoseExerciseName::ReachForwardWheelchair),
            112 => Some(PoseExerciseName::WarriorWheelchair),
            113 => Some(PoseExerciseName::ReverseWarriorWheelchair),
            114 => Some(PoseExerciseName::DownwardFacingDogToCobra),
            115 => Some(PoseExerciseName::SeatedCatCow),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "all_fours" => Some(PoseExerciseName::AllFours),
            "ankle_to_knee" => Some(PoseExerciseName::AnkleToKnee),
            "baby_cobra" => Some(PoseExerciseName::BabyCobra),
            "boat" => Some(PoseExerciseName::Boat),
            "bound_angle" => Some(PoseExerciseName::BoundAngle),
            "bound_seated_single_leg_forward_bend" => {
                Some(PoseExerciseName::BoundSeatedSingleLegForwardBend)
            }
            "bow" => Some(PoseExerciseName::Bow),
            "bowed_half_moon" => Some(PoseExerciseName::BowedHalfMoon),
            "bridge" => Some(PoseExerciseName::Bridge),
            "cat" => Some(PoseExerciseName::Cat),
            "chair" => Some(PoseExerciseName::Chair),
            "childs" => Some(PoseExerciseName::Childs),
            "corpse" => Some(PoseExerciseName::Corpse),
            "cow_face" => Some(PoseExerciseName::CowFace),
            "cow" => Some(PoseExerciseName::Cow),
            "devotional_warrior" => Some(PoseExerciseName::DevotionalWarrior),
            "dolphin_plank" => Some(PoseExerciseName::DolphinPlank),
            "dolphin" => Some(PoseExerciseName::Dolphin),
            "down_dog_knee_to_nose" => Some(PoseExerciseName::DownDogKneeToNose),
            "down_dog_split" => Some(PoseExerciseName::DownDogSplit),
            "down_dog_split_open_hip_bent_knee" => {
                Some(PoseExerciseName::DownDogSplitOpenHipBentKnee)
            }
            "downward_facing_dog" => Some(PoseExerciseName::DownwardFacingDog),
            "eagle" => Some(PoseExerciseName::Eagle),
            "easy_seated" => Some(PoseExerciseName::EasySeated),
            "extended_puppy" => Some(PoseExerciseName::ExtendedPuppy),
            "extended_side_angle" => Some(PoseExerciseName::ExtendedSideAngle),
            "fish" => Some(PoseExerciseName::Fish),
            "four_limbed_staff" => Some(PoseExerciseName::FourLimbedStaff),
            "full_split" => Some(PoseExerciseName::FullSplit),
            "gate" => Some(PoseExerciseName::Gate),
            "half_chair_half_ankle_to_knee" => Some(PoseExerciseName::HalfChairHalfAnkleToKnee),
            "half_moon" => Some(PoseExerciseName::HalfMoon),
            "head_to_knee" => Some(PoseExerciseName::HeadToKnee),
            "heron" => Some(PoseExerciseName::Heron),
            "heros" => Some(PoseExerciseName::Heros),
            "high_lunge" => Some(PoseExerciseName::HighLunge),
            "knees_chest_chin" => Some(PoseExerciseName::KneesChestChin),
            "lizard" => Some(PoseExerciseName::Lizard),
            "locust" => Some(PoseExerciseName::Locust),
            "low_lunge" => Some(PoseExerciseName::LowLunge),
            "low_lunge_twist" => Some(PoseExerciseName::LowLungeTwist),
            "low_lunge_with_knee_down" => Some(PoseExerciseName::LowLungeWithKneeDown),
            "mermaid" => Some(PoseExerciseName::Mermaid),
            "mountain" => Some(PoseExerciseName::Mountain),
            "one_legged_downward_facing_pose_open_hip_bent_knee" => {
                Some(PoseExerciseName::OneLeggedDownwardFacingPoseOpenHipBentKnee)
            }
            "one_legged_pigeon" => Some(PoseExerciseName::OneLeggedPigeon),
            "peaceful_warrior" => Some(PoseExerciseName::PeacefulWarrior),
            "plank" => Some(PoseExerciseName::Plank),
            "plow" => Some(PoseExerciseName::Plow),
            "reclined_hand_to_foot" => Some(PoseExerciseName::ReclinedHandToFoot),
            "revolved_half_moon" => Some(PoseExerciseName::RevolvedHalfMoon),
            "revolved_head_to_knee" => Some(PoseExerciseName::RevolvedHeadToKnee),
            "revolved_triangle" => Some(PoseExerciseName::RevolvedTriangle),
            "runners_lunge" => Some(PoseExerciseName::RunnersLunge),
            "seated_easy_side_bend" => Some(PoseExerciseName::SeatedEasySideBend),
            "seated_easy_twist" => Some(PoseExerciseName::SeatedEasyTwist),
            "seated_long_leg_forward_bend" => Some(PoseExerciseName::SeatedLongLegForwardBend),
            "seated_wide_leg_forward_bend" => Some(PoseExerciseName::SeatedWideLegForwardBend),
            "shoulder_stand" => Some(PoseExerciseName::ShoulderStand),
            "side_boat" => Some(PoseExerciseName::SideBoat),
            "side_plank" => Some(PoseExerciseName::SidePlank),
            "sphinx" => Some(PoseExerciseName::Sphinx),
            "squat_open_arm_twist" => Some(PoseExerciseName::SquatOpenArmTwist),
            "squat_palm_press" => Some(PoseExerciseName::SquatPalmPress),
            "staff" => Some(PoseExerciseName::Staff),
            "standing_arms_up" => Some(PoseExerciseName::StandingArmsUp),
            "standing_forward_bend_halfway_up" => {
                Some(PoseExerciseName::StandingForwardBendHalfwayUp)
            }
            "standing_forward_bend" => Some(PoseExerciseName::StandingForwardBend),
            "standing_side_opener" => Some(PoseExerciseName::StandingSideOpener),
            "standing_single_leg_forward_bend" => {
                Some(PoseExerciseName::StandingSingleLegForwardBend)
            }
            "standing_split" => Some(PoseExerciseName::StandingSplit),
            "standing_wide_leg_forward_bend" => Some(PoseExerciseName::StandingWideLegForwardBend),
            "standing_wide_leg_forward_bend_with_twist" => {
                Some(PoseExerciseName::StandingWideLegForwardBendWithTwist)
            }
            "supine_spinal_twist" => Some(PoseExerciseName::SupineSpinalTwist),
            "table_top" => Some(PoseExerciseName::TableTop),
            "thread_the_needle" => Some(PoseExerciseName::ThreadTheNeedle),
            "thunderbolt" => Some(PoseExerciseName::Thunderbolt),
            "thunderbolt_pose_both_sides_arm_stretch" => {
                Some(PoseExerciseName::ThunderboltPoseBothSidesArmStretch)
            }
            "tree" => Some(PoseExerciseName::Tree),
            "triangle" => Some(PoseExerciseName::Triangle),
            "up_dog" => Some(PoseExerciseName::UpDog),
            "upward_facing_plank" => Some(PoseExerciseName::UpwardFacingPlank),
            "warrior_one" => Some(PoseExerciseName::WarriorOne),
            "warrior_three" => Some(PoseExerciseName::WarriorThree),
            "warrior_two" => Some(PoseExerciseName::WarriorTwo),
            "wheel" => Some(PoseExerciseName::Wheel),
            "wide_side_lunge" => Some(PoseExerciseName::WideSideLunge),
            "deep_breathing_wheelchair" => Some(PoseExerciseName::DeepBreathingWheelchair),
            "deep_breathing_low_wheelchair" => Some(PoseExerciseName::DeepBreathingLowWheelchair),
            "deep_breathing_mid_wheelchair" => Some(PoseExerciseName::DeepBreathingMidWheelchair),
            "deep_breathing_high_wheelchair" => Some(PoseExerciseName::DeepBreathingHighWheelchair),
            "prayer_wheelchair" => Some(PoseExerciseName::PrayerWheelchair),
            "overhead_prayer_wheelchair" => Some(PoseExerciseName::OverheadPrayerWheelchair),
            "cactus_wheelchair" => Some(PoseExerciseName::CactusWheelchair),
            "breathing_punches_wheelchair" => Some(PoseExerciseName::BreathingPunchesWheelchair),
            "breathing_punches_extended_wheelchair" => {
                Some(PoseExerciseName::BreathingPunchesExtendedWheelchair)
            }
            "breathing_punches_overhead_wheelchair" => {
                Some(PoseExerciseName::BreathingPunchesOverheadWheelchair)
            }
            "breathing_punches_overhead_and_down_wheelchair" => {
                Some(PoseExerciseName::BreathingPunchesOverheadAndDownWheelchair)
            }
            "breathing_punches_side_wheelchair" => {
                Some(PoseExerciseName::BreathingPunchesSideWheelchair)
            }
            "breathing_punches_extended_side_wheelchair" => {
                Some(PoseExerciseName::BreathingPunchesExtendedSideWheelchair)
            }
            "breathing_punches_overhead_side_wheelchair" => {
                Some(PoseExerciseName::BreathingPunchesOverheadSideWheelchair)
            }
            "breathing_punches_overhead_and_down_side_wheelchair" => {
                Some(PoseExerciseName::BreathingPunchesOverheadAndDownSideWheelchair)
            }
            "left_hand_back_wheelchair" => Some(PoseExerciseName::LeftHandBackWheelchair),
            "triangle_wheelchair" => Some(PoseExerciseName::TriangleWheelchair),
            "thread_the_needle_wheelchair" => Some(PoseExerciseName::ThreadTheNeedleWheelchair),
            "neck_flexion_and_extension_wheelchair" => {
                Some(PoseExerciseName::NeckFlexionAndExtensionWheelchair)
            }
            "neck_lateral_flexion_wheelchair" => {
                Some(PoseExerciseName::NeckLateralFlexionWheelchair)
            }
            "spine_flexion_and_extension_wheelchair" => {
                Some(PoseExerciseName::SpineFlexionAndExtensionWheelchair)
            }
            "spine_rotation_wheelchair" => Some(PoseExerciseName::SpineRotationWheelchair),
            "spine_lateral_flexion_wheelchair" => {
                Some(PoseExerciseName::SpineLateralFlexionWheelchair)
            }
            "alternative_skiing_wheelchair" => Some(PoseExerciseName::AlternativeSkiingWheelchair),
            "reach_forward_wheelchair" => Some(PoseExerciseName::ReachForwardWheelchair),
            "warrior_wheelchair" => Some(PoseExerciseName::WarriorWheelchair),
            "reverse_warrior_wheelchair" => Some(PoseExerciseName::ReverseWarriorWheelchair),
            "downward_facing_dog_to_cobra" => Some(PoseExerciseName::DownwardFacingDogToCobra),
            "seated_cat_cow" => Some(PoseExerciseName::SeatedCatCow),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum TricepsExtensionExerciseName {
    BenchDip = 0,
    WeightedBenchDip = 1,
    BodyWeightDip = 2,
    CableKickback = 3,
    CableLyingTricepsExtension = 4,
    CableOverheadTricepsExtension = 5,
    DumbbellKickback = 6,
    DumbbellLyingTricepsExtension = 7,
    EzBarOverheadTricepsExtension = 8,
    InclineDip = 9,
    WeightedInclineDip = 10,
    InclineEzBarLyingTricepsExtension = 11,
    LyingDumbbellPulloverToExtension = 12,
    LyingEzBarTricepsExtension = 13,
    LyingTricepsExtensionToCloseGripBenchPress = 14,
    OverheadDumbbellTricepsExtension = 15,
    RecliningTricepsPress = 16,
    ReverseGripPressdown = 17,
    ReverseGripTricepsPressdown = 18,
    RopePressdown = 19,
    SeatedBarbellOverheadTricepsExtension = 20,
    SeatedDumbbellOverheadTricepsExtension = 21,
    SeatedEzBarOverheadTricepsExtension = 22,
    SeatedSingleArmOverheadDumbbellExtension = 23,
    SingleArmDumbbellOverheadTricepsExtension = 24,
    SingleDumbbellSeatedOverheadTricepsExtension = 25,
    SingleLegBenchDipAndKick = 26,
    WeightedSingleLegBenchDipAndKick = 27,
    SingleLegDip = 28,
    WeightedSingleLegDip = 29,
    StaticLyingTricepsExtension = 30,
    SuspendedDip = 31,
    WeightedSuspendedDip = 32,
    SwissBallDumbbellLyingTricepsExtension = 33,
    SwissBallEzBarLyingTricepsExtension = 34,
    SwissBallEzBarOverheadTricepsExtension = 35,
    TabletopDip = 36,
    WeightedTabletopDip = 37,
    TricepsExtensionOnFloor = 38,
    TricepsPressdown = 39,
    WeightedDip = 40,
    AlternatingDumbbellLyingTricepsExtension = 41,
    TricepsPress = 42,
    DumbbellKickbackWheelchair = 43,
    OverheadDumbbellTricepsExtensionWheelchair = 44,
}

impl TricepsExtensionExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            TricepsExtensionExerciseName::BenchDip => "bench_dip",
            TricepsExtensionExerciseName::WeightedBenchDip => "weighted_bench_dip",
            TricepsExtensionExerciseName::BodyWeightDip => "body_weight_dip",
            TricepsExtensionExerciseName::CableKickback => "cable_kickback",
            TricepsExtensionExerciseName::CableLyingTricepsExtension => {
                "cable_lying_triceps_extension"
            }
            TricepsExtensionExerciseName::CableOverheadTricepsExtension => {
                "cable_overhead_triceps_extension"
            }
            TricepsExtensionExerciseName::DumbbellKickback => "dumbbell_kickback",
            TricepsExtensionExerciseName::DumbbellLyingTricepsExtension => {
                "dumbbell_lying_triceps_extension"
            }
            TricepsExtensionExerciseName::EzBarOverheadTricepsExtension => {
                "ez_bar_overhead_triceps_extension"
            }
            TricepsExtensionExerciseName::InclineDip => "incline_dip",
            TricepsExtensionExerciseName::WeightedInclineDip => "weighted_incline_dip",
            TricepsExtensionExerciseName::InclineEzBarLyingTricepsExtension => {
                "incline_ez_bar_lying_triceps_extension"
            }
            TricepsExtensionExerciseName::LyingDumbbellPulloverToExtension => {
                "lying_dumbbell_pullover_to_extension"
            }
            TricepsExtensionExerciseName::LyingEzBarTricepsExtension => {
                "lying_ez_bar_triceps_extension"
            }
            TricepsExtensionExerciseName::LyingTricepsExtensionToCloseGripBenchPress => {
                "lying_triceps_extension_to_close_grip_bench_press"
            }
            TricepsExtensionExerciseName::OverheadDumbbellTricepsExtension => {
                "overhead_dumbbell_triceps_extension"
            }
            TricepsExtensionExerciseName::RecliningTricepsPress => "reclining_triceps_press",
            TricepsExtensionExerciseName::ReverseGripPressdown => "reverse_grip_pressdown",
            TricepsExtensionExerciseName::ReverseGripTricepsPressdown => {
                "reverse_grip_triceps_pressdown"
            }
            TricepsExtensionExerciseName::RopePressdown => "rope_pressdown",
            TricepsExtensionExerciseName::SeatedBarbellOverheadTricepsExtension => {
                "seated_barbell_overhead_triceps_extension"
            }
            TricepsExtensionExerciseName::SeatedDumbbellOverheadTricepsExtension => {
                "seated_dumbbell_overhead_triceps_extension"
            }
            TricepsExtensionExerciseName::SeatedEzBarOverheadTricepsExtension => {
                "seated_ez_bar_overhead_triceps_extension"
            }
            TricepsExtensionExerciseName::SeatedSingleArmOverheadDumbbellExtension => {
                "seated_single_arm_overhead_dumbbell_extension"
            }
            TricepsExtensionExerciseName::SingleArmDumbbellOverheadTricepsExtension => {
                "single_arm_dumbbell_overhead_triceps_extension"
            }
            TricepsExtensionExerciseName::SingleDumbbellSeatedOverheadTricepsExtension => {
                "single_dumbbell_seated_overhead_triceps_extension"
            }
            TricepsExtensionExerciseName::SingleLegBenchDipAndKick => {
                "single_leg_bench_dip_and_kick"
            }
            TricepsExtensionExerciseName::WeightedSingleLegBenchDipAndKick => {
                "weighted_single_leg_bench_dip_and_kick"
            }
            TricepsExtensionExerciseName::SingleLegDip => "single_leg_dip",
            TricepsExtensionExerciseName::WeightedSingleLegDip => "weighted_single_leg_dip",
            TricepsExtensionExerciseName::StaticLyingTricepsExtension => {
                "static_lying_triceps_extension"
            }
            TricepsExtensionExerciseName::SuspendedDip => "suspended_dip",
            TricepsExtensionExerciseName::WeightedSuspendedDip => "weighted_suspended_dip",
            TricepsExtensionExerciseName::SwissBallDumbbellLyingTricepsExtension => {
                "swiss_ball_dumbbell_lying_triceps_extension"
            }
            TricepsExtensionExerciseName::SwissBallEzBarLyingTricepsExtension => {
                "swiss_ball_ez_bar_lying_triceps_extension"
            }
            TricepsExtensionExerciseName::SwissBallEzBarOverheadTricepsExtension => {
                "swiss_ball_ez_bar_overhead_triceps_extension"
            }
            TricepsExtensionExerciseName::TabletopDip => "tabletop_dip",
            TricepsExtensionExerciseName::WeightedTabletopDip => "weighted_tabletop_dip",
            TricepsExtensionExerciseName::TricepsExtensionOnFloor => "triceps_extension_on_floor",
            TricepsExtensionExerciseName::TricepsPressdown => "triceps_pressdown",
            TricepsExtensionExerciseName::WeightedDip => "weighted_dip",
            TricepsExtensionExerciseName::AlternatingDumbbellLyingTricepsExtension => {
                "alternating_dumbbell_lying_triceps_extension"
            }
            TricepsExtensionExerciseName::TricepsPress => "triceps_press",
            TricepsExtensionExerciseName::DumbbellKickbackWheelchair => {
                "dumbbell_kickback_wheelchair"
            }
            TricepsExtensionExerciseName::OverheadDumbbellTricepsExtensionWheelchair => {
                "overhead_dumbbell_triceps_extension_wheelchair"
            }
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(TricepsExtensionExerciseName::BenchDip),
            1 => Some(TricepsExtensionExerciseName::WeightedBenchDip),
            2 => Some(TricepsExtensionExerciseName::BodyWeightDip),
            3 => Some(TricepsExtensionExerciseName::CableKickback),
            4 => Some(TricepsExtensionExerciseName::CableLyingTricepsExtension),
            5 => Some(TricepsExtensionExerciseName::CableOverheadTricepsExtension),
            6 => Some(TricepsExtensionExerciseName::DumbbellKickback),
            7 => Some(TricepsExtensionExerciseName::DumbbellLyingTricepsExtension),
            8 => Some(TricepsExtensionExerciseName::EzBarOverheadTricepsExtension),
            9 => Some(TricepsExtensionExerciseName::InclineDip),
            10 => Some(TricepsExtensionExerciseName::WeightedInclineDip),
            11 => Some(TricepsExtensionExerciseName::InclineEzBarLyingTricepsExtension),
            12 => Some(TricepsExtensionExerciseName::LyingDumbbellPulloverToExtension),
            13 => Some(TricepsExtensionExerciseName::LyingEzBarTricepsExtension),
            14 => Some(TricepsExtensionExerciseName::LyingTricepsExtensionToCloseGripBenchPress),
            15 => Some(TricepsExtensionExerciseName::OverheadDumbbellTricepsExtension),
            16 => Some(TricepsExtensionExerciseName::RecliningTricepsPress),
            17 => Some(TricepsExtensionExerciseName::ReverseGripPressdown),
            18 => Some(TricepsExtensionExerciseName::ReverseGripTricepsPressdown),
            19 => Some(TricepsExtensionExerciseName::RopePressdown),
            20 => Some(TricepsExtensionExerciseName::SeatedBarbellOverheadTricepsExtension),
            21 => Some(TricepsExtensionExerciseName::SeatedDumbbellOverheadTricepsExtension),
            22 => Some(TricepsExtensionExerciseName::SeatedEzBarOverheadTricepsExtension),
            23 => Some(TricepsExtensionExerciseName::SeatedSingleArmOverheadDumbbellExtension),
            24 => Some(TricepsExtensionExerciseName::SingleArmDumbbellOverheadTricepsExtension),
            25 => Some(TricepsExtensionExerciseName::SingleDumbbellSeatedOverheadTricepsExtension),
            26 => Some(TricepsExtensionExerciseName::SingleLegBenchDipAndKick),
            27 => Some(TricepsExtensionExerciseName::WeightedSingleLegBenchDipAndKick),
            28 => Some(TricepsExtensionExerciseName::SingleLegDip),
            29 => Some(TricepsExtensionExerciseName::WeightedSingleLegDip),
            30 => Some(TricepsExtensionExerciseName::StaticLyingTricepsExtension),
            31 => Some(TricepsExtensionExerciseName::SuspendedDip),
            32 => Some(TricepsExtensionExerciseName::WeightedSuspendedDip),
            33 => Some(TricepsExtensionExerciseName::SwissBallDumbbellLyingTricepsExtension),
            34 => Some(TricepsExtensionExerciseName::SwissBallEzBarLyingTricepsExtension),
            35 => Some(TricepsExtensionExerciseName::SwissBallEzBarOverheadTricepsExtension),
            36 => Some(TricepsExtensionExerciseName::TabletopDip),
            37 => Some(TricepsExtensionExerciseName::WeightedTabletopDip),
            38 => Some(TricepsExtensionExerciseName::TricepsExtensionOnFloor),
            39 => Some(TricepsExtensionExerciseName::TricepsPressdown),
            40 => Some(TricepsExtensionExerciseName::WeightedDip),
            41 => Some(TricepsExtensionExerciseName::AlternatingDumbbellLyingTricepsExtension),
            42 => Some(TricepsExtensionExerciseName::TricepsPress),
            43 => Some(TricepsExtensionExerciseName::DumbbellKickbackWheelchair),
            44 => Some(TricepsExtensionExerciseName::OverheadDumbbellTricepsExtensionWheelchair),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "bench_dip" => Some(TricepsExtensionExerciseName::BenchDip),
            "weighted_bench_dip" => Some(TricepsExtensionExerciseName::WeightedBenchDip),
            "body_weight_dip" => Some(TricepsExtensionExerciseName::BodyWeightDip),
            "cable_kickback" => Some(TricepsExtensionExerciseName::CableKickback),
            "cable_lying_triceps_extension" => {
                Some(TricepsExtensionExerciseName::CableLyingTricepsExtension)
            }
            "cable_overhead_triceps_extension" => {
                Some(TricepsExtensionExerciseName::CableOverheadTricepsExtension)
            }
            "dumbbell_kickback" => Some(TricepsExtensionExerciseName::DumbbellKickback),
            "dumbbell_lying_triceps_extension" => {
                Some(TricepsExtensionExerciseName::DumbbellLyingTricepsExtension)
            }
            "ez_bar_overhead_triceps_extension" => {
                Some(TricepsExtensionExerciseName::EzBarOverheadTricepsExtension)
            }
            "incline_dip" => Some(TricepsExtensionExerciseName::InclineDip),
            "weighted_incline_dip" => Some(TricepsExtensionExerciseName::WeightedInclineDip),
            "incline_ez_bar_lying_triceps_extension" => {
                Some(TricepsExtensionExerciseName::InclineEzBarLyingTricepsExtension)
            }
            "lying_dumbbell_pullover_to_extension" => {
                Some(TricepsExtensionExerciseName::LyingDumbbellPulloverToExtension)
            }
            "lying_ez_bar_triceps_extension" => {
                Some(TricepsExtensionExerciseName::LyingEzBarTricepsExtension)
            }
            "lying_triceps_extension_to_close_grip_bench_press" => {
                Some(TricepsExtensionExerciseName::LyingTricepsExtensionToCloseGripBenchPress)
            }
            "overhead_dumbbell_triceps_extension" => {
                Some(TricepsExtensionExerciseName::OverheadDumbbellTricepsExtension)
            }
            "reclining_triceps_press" => Some(TricepsExtensionExerciseName::RecliningTricepsPress),
            "reverse_grip_pressdown" => Some(TricepsExtensionExerciseName::ReverseGripPressdown),
            "reverse_grip_triceps_pressdown" => {
                Some(TricepsExtensionExerciseName::ReverseGripTricepsPressdown)
            }
            "rope_pressdown" => Some(TricepsExtensionExerciseName::RopePressdown),
            "seated_barbell_overhead_triceps_extension" => {
                Some(TricepsExtensionExerciseName::SeatedBarbellOverheadTricepsExtension)
            }
            "seated_dumbbell_overhead_triceps_extension" => {
                Some(TricepsExtensionExerciseName::SeatedDumbbellOverheadTricepsExtension)
            }
            "seated_ez_bar_overhead_triceps_extension" => {
                Some(TricepsExtensionExerciseName::SeatedEzBarOverheadTricepsExtension)
            }
            "seated_single_arm_overhead_dumbbell_extension" => {
                Some(TricepsExtensionExerciseName::SeatedSingleArmOverheadDumbbellExtension)
            }
            "single_arm_dumbbell_overhead_triceps_extension" => {
                Some(TricepsExtensionExerciseName::SingleArmDumbbellOverheadTricepsExtension)
            }
            "single_dumbbell_seated_overhead_triceps_extension" => {
                Some(TricepsExtensionExerciseName::SingleDumbbellSeatedOverheadTricepsExtension)
            }
            "single_leg_bench_dip_and_kick" => {
                Some(TricepsExtensionExerciseName::SingleLegBenchDipAndKick)
            }
            "weighted_single_leg_bench_dip_and_kick" => {
                Some(TricepsExtensionExerciseName::WeightedSingleLegBenchDipAndKick)
            }
            "single_leg_dip" => Some(TricepsExtensionExerciseName::SingleLegDip),
            "weighted_single_leg_dip" => Some(TricepsExtensionExerciseName::WeightedSingleLegDip),
            "static_lying_triceps_extension" => {
                Some(TricepsExtensionExerciseName::StaticLyingTricepsExtension)
            }
            "suspended_dip" => Some(TricepsExtensionExerciseName::SuspendedDip),
            "weighted_suspended_dip" => Some(TricepsExtensionExerciseName::WeightedSuspendedDip),
            "swiss_ball_dumbbell_lying_triceps_extension" => {
                Some(TricepsExtensionExerciseName::SwissBallDumbbellLyingTricepsExtension)
            }
            "swiss_ball_ez_bar_lying_triceps_extension" => {
                Some(TricepsExtensionExerciseName::SwissBallEzBarLyingTricepsExtension)
            }
            "swiss_ball_ez_bar_overhead_triceps_extension" => {
                Some(TricepsExtensionExerciseName::SwissBallEzBarOverheadTricepsExtension)
            }
            "tabletop_dip" => Some(TricepsExtensionExerciseName::TabletopDip),
            "weighted_tabletop_dip" => Some(TricepsExtensionExerciseName::WeightedTabletopDip),
            "triceps_extension_on_floor" => {
                Some(TricepsExtensionExerciseName::TricepsExtensionOnFloor)
            }
            "triceps_pressdown" => Some(TricepsExtensionExerciseName::TricepsPressdown),
            "weighted_dip" => Some(TricepsExtensionExerciseName::WeightedDip),
            "alternating_dumbbell_lying_triceps_extension" => {
                Some(TricepsExtensionExerciseName::AlternatingDumbbellLyingTricepsExtension)
            }
            "triceps_press" => Some(TricepsExtensionExerciseName::TricepsPress),
            "dumbbell_kickback_wheelchair" => {
                Some(TricepsExtensionExerciseName::DumbbellKickbackWheelchair)
            }
            "overhead_dumbbell_triceps_extension_wheelchair" => {
                Some(TricepsExtensionExerciseName::OverheadDumbbellTricepsExtensionWheelchair)
            }
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum WarmUpExerciseName {
    QuadrupedRocking = 0,
    NeckTilts = 1,
    AnkleCircles = 2,
    AnkleDorsiflexionWithBand = 3,
    AnkleInternalRotation = 4,
    ArmCircles = 5,
    BentOverReachToSky = 6,
    CatCamel = 7,
    ElbowToFootLunge = 8,
    ForwardAndBackwardLegSwings = 9,
    Groiners = 10,
    InvertedHamstringStretch = 11,
    LateralDuckUnder = 12,
    NeckRotations = 13,
    OppositeArmAndLegBalance = 14,
    ReachRollAndLift = 15,
    Scorpion = 16,
    ShoulderCircles = 17,
    SideToSideLegSwings = 18,
    SleeperStretch = 19,
    SlideOut = 20,
    SwissBallHipCrossover = 21,
    SwissBallReachRollAndLift = 22,
    SwissBallWindshieldWipers = 23,
    ThoracicRotation = 24,
    WalkingHighKicks = 25,
    WalkingHighKnees = 26,
    WalkingKneeHugs = 27,
    WalkingLegCradles = 28,
    Walkout = 29,
    WalkoutFromPushUpPosition = 30,
    BicepsStretch = 31,
    GlutesStretch = 32,
    StandingHamstringStretch = 33,
    Stretch9090 = 34,
    StretchAbs = 35,
    StretchButterfly = 36,
    StretchCalf = 37,
    StretchCatCow = 38,
    StretchChildsPose = 39,
    StretchCobra = 40,
    StretchForearms = 41,
    StretchForwardGlutes = 42,
    StretchFrontSplit = 43,
    StretchHamstring = 44,
    StretchHipFlexorAndQuad = 45,
    StretchLat = 46,
    StretchLevatorScapulae = 47,
    StretchLungeWithSpinalTwist = 48,
    StretchLungingHipFlexor = 49,
    StretchLyingAbduction = 50,
    StretchLyingItBand = 51,
    StretchLyingKneeToChest = 52,
    StretchLyingPiriformis = 53,
    StretchLyingSpinalTwist = 54,
    StretchNeck = 55,
    StretchObliques = 56,
    StretchOverUnderShoulder = 57,
    StretchPectoral = 58,
    StretchPigeonPose = 59,
    StretchPiriformis = 60,
    StretchQuad = 61,
    StretchScorpion = 62,
    StretchShoulder = 63,
    StretchSide = 64,
    StretchSideLunge = 65,
    StretchSideSplit = 66,
    StretchStandingItBand = 67,
    StretchStraddle = 68,
    StretchTriceps = 69,
    StretchWallChestAndShoulder = 70,
    NeckRotationsWheelchair = 71,
    HalfKneelingArmRotation = 72,
    ThreeWayAnkleMobilization = 73,
    NinetyNinetyHipSwitch = 74,
    ActiveFrog = 75,
    ShoulderSweeps = 76,
    AnkleLunges = 77,
    BackRollFoamRoller = 78,
    BearCrawl = 79,
    LatissimusDorsiFoamRoll = 80,
    ReverseTHipOpener = 81,
    ShoulderRolls = 82,
    ChestOpeners = 83,
    TricepsStretch = 84,
    UpperBackStretch = 85,
    HipCircles = 86,
    AnkleStretch = 87,
    MarchingInPlace = 88,
    TricepsStretchWheelchair = 89,
    UpperBackStretchWheelchair = 90,
}

impl WarmUpExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            WarmUpExerciseName::QuadrupedRocking => "quadruped_rocking",
            WarmUpExerciseName::NeckTilts => "neck_tilts",
            WarmUpExerciseName::AnkleCircles => "ankle_circles",
            WarmUpExerciseName::AnkleDorsiflexionWithBand => "ankle_dorsiflexion_with_band",
            WarmUpExerciseName::AnkleInternalRotation => "ankle_internal_rotation",
            WarmUpExerciseName::ArmCircles => "arm_circles",
            WarmUpExerciseName::BentOverReachToSky => "bent_over_reach_to_sky",
            WarmUpExerciseName::CatCamel => "cat_camel",
            WarmUpExerciseName::ElbowToFootLunge => "elbow_to_foot_lunge",
            WarmUpExerciseName::ForwardAndBackwardLegSwings => "forward_and_backward_leg_swings",
            WarmUpExerciseName::Groiners => "groiners",
            WarmUpExerciseName::InvertedHamstringStretch => "inverted_hamstring_stretch",
            WarmUpExerciseName::LateralDuckUnder => "lateral_duck_under",
            WarmUpExerciseName::NeckRotations => "neck_rotations",
            WarmUpExerciseName::OppositeArmAndLegBalance => "opposite_arm_and_leg_balance",
            WarmUpExerciseName::ReachRollAndLift => "reach_roll_and_lift",
            WarmUpExerciseName::Scorpion => "scorpion",
            WarmUpExerciseName::ShoulderCircles => "shoulder_circles",
            WarmUpExerciseName::SideToSideLegSwings => "side_to_side_leg_swings",
            WarmUpExerciseName::SleeperStretch => "sleeper_stretch",
            WarmUpExerciseName::SlideOut => "slide_out",
            WarmUpExerciseName::SwissBallHipCrossover => "swiss_ball_hip_crossover",
            WarmUpExerciseName::SwissBallReachRollAndLift => "swiss_ball_reach_roll_and_lift",
            WarmUpExerciseName::SwissBallWindshieldWipers => "swiss_ball_windshield_wipers",
            WarmUpExerciseName::ThoracicRotation => "thoracic_rotation",
            WarmUpExerciseName::WalkingHighKicks => "walking_high_kicks",
            WarmUpExerciseName::WalkingHighKnees => "walking_high_knees",
            WarmUpExerciseName::WalkingKneeHugs => "walking_knee_hugs",
            WarmUpExerciseName::WalkingLegCradles => "walking_leg_cradles",
            WarmUpExerciseName::Walkout => "walkout",
            WarmUpExerciseName::WalkoutFromPushUpPosition => "walkout_from_push_up_position",
            WarmUpExerciseName::BicepsStretch => "biceps_stretch",
            WarmUpExerciseName::GlutesStretch => "glutes_stretch",
            WarmUpExerciseName::StandingHamstringStretch => "standing_hamstring_stretch",
            WarmUpExerciseName::Stretch9090 => "stretch_90_90",
            WarmUpExerciseName::StretchAbs => "stretch_abs",
            WarmUpExerciseName::StretchButterfly => "stretch_butterfly",
            WarmUpExerciseName::StretchCalf => "stretch_calf",
            WarmUpExerciseName::StretchCatCow => "stretch_cat_cow",
            WarmUpExerciseName::StretchChildsPose => "stretch_childs_pose",
            WarmUpExerciseName::StretchCobra => "stretch_cobra",
            WarmUpExerciseName::StretchForearms => "stretch_forearms",
            WarmUpExerciseName::StretchForwardGlutes => "stretch_forward_glutes",
            WarmUpExerciseName::StretchFrontSplit => "stretch_front_split",
            WarmUpExerciseName::StretchHamstring => "stretch_hamstring",
            WarmUpExerciseName::StretchHipFlexorAndQuad => "stretch_hip_flexor_and_quad",
            WarmUpExerciseName::StretchLat => "stretch_lat",
            WarmUpExerciseName::StretchLevatorScapulae => "stretch_levator_scapulae",
            WarmUpExerciseName::StretchLungeWithSpinalTwist => "stretch_lunge_with_spinal_twist",
            WarmUpExerciseName::StretchLungingHipFlexor => "stretch_lunging_hip_flexor",
            WarmUpExerciseName::StretchLyingAbduction => "stretch_lying_abduction",
            WarmUpExerciseName::StretchLyingItBand => "stretch_lying_it_band",
            WarmUpExerciseName::StretchLyingKneeToChest => "stretch_lying_knee_to_chest",
            WarmUpExerciseName::StretchLyingPiriformis => "stretch_lying_piriformis",
            WarmUpExerciseName::StretchLyingSpinalTwist => "stretch_lying_spinal_twist",
            WarmUpExerciseName::StretchNeck => "stretch_neck",
            WarmUpExerciseName::StretchObliques => "stretch_obliques",
            WarmUpExerciseName::StretchOverUnderShoulder => "stretch_over_under_shoulder",
            WarmUpExerciseName::StretchPectoral => "stretch_pectoral",
            WarmUpExerciseName::StretchPigeonPose => "stretch_pigeon_pose",
            WarmUpExerciseName::StretchPiriformis => "stretch_piriformis",
            WarmUpExerciseName::StretchQuad => "stretch_quad",
            WarmUpExerciseName::StretchScorpion => "stretch_scorpion",
            WarmUpExerciseName::StretchShoulder => "stretch_shoulder",
            WarmUpExerciseName::StretchSide => "stretch_side",
            WarmUpExerciseName::StretchSideLunge => "stretch_side_lunge",
            WarmUpExerciseName::StretchSideSplit => "stretch_side_split",
            WarmUpExerciseName::StretchStandingItBand => "stretch_standing_it_band",
            WarmUpExerciseName::StretchStraddle => "stretch_straddle",
            WarmUpExerciseName::StretchTriceps => "stretch_triceps",
            WarmUpExerciseName::StretchWallChestAndShoulder => "stretch_wall_chest_and_shoulder",
            WarmUpExerciseName::NeckRotationsWheelchair => "neck_rotations_wheelchair",
            WarmUpExerciseName::HalfKneelingArmRotation => "half_kneeling_arm_rotation",
            WarmUpExerciseName::ThreeWayAnkleMobilization => "three_way_ankle_mobilization",
            WarmUpExerciseName::NinetyNinetyHipSwitch => "ninety_ninety_hip_switch",
            WarmUpExerciseName::ActiveFrog => "active_frog",
            WarmUpExerciseName::ShoulderSweeps => "shoulder_sweeps",
            WarmUpExerciseName::AnkleLunges => "ankle_lunges",
            WarmUpExerciseName::BackRollFoamRoller => "back_roll_foam_roller",
            WarmUpExerciseName::BearCrawl => "bear_crawl",
            WarmUpExerciseName::LatissimusDorsiFoamRoll => "latissimus_dorsi_foam_roll",
            WarmUpExerciseName::ReverseTHipOpener => "reverse_t_hip_opener",
            WarmUpExerciseName::ShoulderRolls => "shoulder_rolls",
            WarmUpExerciseName::ChestOpeners => "chest_openers",
            WarmUpExerciseName::TricepsStretch => "triceps_stretch",
            WarmUpExerciseName::UpperBackStretch => "upper_back_stretch",
            WarmUpExerciseName::HipCircles => "hip_circles",
            WarmUpExerciseName::AnkleStretch => "ankle_stretch",
            WarmUpExerciseName::MarchingInPlace => "marching_in_place",
            WarmUpExerciseName::TricepsStretchWheelchair => "triceps_stretch_wheelchair",
            WarmUpExerciseName::UpperBackStretchWheelchair => "upper_back_stretch_wheelchair",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(WarmUpExerciseName::QuadrupedRocking),
            1 => Some(WarmUpExerciseName::NeckTilts),
            2 => Some(WarmUpExerciseName::AnkleCircles),
            3 => Some(WarmUpExerciseName::AnkleDorsiflexionWithBand),
            4 => Some(WarmUpExerciseName::AnkleInternalRotation),
            5 => Some(WarmUpExerciseName::ArmCircles),
            6 => Some(WarmUpExerciseName::BentOverReachToSky),
            7 => Some(WarmUpExerciseName::CatCamel),
            8 => Some(WarmUpExerciseName::ElbowToFootLunge),
            9 => Some(WarmUpExerciseName::ForwardAndBackwardLegSwings),
            10 => Some(WarmUpExerciseName::Groiners),
            11 => Some(WarmUpExerciseName::InvertedHamstringStretch),
            12 => Some(WarmUpExerciseName::LateralDuckUnder),
            13 => Some(WarmUpExerciseName::NeckRotations),
            14 => Some(WarmUpExerciseName::OppositeArmAndLegBalance),
            15 => Some(WarmUpExerciseName::ReachRollAndLift),
            16 => Some(WarmUpExerciseName::Scorpion),
            17 => Some(WarmUpExerciseName::ShoulderCircles),
            18 => Some(WarmUpExerciseName::SideToSideLegSwings),
            19 => Some(WarmUpExerciseName::SleeperStretch),
            20 => Some(WarmUpExerciseName::SlideOut),
            21 => Some(WarmUpExerciseName::SwissBallHipCrossover),
            22 => Some(WarmUpExerciseName::SwissBallReachRollAndLift),
            23 => Some(WarmUpExerciseName::SwissBallWindshieldWipers),
            24 => Some(WarmUpExerciseName::ThoracicRotation),
            25 => Some(WarmUpExerciseName::WalkingHighKicks),
            26 => Some(WarmUpExerciseName::WalkingHighKnees),
            27 => Some(WarmUpExerciseName::WalkingKneeHugs),
            28 => Some(WarmUpExerciseName::WalkingLegCradles),
            29 => Some(WarmUpExerciseName::Walkout),
            30 => Some(WarmUpExerciseName::WalkoutFromPushUpPosition),
            31 => Some(WarmUpExerciseName::BicepsStretch),
            32 => Some(WarmUpExerciseName::GlutesStretch),
            33 => Some(WarmUpExerciseName::StandingHamstringStretch),
            34 => Some(WarmUpExerciseName::Stretch9090),
            35 => Some(WarmUpExerciseName::StretchAbs),
            36 => Some(WarmUpExerciseName::StretchButterfly),
            37 => Some(WarmUpExerciseName::StretchCalf),
            38 => Some(WarmUpExerciseName::StretchCatCow),
            39 => Some(WarmUpExerciseName::StretchChildsPose),
            40 => Some(WarmUpExerciseName::StretchCobra),
            41 => Some(WarmUpExerciseName::StretchForearms),
            42 => Some(WarmUpExerciseName::StretchForwardGlutes),
            43 => Some(WarmUpExerciseName::StretchFrontSplit),
            44 => Some(WarmUpExerciseName::StretchHamstring),
            45 => Some(WarmUpExerciseName::StretchHipFlexorAndQuad),
            46 => Some(WarmUpExerciseName::StretchLat),
            47 => Some(WarmUpExerciseName::StretchLevatorScapulae),
            48 => Some(WarmUpExerciseName::StretchLungeWithSpinalTwist),
            49 => Some(WarmUpExerciseName::StretchLungingHipFlexor),
            50 => Some(WarmUpExerciseName::StretchLyingAbduction),
            51 => Some(WarmUpExerciseName::StretchLyingItBand),
            52 => Some(WarmUpExerciseName::StretchLyingKneeToChest),
            53 => Some(WarmUpExerciseName::StretchLyingPiriformis),
            54 => Some(WarmUpExerciseName::StretchLyingSpinalTwist),
            55 => Some(WarmUpExerciseName::StretchNeck),
            56 => Some(WarmUpExerciseName::StretchObliques),
            57 => Some(WarmUpExerciseName::StretchOverUnderShoulder),
            58 => Some(WarmUpExerciseName::StretchPectoral),
            59 => Some(WarmUpExerciseName::StretchPigeonPose),
            60 => Some(WarmUpExerciseName::StretchPiriformis),
            61 => Some(WarmUpExerciseName::StretchQuad),
            62 => Some(WarmUpExerciseName::StretchScorpion),
            63 => Some(WarmUpExerciseName::StretchShoulder),
            64 => Some(WarmUpExerciseName::StretchSide),
            65 => Some(WarmUpExerciseName::StretchSideLunge),
            66 => Some(WarmUpExerciseName::StretchSideSplit),
            67 => Some(WarmUpExerciseName::StretchStandingItBand),
            68 => Some(WarmUpExerciseName::StretchStraddle),
            69 => Some(WarmUpExerciseName::StretchTriceps),
            70 => Some(WarmUpExerciseName::StretchWallChestAndShoulder),
            71 => Some(WarmUpExerciseName::NeckRotationsWheelchair),
            72 => Some(WarmUpExerciseName::HalfKneelingArmRotation),
            73 => Some(WarmUpExerciseName::ThreeWayAnkleMobilization),
            74 => Some(WarmUpExerciseName::NinetyNinetyHipSwitch),
            75 => Some(WarmUpExerciseName::ActiveFrog),
            76 => Some(WarmUpExerciseName::ShoulderSweeps),
            77 => Some(WarmUpExerciseName::AnkleLunges),
            78 => Some(WarmUpExerciseName::BackRollFoamRoller),
            79 => Some(WarmUpExerciseName::BearCrawl),
            80 => Some(WarmUpExerciseName::LatissimusDorsiFoamRoll),
            81 => Some(WarmUpExerciseName::ReverseTHipOpener),
            82 => Some(WarmUpExerciseName::ShoulderRolls),
            83 => Some(WarmUpExerciseName::ChestOpeners),
            84 => Some(WarmUpExerciseName::TricepsStretch),
            85 => Some(WarmUpExerciseName::UpperBackStretch),
            86 => Some(WarmUpExerciseName::HipCircles),
            87 => Some(WarmUpExerciseName::AnkleStretch),
            88 => Some(WarmUpExerciseName::MarchingInPlace),
            89 => Some(WarmUpExerciseName::TricepsStretchWheelchair),
            90 => Some(WarmUpExerciseName::UpperBackStretchWheelchair),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "quadruped_rocking" => Some(WarmUpExerciseName::QuadrupedRocking),
            "neck_tilts" => Some(WarmUpExerciseName::NeckTilts),
            "ankle_circles" => Some(WarmUpExerciseName::AnkleCircles),
            "ankle_dorsiflexion_with_band" => Some(WarmUpExerciseName::AnkleDorsiflexionWithBand),
            "ankle_internal_rotation" => Some(WarmUpExerciseName::AnkleInternalRotation),
            "arm_circles" => Some(WarmUpExerciseName::ArmCircles),
            "bent_over_reach_to_sky" => Some(WarmUpExerciseName::BentOverReachToSky),
            "cat_camel" => Some(WarmUpExerciseName::CatCamel),
            "elbow_to_foot_lunge" => Some(WarmUpExerciseName::ElbowToFootLunge),
            "forward_and_backward_leg_swings" => {
                Some(WarmUpExerciseName::ForwardAndBackwardLegSwings)
            }
            "groiners" => Some(WarmUpExerciseName::Groiners),
            "inverted_hamstring_stretch" => Some(WarmUpExerciseName::InvertedHamstringStretch),
            "lateral_duck_under" => Some(WarmUpExerciseName::LateralDuckUnder),
            "neck_rotations" => Some(WarmUpExerciseName::NeckRotations),
            "opposite_arm_and_leg_balance" => Some(WarmUpExerciseName::OppositeArmAndLegBalance),
            "reach_roll_and_lift" => Some(WarmUpExerciseName::ReachRollAndLift),
            "scorpion" => Some(WarmUpExerciseName::Scorpion),
            "shoulder_circles" => Some(WarmUpExerciseName::ShoulderCircles),
            "side_to_side_leg_swings" => Some(WarmUpExerciseName::SideToSideLegSwings),
            "sleeper_stretch" => Some(WarmUpExerciseName::SleeperStretch),
            "slide_out" => Some(WarmUpExerciseName::SlideOut),
            "swiss_ball_hip_crossover" => Some(WarmUpExerciseName::SwissBallHipCrossover),
            "swiss_ball_reach_roll_and_lift" => Some(WarmUpExerciseName::SwissBallReachRollAndLift),
            "swiss_ball_windshield_wipers" => Some(WarmUpExerciseName::SwissBallWindshieldWipers),
            "thoracic_rotation" => Some(WarmUpExerciseName::ThoracicRotation),
            "walking_high_kicks" => Some(WarmUpExerciseName::WalkingHighKicks),
            "walking_high_knees" => Some(WarmUpExerciseName::WalkingHighKnees),
            "walking_knee_hugs" => Some(WarmUpExerciseName::WalkingKneeHugs),
            "walking_leg_cradles" => Some(WarmUpExerciseName::WalkingLegCradles),
            "walkout" => Some(WarmUpExerciseName::Walkout),
            "walkout_from_push_up_position" => Some(WarmUpExerciseName::WalkoutFromPushUpPosition),
            "biceps_stretch" => Some(WarmUpExerciseName::BicepsStretch),
            "glutes_stretch" => Some(WarmUpExerciseName::GlutesStretch),
            "standing_hamstring_stretch" => Some(WarmUpExerciseName::StandingHamstringStretch),
            "stretch_90_90" => Some(WarmUpExerciseName::Stretch9090),
            "stretch_abs" => Some(WarmUpExerciseName::StretchAbs),
            "stretch_butterfly" => Some(WarmUpExerciseName::StretchButterfly),
            "stretch_calf" => Some(WarmUpExerciseName::StretchCalf),
            "stretch_cat_cow" => Some(WarmUpExerciseName::StretchCatCow),
            "stretch_childs_pose" => Some(WarmUpExerciseName::StretchChildsPose),
            "stretch_cobra" => Some(WarmUpExerciseName::StretchCobra),
            "stretch_forearms" => Some(WarmUpExerciseName::StretchForearms),
            "stretch_forward_glutes" => Some(WarmUpExerciseName::StretchForwardGlutes),
            "stretch_front_split" => Some(WarmUpExerciseName::StretchFrontSplit),
            "stretch_hamstring" => Some(WarmUpExerciseName::StretchHamstring),
            "stretch_hip_flexor_and_quad" => Some(WarmUpExerciseName::StretchHipFlexorAndQuad),
            "stretch_lat" => Some(WarmUpExerciseName::StretchLat),
            "stretch_levator_scapulae" => Some(WarmUpExerciseName::StretchLevatorScapulae),
            "stretch_lunge_with_spinal_twist" => {
                Some(WarmUpExerciseName::StretchLungeWithSpinalTwist)
            }
            "stretch_lunging_hip_flexor" => Some(WarmUpExerciseName::StretchLungingHipFlexor),
            "stretch_lying_abduction" => Some(WarmUpExerciseName::StretchLyingAbduction),
            "stretch_lying_it_band" => Some(WarmUpExerciseName::StretchLyingItBand),
            "stretch_lying_knee_to_chest" => Some(WarmUpExerciseName::StretchLyingKneeToChest),
            "stretch_lying_piriformis" => Some(WarmUpExerciseName::StretchLyingPiriformis),
            "stretch_lying_spinal_twist" => Some(WarmUpExerciseName::StretchLyingSpinalTwist),
            "stretch_neck" => Some(WarmUpExerciseName::StretchNeck),
            "stretch_obliques" => Some(WarmUpExerciseName::StretchObliques),
            "stretch_over_under_shoulder" => Some(WarmUpExerciseName::StretchOverUnderShoulder),
            "stretch_pectoral" => Some(WarmUpExerciseName::StretchPectoral),
            "stretch_pigeon_pose" => Some(WarmUpExerciseName::StretchPigeonPose),
            "stretch_piriformis" => Some(WarmUpExerciseName::StretchPiriformis),
            "stretch_quad" => Some(WarmUpExerciseName::StretchQuad),
            "stretch_scorpion" => Some(WarmUpExerciseName::StretchScorpion),
            "stretch_shoulder" => Some(WarmUpExerciseName::StretchShoulder),
            "stretch_side" => Some(WarmUpExerciseName::StretchSide),
            "stretch_side_lunge" => Some(WarmUpExerciseName::StretchSideLunge),
            "stretch_side_split" => Some(WarmUpExerciseName::StretchSideSplit),
            "stretch_standing_it_band" => Some(WarmUpExerciseName::StretchStandingItBand),
            "stretch_straddle" => Some(WarmUpExerciseName::StretchStraddle),
            "stretch_triceps" => Some(WarmUpExerciseName::StretchTriceps),
            "stretch_wall_chest_and_shoulder" => {
                Some(WarmUpExerciseName::StretchWallChestAndShoulder)
            }
            "neck_rotations_wheelchair" => Some(WarmUpExerciseName::NeckRotationsWheelchair),
            "half_kneeling_arm_rotation" => Some(WarmUpExerciseName::HalfKneelingArmRotation),
            "three_way_ankle_mobilization" => Some(WarmUpExerciseName::ThreeWayAnkleMobilization),
            "ninety_ninety_hip_switch" => Some(WarmUpExerciseName::NinetyNinetyHipSwitch),
            "active_frog" => Some(WarmUpExerciseName::ActiveFrog),
            "shoulder_sweeps" => Some(WarmUpExerciseName::ShoulderSweeps),
            "ankle_lunges" => Some(WarmUpExerciseName::AnkleLunges),
            "back_roll_foam_roller" => Some(WarmUpExerciseName::BackRollFoamRoller),
            "bear_crawl" => Some(WarmUpExerciseName::BearCrawl),
            "latissimus_dorsi_foam_roll" => Some(WarmUpExerciseName::LatissimusDorsiFoamRoll),
            "reverse_t_hip_opener" => Some(WarmUpExerciseName::ReverseTHipOpener),
            "shoulder_rolls" => Some(WarmUpExerciseName::ShoulderRolls),
            "chest_openers" => Some(WarmUpExerciseName::ChestOpeners),
            "triceps_stretch" => Some(WarmUpExerciseName::TricepsStretch),
            "upper_back_stretch" => Some(WarmUpExerciseName::UpperBackStretch),
            "hip_circles" => Some(WarmUpExerciseName::HipCircles),
            "ankle_stretch" => Some(WarmUpExerciseName::AnkleStretch),
            "marching_in_place" => Some(WarmUpExerciseName::MarchingInPlace),
            "triceps_stretch_wheelchair" => Some(WarmUpExerciseName::TricepsStretchWheelchair),
            "upper_back_stretch_wheelchair" => Some(WarmUpExerciseName::UpperBackStretchWheelchair),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum RunExerciseName {
    Run = 0,
    Walk = 1,
    Jog = 2,
    Sprint = 3,
    RunOrWalk = 4,
    SpeedWalk = 5,
    WarmUp = 6,
}

impl RunExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            RunExerciseName::Run => "run",
            RunExerciseName::Walk => "walk",
            RunExerciseName::Jog => "jog",
            RunExerciseName::Sprint => "sprint",
            RunExerciseName::RunOrWalk => "run_or_walk",
            RunExerciseName::SpeedWalk => "speed_walk",
            RunExerciseName::WarmUp => "warm_up",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(RunExerciseName::Run),
            1 => Some(RunExerciseName::Walk),
            2 => Some(RunExerciseName::Jog),
            3 => Some(RunExerciseName::Sprint),
            4 => Some(RunExerciseName::RunOrWalk),
            5 => Some(RunExerciseName::SpeedWalk),
            6 => Some(RunExerciseName::WarmUp),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "run" => Some(RunExerciseName::Run),
            "walk" => Some(RunExerciseName::Walk),
            "jog" => Some(RunExerciseName::Jog),
            "sprint" => Some(RunExerciseName::Sprint),
            "run_or_walk" => Some(RunExerciseName::RunOrWalk),
            "speed_walk" => Some(RunExerciseName::SpeedWalk),
            "warm_up" => Some(RunExerciseName::WarmUp),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum BikeExerciseName {
    Bike = 0,
    Ride = 1,
    Sprint = 2,
}

impl BikeExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            BikeExerciseName::Bike => "bike",
            BikeExerciseName::Ride => "ride",
            BikeExerciseName::Sprint => "sprint",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(BikeExerciseName::Bike),
            1 => Some(BikeExerciseName::Ride),
            2 => Some(BikeExerciseName::Sprint),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "bike" => Some(BikeExerciseName::Bike),
            "ride" => Some(BikeExerciseName::Ride),
            "sprint" => Some(BikeExerciseName::Sprint),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum BandedExercisesExerciseName {
    AbTwist = 1,
    BackExtension = 2,
    BicycleCrunch = 3,
    CalfRaises = 4,
    ChestPress = 5,
    ClamShells = 6,
    Curl = 7,
    Deadbug = 8,
    Deadlift = 9,
    DonkeyKick = 10,
    ExternalRotation = 11,
    ExternalRotationAt90DegreeAbduction = 12,
    FacePull = 13,
    FireHydrant = 14,
    Fly = 15,
    FrontRaise = 16,
    GluteBridge = 17,
    HamstringCurls = 18,
    HighPlankLegLifts = 19,
    HipExtension = 20,
    InternalRotation = 21,
    JumpingJack = 22,
    KneelingCrunch = 23,
    LateralBandWalks = 24,
    LateralRaise = 25,
    Latpull = 26,
    LegAbduction = 27,
    LegAdduction = 28,
    LegExtension = 29,
    Lunge = 30,
    Plank = 31,
    PullApart = 32,
    PushUps = 33,
    ReverseCrunch = 34,
    Row = 35,
    ShoulderAbduction = 36,
    ShoulderExtension = 37,
    ShoulderExternalRotation = 38,
    ShoulderFlexionTo90Degrees = 39,
    SidePlankLegLifts = 40,
    SideRaise = 41,
    Squat = 42,
    SquatToPress = 43,
    TricepExtension = 44,
    TricepKickback = 45,
    UprightRow = 46,
    WallCrawlWithExternalRotation = 47,
    LateralRaiseWheelchair = 49,
    TricepsExtensionWheelchair = 50,
    ChestFlyInclineWheelchair = 51,
    ChestFlyDeclineWheelchair = 52,
    PullDownWheelchair = 53,
    StraightArmPullDownWheelchair = 54,
    CurlWheelchair = 55,
    OverheadCurlWheelchair = 56,
    FacePullWheelchair = 57,
    AroundTheWorldWheelchair = 58,
    PullApartWheelchair = 59,
    SideCurlWheelchair = 60,
    OverheadPressWheelchair = 61,
}

impl BandedExercisesExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            BandedExercisesExerciseName::AbTwist => "ab_twist",
            BandedExercisesExerciseName::BackExtension => "back_extension",
            BandedExercisesExerciseName::BicycleCrunch => "bicycle_crunch",
            BandedExercisesExerciseName::CalfRaises => "calf_raises",
            BandedExercisesExerciseName::ChestPress => "chest_press",
            BandedExercisesExerciseName::ClamShells => "clam_shells",
            BandedExercisesExerciseName::Curl => "curl",
            BandedExercisesExerciseName::Deadbug => "deadbug",
            BandedExercisesExerciseName::Deadlift => "deadlift",
            BandedExercisesExerciseName::DonkeyKick => "donkey_kick",
            BandedExercisesExerciseName::ExternalRotation => "external_rotation",
            BandedExercisesExerciseName::ExternalRotationAt90DegreeAbduction => {
                "external_rotation_at_90_degree_abduction"
            }
            BandedExercisesExerciseName::FacePull => "face_pull",
            BandedExercisesExerciseName::FireHydrant => "fire_hydrant",
            BandedExercisesExerciseName::Fly => "fly",
            BandedExercisesExerciseName::FrontRaise => "front_raise",
            BandedExercisesExerciseName::GluteBridge => "glute_bridge",
            BandedExercisesExerciseName::HamstringCurls => "hamstring_curls",
            BandedExercisesExerciseName::HighPlankLegLifts => "high_plank_leg_lifts",
            BandedExercisesExerciseName::HipExtension => "hip_extension",
            BandedExercisesExerciseName::InternalRotation => "internal_rotation",
            BandedExercisesExerciseName::JumpingJack => "jumping_jack",
            BandedExercisesExerciseName::KneelingCrunch => "kneeling_crunch",
            BandedExercisesExerciseName::LateralBandWalks => "lateral_band_walks",
            BandedExercisesExerciseName::LateralRaise => "lateral_raise",
            BandedExercisesExerciseName::Latpull => "latpull",
            BandedExercisesExerciseName::LegAbduction => "leg_abduction",
            BandedExercisesExerciseName::LegAdduction => "leg_adduction",
            BandedExercisesExerciseName::LegExtension => "leg_extension",
            BandedExercisesExerciseName::Lunge => "lunge",
            BandedExercisesExerciseName::Plank => "plank",
            BandedExercisesExerciseName::PullApart => "pull_apart",
            BandedExercisesExerciseName::PushUps => "push_ups",
            BandedExercisesExerciseName::ReverseCrunch => "reverse_crunch",
            BandedExercisesExerciseName::Row => "row",
            BandedExercisesExerciseName::ShoulderAbduction => "shoulder_abduction",
            BandedExercisesExerciseName::ShoulderExtension => "shoulder_extension",
            BandedExercisesExerciseName::ShoulderExternalRotation => "shoulder_external_rotation",
            BandedExercisesExerciseName::ShoulderFlexionTo90Degrees => {
                "shoulder_flexion_to_90_degrees"
            }
            BandedExercisesExerciseName::SidePlankLegLifts => "side_plank_leg_lifts",
            BandedExercisesExerciseName::SideRaise => "side_raise",
            BandedExercisesExerciseName::Squat => "squat",
            BandedExercisesExerciseName::SquatToPress => "squat_to_press",
            BandedExercisesExerciseName::TricepExtension => "tricep_extension",
            BandedExercisesExerciseName::TricepKickback => "tricep_kickback",
            BandedExercisesExerciseName::UprightRow => "upright_row",
            BandedExercisesExerciseName::WallCrawlWithExternalRotation => {
                "wall_crawl_with_external_rotation"
            }
            BandedExercisesExerciseName::LateralRaiseWheelchair => "lateral_raise_wheelchair",
            BandedExercisesExerciseName::TricepsExtensionWheelchair => {
                "triceps_extension_wheelchair"
            }
            BandedExercisesExerciseName::ChestFlyInclineWheelchair => {
                "chest_fly_incline_wheelchair"
            }
            BandedExercisesExerciseName::ChestFlyDeclineWheelchair => {
                "chest_fly_decline_wheelchair"
            }
            BandedExercisesExerciseName::PullDownWheelchair => "pull_down_wheelchair",
            BandedExercisesExerciseName::StraightArmPullDownWheelchair => {
                "straight_arm_pull_down_wheelchair"
            }
            BandedExercisesExerciseName::CurlWheelchair => "curl_wheelchair",
            BandedExercisesExerciseName::OverheadCurlWheelchair => "overhead_curl_wheelchair",
            BandedExercisesExerciseName::FacePullWheelchair => "face_pull_wheelchair",
            BandedExercisesExerciseName::AroundTheWorldWheelchair => "around_the_world_wheelchair",
            BandedExercisesExerciseName::PullApartWheelchair => "pull_apart_wheelchair",
            BandedExercisesExerciseName::SideCurlWheelchair => "side_curl_wheelchair",
            BandedExercisesExerciseName::OverheadPressWheelchair => "overhead_press_wheelchair",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            1 => Some(BandedExercisesExerciseName::AbTwist),
            2 => Some(BandedExercisesExerciseName::BackExtension),
            3 => Some(BandedExercisesExerciseName::BicycleCrunch),
            4 => Some(BandedExercisesExerciseName::CalfRaises),
            5 => Some(BandedExercisesExerciseName::ChestPress),
            6 => Some(BandedExercisesExerciseName::ClamShells),
            7 => Some(BandedExercisesExerciseName::Curl),
            8 => Some(BandedExercisesExerciseName::Deadbug),
            9 => Some(BandedExercisesExerciseName::Deadlift),
            10 => Some(BandedExercisesExerciseName::DonkeyKick),
            11 => Some(BandedExercisesExerciseName::ExternalRotation),
            12 => Some(BandedExercisesExerciseName::ExternalRotationAt90DegreeAbduction),
            13 => Some(BandedExercisesExerciseName::FacePull),
            14 => Some(BandedExercisesExerciseName::FireHydrant),
            15 => Some(BandedExercisesExerciseName::Fly),
            16 => Some(BandedExercisesExerciseName::FrontRaise),
            17 => Some(BandedExercisesExerciseName::GluteBridge),
            18 => Some(BandedExercisesExerciseName::HamstringCurls),
            19 => Some(BandedExercisesExerciseName::HighPlankLegLifts),
            20 => Some(BandedExercisesExerciseName::HipExtension),
            21 => Some(BandedExercisesExerciseName::InternalRotation),
            22 => Some(BandedExercisesExerciseName::JumpingJack),
            23 => Some(BandedExercisesExerciseName::KneelingCrunch),
            24 => Some(BandedExercisesExerciseName::LateralBandWalks),
            25 => Some(BandedExercisesExerciseName::LateralRaise),
            26 => Some(BandedExercisesExerciseName::Latpull),
            27 => Some(BandedExercisesExerciseName::LegAbduction),
            28 => Some(BandedExercisesExerciseName::LegAdduction),
            29 => Some(BandedExercisesExerciseName::LegExtension),
            30 => Some(BandedExercisesExerciseName::Lunge),
            31 => Some(BandedExercisesExerciseName::Plank),
            32 => Some(BandedExercisesExerciseName::PullApart),
            33 => Some(BandedExercisesExerciseName::PushUps),
            34 => Some(BandedExercisesExerciseName::ReverseCrunch),
            35 => Some(BandedExercisesExerciseName::Row),
            36 => Some(BandedExercisesExerciseName::ShoulderAbduction),
            37 => Some(BandedExercisesExerciseName::ShoulderExtension),
            38 => Some(BandedExercisesExerciseName::ShoulderExternalRotation),
            39 => Some(BandedExercisesExerciseName::ShoulderFlexionTo90Degrees),
            40 => Some(BandedExercisesExerciseName::SidePlankLegLifts),
            41 => Some(BandedExercisesExerciseName::SideRaise),
            42 => Some(BandedExercisesExerciseName::Squat),
            43 => Some(BandedExercisesExerciseName::SquatToPress),
            44 => Some(BandedExercisesExerciseName::TricepExtension),
            45 => Some(BandedExercisesExerciseName::TricepKickback),
            46 => Some(BandedExercisesExerciseName::UprightRow),
            47 => Some(BandedExercisesExerciseName::WallCrawlWithExternalRotation),
            49 => Some(BandedExercisesExerciseName::LateralRaiseWheelchair),
            50 => Some(BandedExercisesExerciseName::TricepsExtensionWheelchair),
            51 => Some(BandedExercisesExerciseName::ChestFlyInclineWheelchair),
            52 => Some(BandedExercisesExerciseName::ChestFlyDeclineWheelchair),
            53 => Some(BandedExercisesExerciseName::PullDownWheelchair),
            54 => Some(BandedExercisesExerciseName::StraightArmPullDownWheelchair),
            55 => Some(BandedExercisesExerciseName::CurlWheelchair),
            56 => Some(BandedExercisesExerciseName::OverheadCurlWheelchair),
            57 => Some(BandedExercisesExerciseName::FacePullWheelchair),
            58 => Some(BandedExercisesExerciseName::AroundTheWorldWheelchair),
            59 => Some(BandedExercisesExerciseName::PullApartWheelchair),
            60 => Some(BandedExercisesExerciseName::SideCurlWheelchair),
            61 => Some(BandedExercisesExerciseName::OverheadPressWheelchair),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "ab_twist" => Some(BandedExercisesExerciseName::AbTwist),
            "back_extension" => Some(BandedExercisesExerciseName::BackExtension),
            "bicycle_crunch" => Some(BandedExercisesExerciseName::BicycleCrunch),
            "calf_raises" => Some(BandedExercisesExerciseName::CalfRaises),
            "chest_press" => Some(BandedExercisesExerciseName::ChestPress),
            "clam_shells" => Some(BandedExercisesExerciseName::ClamShells),
            "curl" => Some(BandedExercisesExerciseName::Curl),
            "deadbug" => Some(BandedExercisesExerciseName::Deadbug),
            "deadlift" => Some(BandedExercisesExerciseName::Deadlift),
            "donkey_kick" => Some(BandedExercisesExerciseName::DonkeyKick),
            "external_rotation" => Some(BandedExercisesExerciseName::ExternalRotation),
            "external_rotation_at_90_degree_abduction" => {
                Some(BandedExercisesExerciseName::ExternalRotationAt90DegreeAbduction)
            }
            "face_pull" => Some(BandedExercisesExerciseName::FacePull),
            "fire_hydrant" => Some(BandedExercisesExerciseName::FireHydrant),
            "fly" => Some(BandedExercisesExerciseName::Fly),
            "front_raise" => Some(BandedExercisesExerciseName::FrontRaise),
            "glute_bridge" => Some(BandedExercisesExerciseName::GluteBridge),
            "hamstring_curls" => Some(BandedExercisesExerciseName::HamstringCurls),
            "high_plank_leg_lifts" => Some(BandedExercisesExerciseName::HighPlankLegLifts),
            "hip_extension" => Some(BandedExercisesExerciseName::HipExtension),
            "internal_rotation" => Some(BandedExercisesExerciseName::InternalRotation),
            "jumping_jack" => Some(BandedExercisesExerciseName::JumpingJack),
            "kneeling_crunch" => Some(BandedExercisesExerciseName::KneelingCrunch),
            "lateral_band_walks" => Some(BandedExercisesExerciseName::LateralBandWalks),
            "lateral_raise" => Some(BandedExercisesExerciseName::LateralRaise),
            "latpull" => Some(BandedExercisesExerciseName::Latpull),
            "leg_abduction" => Some(BandedExercisesExerciseName::LegAbduction),
            "leg_adduction" => Some(BandedExercisesExerciseName::LegAdduction),
            "leg_extension" => Some(BandedExercisesExerciseName::LegExtension),
            "lunge" => Some(BandedExercisesExerciseName::Lunge),
            "plank" => Some(BandedExercisesExerciseName::Plank),
            "pull_apart" => Some(BandedExercisesExerciseName::PullApart),
            "push_ups" => Some(BandedExercisesExerciseName::PushUps),
            "reverse_crunch" => Some(BandedExercisesExerciseName::ReverseCrunch),
            "row" => Some(BandedExercisesExerciseName::Row),
            "shoulder_abduction" => Some(BandedExercisesExerciseName::ShoulderAbduction),
            "shoulder_extension" => Some(BandedExercisesExerciseName::ShoulderExtension),
            "shoulder_external_rotation" => {
                Some(BandedExercisesExerciseName::ShoulderExternalRotation)
            }
            "shoulder_flexion_to_90_degrees" => {
                Some(BandedExercisesExerciseName::ShoulderFlexionTo90Degrees)
            }
            "side_plank_leg_lifts" => Some(BandedExercisesExerciseName::SidePlankLegLifts),
            "side_raise" => Some(BandedExercisesExerciseName::SideRaise),
            "squat" => Some(BandedExercisesExerciseName::Squat),
            "squat_to_press" => Some(BandedExercisesExerciseName::SquatToPress),
            "tricep_extension" => Some(BandedExercisesExerciseName::TricepExtension),
            "tricep_kickback" => Some(BandedExercisesExerciseName::TricepKickback),
            "upright_row" => Some(BandedExercisesExerciseName::UprightRow),
            "wall_crawl_with_external_rotation" => {
                Some(BandedExercisesExerciseName::WallCrawlWithExternalRotation)
            }
            "lateral_raise_wheelchair" => Some(BandedExercisesExerciseName::LateralRaiseWheelchair),
            "triceps_extension_wheelchair" => {
                Some(BandedExercisesExerciseName::TricepsExtensionWheelchair)
            }
            "chest_fly_incline_wheelchair" => {
                Some(BandedExercisesExerciseName::ChestFlyInclineWheelchair)
            }
            "chest_fly_decline_wheelchair" => {
                Some(BandedExercisesExerciseName::ChestFlyDeclineWheelchair)
            }
            "pull_down_wheelchair" => Some(BandedExercisesExerciseName::PullDownWheelchair),
            "straight_arm_pull_down_wheelchair" => {
                Some(BandedExercisesExerciseName::StraightArmPullDownWheelchair)
            }
            "curl_wheelchair" => Some(BandedExercisesExerciseName::CurlWheelchair),
            "overhead_curl_wheelchair" => Some(BandedExercisesExerciseName::OverheadCurlWheelchair),
            "face_pull_wheelchair" => Some(BandedExercisesExerciseName::FacePullWheelchair),
            "around_the_world_wheelchair" => {
                Some(BandedExercisesExerciseName::AroundTheWorldWheelchair)
            }
            "pull_apart_wheelchair" => Some(BandedExercisesExerciseName::PullApartWheelchair),
            "side_curl_wheelchair" => Some(BandedExercisesExerciseName::SideCurlWheelchair),
            "overhead_press_wheelchair" => {
                Some(BandedExercisesExerciseName::OverheadPressWheelchair)
            }
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum BattleRopeExerciseName {
    AlternatingFigureEight = 0,
    AlternatingJumpWave = 1,
    AlternatingKneelingToStandingWave = 2,
    AlternatingLungeWave = 3,
    AlternatingSquatWave = 4,
    AlternatingWave = 5,
    AlternatingWaveWithLateralShuffle = 6,
    ClapWave = 7,
    DoubleArmFigureEight = 8,
    DoubleArmSideToSideSnake = 9,
    DoubleArmSideWave = 10,
    DoubleArmSlam = 11,
    DoubleArmWave = 12,
    GrapplerToss = 13,
    HipToss = 14,
    InAndOutWave = 15,
    InsideCircle = 16,
    JumpingJacks = 17,
    OutsideCircle = 18,
    Rainbow = 19,
    SidePlankWave = 20,
    Sidewinder = 21,
    SittingRussianTwist = 22,
    SnakeWave = 23,
    SplitJack = 24,
    StageCoach = 25,
    UltimateWarrior = 26,
    UpperCuts = 27,
}

impl BattleRopeExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            BattleRopeExerciseName::AlternatingFigureEight => "alternating_figure_eight",
            BattleRopeExerciseName::AlternatingJumpWave => "alternating_jump_wave",
            BattleRopeExerciseName::AlternatingKneelingToStandingWave => {
                "alternating_kneeling_to_standing_wave"
            }
            BattleRopeExerciseName::AlternatingLungeWave => "alternating_lunge_wave",
            BattleRopeExerciseName::AlternatingSquatWave => "alternating_squat_wave",
            BattleRopeExerciseName::AlternatingWave => "alternating_wave",
            BattleRopeExerciseName::AlternatingWaveWithLateralShuffle => {
                "alternating_wave_with_lateral_shuffle"
            }
            BattleRopeExerciseName::ClapWave => "clap_wave",
            BattleRopeExerciseName::DoubleArmFigureEight => "double_arm_figure_eight",
            BattleRopeExerciseName::DoubleArmSideToSideSnake => "double_arm_side_to_side_snake",
            BattleRopeExerciseName::DoubleArmSideWave => "double_arm_side_wave",
            BattleRopeExerciseName::DoubleArmSlam => "double_arm_slam",
            BattleRopeExerciseName::DoubleArmWave => "double_arm_wave",
            BattleRopeExerciseName::GrapplerToss => "grappler_toss",
            BattleRopeExerciseName::HipToss => "hip_toss",
            BattleRopeExerciseName::InAndOutWave => "in_and_out_wave",
            BattleRopeExerciseName::InsideCircle => "inside_circle",
            BattleRopeExerciseName::JumpingJacks => "jumping_jacks",
            BattleRopeExerciseName::OutsideCircle => "outside_circle",
            BattleRopeExerciseName::Rainbow => "rainbow",
            BattleRopeExerciseName::SidePlankWave => "side_plank_wave",
            BattleRopeExerciseName::Sidewinder => "sidewinder",
            BattleRopeExerciseName::SittingRussianTwist => "sitting_russian_twist",
            BattleRopeExerciseName::SnakeWave => "snake_wave",
            BattleRopeExerciseName::SplitJack => "split_jack",
            BattleRopeExerciseName::StageCoach => "stage_coach",
            BattleRopeExerciseName::UltimateWarrior => "ultimate_warrior",
            BattleRopeExerciseName::UpperCuts => "upper_cuts",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(BattleRopeExerciseName::AlternatingFigureEight),
            1 => Some(BattleRopeExerciseName::AlternatingJumpWave),
            2 => Some(BattleRopeExerciseName::AlternatingKneelingToStandingWave),
            3 => Some(BattleRopeExerciseName::AlternatingLungeWave),
            4 => Some(BattleRopeExerciseName::AlternatingSquatWave),
            5 => Some(BattleRopeExerciseName::AlternatingWave),
            6 => Some(BattleRopeExerciseName::AlternatingWaveWithLateralShuffle),
            7 => Some(BattleRopeExerciseName::ClapWave),
            8 => Some(BattleRopeExerciseName::DoubleArmFigureEight),
            9 => Some(BattleRopeExerciseName::DoubleArmSideToSideSnake),
            10 => Some(BattleRopeExerciseName::DoubleArmSideWave),
            11 => Some(BattleRopeExerciseName::DoubleArmSlam),
            12 => Some(BattleRopeExerciseName::DoubleArmWave),
            13 => Some(BattleRopeExerciseName::GrapplerToss),
            14 => Some(BattleRopeExerciseName::HipToss),
            15 => Some(BattleRopeExerciseName::InAndOutWave),
            16 => Some(BattleRopeExerciseName::InsideCircle),
            17 => Some(BattleRopeExerciseName::JumpingJacks),
            18 => Some(BattleRopeExerciseName::OutsideCircle),
            19 => Some(BattleRopeExerciseName::Rainbow),
            20 => Some(BattleRopeExerciseName::SidePlankWave),
            21 => Some(BattleRopeExerciseName::Sidewinder),
            22 => Some(BattleRopeExerciseName::SittingRussianTwist),
            23 => Some(BattleRopeExerciseName::SnakeWave),
            24 => Some(BattleRopeExerciseName::SplitJack),
            25 => Some(BattleRopeExerciseName::StageCoach),
            26 => Some(BattleRopeExerciseName::UltimateWarrior),
            27 => Some(BattleRopeExerciseName::UpperCuts),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "alternating_figure_eight" => Some(BattleRopeExerciseName::AlternatingFigureEight),
            "alternating_jump_wave" => Some(BattleRopeExerciseName::AlternatingJumpWave),
            "alternating_kneeling_to_standing_wave" => {
                Some(BattleRopeExerciseName::AlternatingKneelingToStandingWave)
            }
            "alternating_lunge_wave" => Some(BattleRopeExerciseName::AlternatingLungeWave),
            "alternating_squat_wave" => Some(BattleRopeExerciseName::AlternatingSquatWave),
            "alternating_wave" => Some(BattleRopeExerciseName::AlternatingWave),
            "alternating_wave_with_lateral_shuffle" => {
                Some(BattleRopeExerciseName::AlternatingWaveWithLateralShuffle)
            }
            "clap_wave" => Some(BattleRopeExerciseName::ClapWave),
            "double_arm_figure_eight" => Some(BattleRopeExerciseName::DoubleArmFigureEight),
            "double_arm_side_to_side_snake" => {
                Some(BattleRopeExerciseName::DoubleArmSideToSideSnake)
            }
            "double_arm_side_wave" => Some(BattleRopeExerciseName::DoubleArmSideWave),
            "double_arm_slam" => Some(BattleRopeExerciseName::DoubleArmSlam),
            "double_arm_wave" => Some(BattleRopeExerciseName::DoubleArmWave),
            "grappler_toss" => Some(BattleRopeExerciseName::GrapplerToss),
            "hip_toss" => Some(BattleRopeExerciseName::HipToss),
            "in_and_out_wave" => Some(BattleRopeExerciseName::InAndOutWave),
            "inside_circle" => Some(BattleRopeExerciseName::InsideCircle),
            "jumping_jacks" => Some(BattleRopeExerciseName::JumpingJacks),
            "outside_circle" => Some(BattleRopeExerciseName::OutsideCircle),
            "rainbow" => Some(BattleRopeExerciseName::Rainbow),
            "side_plank_wave" => Some(BattleRopeExerciseName::SidePlankWave),
            "sidewinder" => Some(BattleRopeExerciseName::Sidewinder),
            "sitting_russian_twist" => Some(BattleRopeExerciseName::SittingRussianTwist),
            "snake_wave" => Some(BattleRopeExerciseName::SnakeWave),
            "split_jack" => Some(BattleRopeExerciseName::SplitJack),
            "stage_coach" => Some(BattleRopeExerciseName::StageCoach),
            "ultimate_warrior" => Some(BattleRopeExerciseName::UltimateWarrior),
            "upper_cuts" => Some(BattleRopeExerciseName::UpperCuts),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum EllipticalExerciseName {
    Elliptical = 0,
}

impl EllipticalExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            EllipticalExerciseName::Elliptical => "elliptical",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(EllipticalExerciseName::Elliptical),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "elliptical" => Some(EllipticalExerciseName::Elliptical),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum FloorClimbExerciseName {
    FloorClimb = 0,
}

impl FloorClimbExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            FloorClimbExerciseName::FloorClimb => "floor_climb",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(FloorClimbExerciseName::FloorClimb),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "floor_climb" => Some(FloorClimbExerciseName::FloorClimb),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum IndoorBikeExerciseName {
    AirBike = 0,
    AssaultBike = 1,
    StationaryBike = 3,
}

impl IndoorBikeExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            IndoorBikeExerciseName::AirBike => "air_bike",
            IndoorBikeExerciseName::AssaultBike => "assault_bike",
            IndoorBikeExerciseName::StationaryBike => "stationary_bike",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(IndoorBikeExerciseName::AirBike),
            1 => Some(IndoorBikeExerciseName::AssaultBike),
            3 => Some(IndoorBikeExerciseName::StationaryBike),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "air_bike" => Some(IndoorBikeExerciseName::AirBike),
            "assault_bike" => Some(IndoorBikeExerciseName::AssaultBike),
            "stationary_bike" => Some(IndoorBikeExerciseName::StationaryBike),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum IndoorRowExerciseName {
    RowingMachine = 0,
}

impl IndoorRowExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            IndoorRowExerciseName::RowingMachine => "rowing_machine",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(IndoorRowExerciseName::RowingMachine),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "rowing_machine" => Some(IndoorRowExerciseName::RowingMachine),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum LadderExerciseName {
    Agility = 0,
    Speed = 1,
}

impl LadderExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            LadderExerciseName::Agility => "agility",
            LadderExerciseName::Speed => "speed",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(LadderExerciseName::Agility),
            1 => Some(LadderExerciseName::Speed),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "agility" => Some(LadderExerciseName::Agility),
            "speed" => Some(LadderExerciseName::Speed),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum SandbagExerciseName {
    AroundTheWorld = 0,
    BackSquat = 1,
    BearCrawlPullThrough = 2,
    BearHugSquat = 3,
    Clean = 4,
    CleanAndPress = 5,
    Curl = 6,
    FrontCarry = 7,
    FrontSquat = 8,
    Lunge = 9,
    OverheadPress = 10,
    PlankPullThrough = 11,
    RotationalLunge = 12,
    Row = 13,
    RussianTwist = 14,
    Shouldering = 15,
    Shoveling = 16,
    SideLunge = 17,
    Sprint = 18,
    ZercherSquat = 19,
}

impl SandbagExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            SandbagExerciseName::AroundTheWorld => "around_the_world",
            SandbagExerciseName::BackSquat => "back_squat",
            SandbagExerciseName::BearCrawlPullThrough => "bear_crawl_pull_through",
            SandbagExerciseName::BearHugSquat => "bear_hug_squat",
            SandbagExerciseName::Clean => "clean",
            SandbagExerciseName::CleanAndPress => "clean_and_press",
            SandbagExerciseName::Curl => "curl",
            SandbagExerciseName::FrontCarry => "front_carry",
            SandbagExerciseName::FrontSquat => "front_squat",
            SandbagExerciseName::Lunge => "lunge",
            SandbagExerciseName::OverheadPress => "overhead_press",
            SandbagExerciseName::PlankPullThrough => "plank_pull_through",
            SandbagExerciseName::RotationalLunge => "rotational_lunge",
            SandbagExerciseName::Row => "row",
            SandbagExerciseName::RussianTwist => "russian_twist",
            SandbagExerciseName::Shouldering => "shouldering",
            SandbagExerciseName::Shoveling => "shoveling",
            SandbagExerciseName::SideLunge => "side_lunge",
            SandbagExerciseName::Sprint => "sprint",
            SandbagExerciseName::ZercherSquat => "zercher_squat",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(SandbagExerciseName::AroundTheWorld),
            1 => Some(SandbagExerciseName::BackSquat),
            2 => Some(SandbagExerciseName::BearCrawlPullThrough),
            3 => Some(SandbagExerciseName::BearHugSquat),
            4 => Some(SandbagExerciseName::Clean),
            5 => Some(SandbagExerciseName::CleanAndPress),
            6 => Some(SandbagExerciseName::Curl),
            7 => Some(SandbagExerciseName::FrontCarry),
            8 => Some(SandbagExerciseName::FrontSquat),
            9 => Some(SandbagExerciseName::Lunge),
            10 => Some(SandbagExerciseName::OverheadPress),
            11 => Some(SandbagExerciseName::PlankPullThrough),
            12 => Some(SandbagExerciseName::RotationalLunge),
            13 => Some(SandbagExerciseName::Row),
            14 => Some(SandbagExerciseName::RussianTwist),
            15 => Some(SandbagExerciseName::Shouldering),
            16 => Some(SandbagExerciseName::Shoveling),
            17 => Some(SandbagExerciseName::SideLunge),
            18 => Some(SandbagExerciseName::Sprint),
            19 => Some(SandbagExerciseName::ZercherSquat),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "around_the_world" => Some(SandbagExerciseName::AroundTheWorld),
            "back_squat" => Some(SandbagExerciseName::BackSquat),
            "bear_crawl_pull_through" => Some(SandbagExerciseName::BearCrawlPullThrough),
            "bear_hug_squat" => Some(SandbagExerciseName::BearHugSquat),
            "clean" => Some(SandbagExerciseName::Clean),
            "clean_and_press" => Some(SandbagExerciseName::CleanAndPress),
            "curl" => Some(SandbagExerciseName::Curl),
            "front_carry" => Some(SandbagExerciseName::FrontCarry),
            "front_squat" => Some(SandbagExerciseName::FrontSquat),
            "lunge" => Some(SandbagExerciseName::Lunge),
            "overhead_press" => Some(SandbagExerciseName::OverheadPress),
            "plank_pull_through" => Some(SandbagExerciseName::PlankPullThrough),
            "rotational_lunge" => Some(SandbagExerciseName::RotationalLunge),
            "row" => Some(SandbagExerciseName::Row),
            "russian_twist" => Some(SandbagExerciseName::RussianTwist),
            "shouldering" => Some(SandbagExerciseName::Shouldering),
            "shoveling" => Some(SandbagExerciseName::Shoveling),
            "side_lunge" => Some(SandbagExerciseName::SideLunge),
            "sprint" => Some(SandbagExerciseName::Sprint),
            "zercher_squat" => Some(SandbagExerciseName::ZercherSquat),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum SledExerciseName {
    BackwardDrag = 0,
    ChestPress = 1,
    ForwardDrag = 2,
    LowPush = 3,
    Push = 4,
    Row = 5,
}

impl SledExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            SledExerciseName::BackwardDrag => "backward_drag",
            SledExerciseName::ChestPress => "chest_press",
            SledExerciseName::ForwardDrag => "forward_drag",
            SledExerciseName::LowPush => "low_push",
            SledExerciseName::Push => "push",
            SledExerciseName::Row => "row",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(SledExerciseName::BackwardDrag),
            1 => Some(SledExerciseName::ChestPress),
            2 => Some(SledExerciseName::ForwardDrag),
            3 => Some(SledExerciseName::LowPush),
            4 => Some(SledExerciseName::Push),
            5 => Some(SledExerciseName::Row),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "backward_drag" => Some(SledExerciseName::BackwardDrag),
            "chest_press" => Some(SledExerciseName::ChestPress),
            "forward_drag" => Some(SledExerciseName::ForwardDrag),
            "low_push" => Some(SledExerciseName::LowPush),
            "push" => Some(SledExerciseName::Push),
            "row" => Some(SledExerciseName::Row),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum SledgeHammerExerciseName {
    LateralSwing = 0,
    HammerSlam = 1,
}

impl SledgeHammerExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            SledgeHammerExerciseName::LateralSwing => "lateral_swing",
            SledgeHammerExerciseName::HammerSlam => "hammer_slam",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(SledgeHammerExerciseName::LateralSwing),
            1 => Some(SledgeHammerExerciseName::HammerSlam),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "lateral_swing" => Some(SledgeHammerExerciseName::LateralSwing),
            "hammer_slam" => Some(SledgeHammerExerciseName::HammerSlam),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum StairStepperExerciseName {
    StairStepper = 0,
}

impl StairStepperExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            StairStepperExerciseName::StairStepper => "stair_stepper",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(StairStepperExerciseName::StairStepper),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "stair_stepper" => Some(StairStepperExerciseName::StairStepper),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum SuspensionExerciseName {
    ChestFly = 0,
    ChestPress = 1,
    Crunch = 2,
    Curl = 3,
    Dip = 4,
    FacePull = 5,
    GluteBridge = 6,
    HamstringCurl = 7,
    HipDrop = 8,
    InvertedRow = 9,
    KneeDriveJump = 10,
    KneeToChest = 11,
    LatPullover = 12,
    Lunge = 13,
    MountainClimber = 14,
    Pendulum = 15,
    Pike = 16,
    Plank = 17,
    PowerPull = 18,
    PullUp = 19,
    PushUp = 20,
    ReverseMountainClimber = 21,
    ReversePlank = 22,
    Rollout = 23,
    Row = 24,
    SideLunge = 25,
    SidePlank = 26,
    SingleLegDeadlift = 27,
    SingleLegSquat = 28,
    SitUp = 29,
    Split = 30,
    Squat = 31,
    SquatJump = 32,
    TricepPress = 33,
    YFly = 34,
}

impl SuspensionExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            SuspensionExerciseName::ChestFly => "chest_fly",
            SuspensionExerciseName::ChestPress => "chest_press",
            SuspensionExerciseName::Crunch => "crunch",
            SuspensionExerciseName::Curl => "curl",
            SuspensionExerciseName::Dip => "dip",
            SuspensionExerciseName::FacePull => "face_pull",
            SuspensionExerciseName::GluteBridge => "glute_bridge",
            SuspensionExerciseName::HamstringCurl => "hamstring_curl",
            SuspensionExerciseName::HipDrop => "hip_drop",
            SuspensionExerciseName::InvertedRow => "inverted_row",
            SuspensionExerciseName::KneeDriveJump => "knee_drive_jump",
            SuspensionExerciseName::KneeToChest => "knee_to_chest",
            SuspensionExerciseName::LatPullover => "lat_pullover",
            SuspensionExerciseName::Lunge => "lunge",
            SuspensionExerciseName::MountainClimber => "mountain_climber",
            SuspensionExerciseName::Pendulum => "pendulum",
            SuspensionExerciseName::Pike => "pike",
            SuspensionExerciseName::Plank => "plank",
            SuspensionExerciseName::PowerPull => "power_pull",
            SuspensionExerciseName::PullUp => "pull_up",
            SuspensionExerciseName::PushUp => "push_up",
            SuspensionExerciseName::ReverseMountainClimber => "reverse_mountain_climber",
            SuspensionExerciseName::ReversePlank => "reverse_plank",
            SuspensionExerciseName::Rollout => "rollout",
            SuspensionExerciseName::Row => "row",
            SuspensionExerciseName::SideLunge => "side_lunge",
            SuspensionExerciseName::SidePlank => "side_plank",
            SuspensionExerciseName::SingleLegDeadlift => "single_leg_deadlift",
            SuspensionExerciseName::SingleLegSquat => "single_leg_squat",
            SuspensionExerciseName::SitUp => "sit_up",
            SuspensionExerciseName::Split => "split",
            SuspensionExerciseName::Squat => "squat",
            SuspensionExerciseName::SquatJump => "squat_jump",
            SuspensionExerciseName::TricepPress => "tricep_press",
            SuspensionExerciseName::YFly => "y_fly",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(SuspensionExerciseName::ChestFly),
            1 => Some(SuspensionExerciseName::ChestPress),
            2 => Some(SuspensionExerciseName::Crunch),
            3 => Some(SuspensionExerciseName::Curl),
            4 => Some(SuspensionExerciseName::Dip),
            5 => Some(SuspensionExerciseName::FacePull),
            6 => Some(SuspensionExerciseName::GluteBridge),
            7 => Some(SuspensionExerciseName::HamstringCurl),
            8 => Some(SuspensionExerciseName::HipDrop),
            9 => Some(SuspensionExerciseName::InvertedRow),
            10 => Some(SuspensionExerciseName::KneeDriveJump),
            11 => Some(SuspensionExerciseName::KneeToChest),
            12 => Some(SuspensionExerciseName::LatPullover),
            13 => Some(SuspensionExerciseName::Lunge),
            14 => Some(SuspensionExerciseName::MountainClimber),
            15 => Some(SuspensionExerciseName::Pendulum),
            16 => Some(SuspensionExerciseName::Pike),
            17 => Some(SuspensionExerciseName::Plank),
            18 => Some(SuspensionExerciseName::PowerPull),
            19 => Some(SuspensionExerciseName::PullUp),
            20 => Some(SuspensionExerciseName::PushUp),
            21 => Some(SuspensionExerciseName::ReverseMountainClimber),
            22 => Some(SuspensionExerciseName::ReversePlank),
            23 => Some(SuspensionExerciseName::Rollout),
            24 => Some(SuspensionExerciseName::Row),
            25 => Some(SuspensionExerciseName::SideLunge),
            26 => Some(SuspensionExerciseName::SidePlank),
            27 => Some(SuspensionExerciseName::SingleLegDeadlift),
            28 => Some(SuspensionExerciseName::SingleLegSquat),
            29 => Some(SuspensionExerciseName::SitUp),
            30 => Some(SuspensionExerciseName::Split),
            31 => Some(SuspensionExerciseName::Squat),
            32 => Some(SuspensionExerciseName::SquatJump),
            33 => Some(SuspensionExerciseName::TricepPress),
            34 => Some(SuspensionExerciseName::YFly),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "chest_fly" => Some(SuspensionExerciseName::ChestFly),
            "chest_press" => Some(SuspensionExerciseName::ChestPress),
            "crunch" => Some(SuspensionExerciseName::Crunch),
            "curl" => Some(SuspensionExerciseName::Curl),
            "dip" => Some(SuspensionExerciseName::Dip),
            "face_pull" => Some(SuspensionExerciseName::FacePull),
            "glute_bridge" => Some(SuspensionExerciseName::GluteBridge),
            "hamstring_curl" => Some(SuspensionExerciseName::HamstringCurl),
            "hip_drop" => Some(SuspensionExerciseName::HipDrop),
            "inverted_row" => Some(SuspensionExerciseName::InvertedRow),
            "knee_drive_jump" => Some(SuspensionExerciseName::KneeDriveJump),
            "knee_to_chest" => Some(SuspensionExerciseName::KneeToChest),
            "lat_pullover" => Some(SuspensionExerciseName::LatPullover),
            "lunge" => Some(SuspensionExerciseName::Lunge),
            "mountain_climber" => Some(SuspensionExerciseName::MountainClimber),
            "pendulum" => Some(SuspensionExerciseName::Pendulum),
            "pike" => Some(SuspensionExerciseName::Pike),
            "plank" => Some(SuspensionExerciseName::Plank),
            "power_pull" => Some(SuspensionExerciseName::PowerPull),
            "pull_up" => Some(SuspensionExerciseName::PullUp),
            "push_up" => Some(SuspensionExerciseName::PushUp),
            "reverse_mountain_climber" => Some(SuspensionExerciseName::ReverseMountainClimber),
            "reverse_plank" => Some(SuspensionExerciseName::ReversePlank),
            "rollout" => Some(SuspensionExerciseName::Rollout),
            "row" => Some(SuspensionExerciseName::Row),
            "side_lunge" => Some(SuspensionExerciseName::SideLunge),
            "side_plank" => Some(SuspensionExerciseName::SidePlank),
            "single_leg_deadlift" => Some(SuspensionExerciseName::SingleLegDeadlift),
            "single_leg_squat" => Some(SuspensionExerciseName::SingleLegSquat),
            "sit_up" => Some(SuspensionExerciseName::SitUp),
            "split" => Some(SuspensionExerciseName::Split),
            "squat" => Some(SuspensionExerciseName::Squat),
            "squat_jump" => Some(SuspensionExerciseName::SquatJump),
            "tricep_press" => Some(SuspensionExerciseName::TricepPress),
            "y_fly" => Some(SuspensionExerciseName::YFly),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum TireExerciseName {
    Flip = 0,
}

impl TireExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            TireExerciseName::Flip => "flip",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(TireExerciseName::Flip),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "flip" => Some(TireExerciseName::Flip),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum BikeOutdoorExerciseName {
    Bike = 0,
}

impl BikeOutdoorExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            BikeOutdoorExerciseName::Bike => "bike",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(BikeOutdoorExerciseName::Bike),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "bike" => Some(BikeOutdoorExerciseName::Bike),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum RunIndoorExerciseName {
    IndoorTrackRun = 0,
    Treadmill = 1,
}

impl RunIndoorExerciseName {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            RunIndoorExerciseName::IndoorTrackRun => "indoor_track_run",
            RunIndoorExerciseName::Treadmill => "treadmill",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            0 => Some(RunIndoorExerciseName::IndoorTrackRun),
            1 => Some(RunIndoorExerciseName::Treadmill),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "indoor_track_run" => Some(RunIndoorExerciseName::IndoorTrackRun),
            "treadmill" => Some(RunIndoorExerciseName::Treadmill),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum WaterType {
    Fresh = 0,
    Salt = 1,
    En13319 = 2,
    Custom = 3,
}

impl WaterType {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            WaterType::Fresh => "fresh",
            WaterType::Salt => "salt",
            WaterType::En13319 => "en13319",
            WaterType::Custom => "custom",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(WaterType::Fresh),
            1 => Some(WaterType::Salt),
            2 => Some(WaterType::En13319),
            3 => Some(WaterType::Custom),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "fresh" => Some(WaterType::Fresh),
            "salt" => Some(WaterType::Salt),
            "en13319" => Some(WaterType::En13319),
            "custom" => Some(WaterType::Custom),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum TissueModelType {
    Zhl16c = 0,
}

impl TissueModelType {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            TissueModelType::Zhl16c => "zhl_16c",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(TissueModelType::Zhl16c),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "zhl_16c" => Some(TissueModelType::Zhl16c),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum DiveGasStatus {
    Disabled = 0,
    Enabled = 1,
    BackupOnly = 2,
}

impl DiveGasStatus {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            DiveGasStatus::Disabled => "disabled",
            DiveGasStatus::Enabled => "enabled",
            DiveGasStatus::BackupOnly => "backup_only",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(DiveGasStatus::Disabled),
            1 => Some(DiveGasStatus::Enabled),
            2 => Some(DiveGasStatus::BackupOnly),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "disabled" => Some(DiveGasStatus::Disabled),
            "enabled" => Some(DiveGasStatus::Enabled),
            "backup_only" => Some(DiveGasStatus::BackupOnly),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum DiveAlert {
    NdlReached = 0,
    GasSwitchPrompted = 1,
    NearSurface = 2,
    ApproachingNdl = 3,
    Po2Warn = 4,
    Po2CritHigh = 5,
    Po2CritLow = 6,
    TimeAlert = 7,
    DepthAlert = 8,
    DecoCeilingBroken = 9,
    DecoComplete = 10,
    SafetyStopBroken = 11,
    SafetyStopComplete = 12,
    CnsWarning = 13,
    CnsCritical = 14,
    OtuWarning = 15,
    OtuCritical = 16,
    AscentCritical = 17,
    AlertDismissedByKey = 18,
    AlertDismissedByTimeout = 19,
    BatteryLow = 20,
    BatteryCritical = 21,
    SafetyStopStarted = 22,
    ApproachingFirstDecoStop = 23,
    SetpointSwitchAutoLow = 24,
    SetpointSwitchAutoHigh = 25,
    SetpointSwitchManualLow = 26,
    SetpointSwitchManualHigh = 27,
    AutoSetpointSwitchIgnored = 28,
    SwitchedToOpenCircuit = 29,
    SwitchedToClosedCircuit = 30,
    TankBatteryLow = 32,
    Po2CcrDilLow = 33,
    DecoStopCleared = 34,
    ApneaNeutralBuoyancy = 35,
    ApneaTargetDepth = 36,
    ApneaSurface = 37,
    ApneaHighSpeed = 38,
    ApneaLowSpeed = 39,
}

impl DiveAlert {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            DiveAlert::NdlReached => "ndl_reached",
            DiveAlert::GasSwitchPrompted => "gas_switch_prompted",
            DiveAlert::NearSurface => "near_surface",
            DiveAlert::ApproachingNdl => "approaching_ndl",
            DiveAlert::Po2Warn => "po2_warn",
            DiveAlert::Po2CritHigh => "po2_crit_high",
            DiveAlert::Po2CritLow => "po2_crit_low",
            DiveAlert::TimeAlert => "time_alert",
            DiveAlert::DepthAlert => "depth_alert",
            DiveAlert::DecoCeilingBroken => "deco_ceiling_broken",
            DiveAlert::DecoComplete => "deco_complete",
            DiveAlert::SafetyStopBroken => "safety_stop_broken",
            DiveAlert::SafetyStopComplete => "safety_stop_complete",
            DiveAlert::CnsWarning => "cns_warning",
            DiveAlert::CnsCritical => "cns_critical",
            DiveAlert::OtuWarning => "otu_warning",
            DiveAlert::OtuCritical => "otu_critical",
            DiveAlert::AscentCritical => "ascent_critical",
            DiveAlert::AlertDismissedByKey => "alert_dismissed_by_key",
            DiveAlert::AlertDismissedByTimeout => "alert_dismissed_by_timeout",
            DiveAlert::BatteryLow => "battery_low",
            DiveAlert::BatteryCritical => "battery_critical",
            DiveAlert::SafetyStopStarted => "safety_stop_started",
            DiveAlert::ApproachingFirstDecoStop => "approaching_first_deco_stop",
            DiveAlert::SetpointSwitchAutoLow => "setpoint_switch_auto_low",
            DiveAlert::SetpointSwitchAutoHigh => "setpoint_switch_auto_high",
            DiveAlert::SetpointSwitchManualLow => "setpoint_switch_manual_low",
            DiveAlert::SetpointSwitchManualHigh => "setpoint_switch_manual_high",
            DiveAlert::AutoSetpointSwitchIgnored => "auto_setpoint_switch_ignored",
            DiveAlert::SwitchedToOpenCircuit => "switched_to_open_circuit",
            DiveAlert::SwitchedToClosedCircuit => "switched_to_closed_circuit",
            DiveAlert::TankBatteryLow => "tank_battery_low",
            DiveAlert::Po2CcrDilLow => "po2_ccr_dil_low",
            DiveAlert::DecoStopCleared => "deco_stop_cleared",
            DiveAlert::ApneaNeutralBuoyancy => "apnea_neutral_buoyancy",
            DiveAlert::ApneaTargetDepth => "apnea_target_depth",
            DiveAlert::ApneaSurface => "apnea_surface",
            DiveAlert::ApneaHighSpeed => "apnea_high_speed",
            DiveAlert::ApneaLowSpeed => "apnea_low_speed",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(DiveAlert::NdlReached),
            1 => Some(DiveAlert::GasSwitchPrompted),
            2 => Some(DiveAlert::NearSurface),
            3 => Some(DiveAlert::ApproachingNdl),
            4 => Some(DiveAlert::Po2Warn),
            5 => Some(DiveAlert::Po2CritHigh),
            6 => Some(DiveAlert::Po2CritLow),
            7 => Some(DiveAlert::TimeAlert),
            8 => Some(DiveAlert::DepthAlert),
            9 => Some(DiveAlert::DecoCeilingBroken),
            10 => Some(DiveAlert::DecoComplete),
            11 => Some(DiveAlert::SafetyStopBroken),
            12 => Some(DiveAlert::SafetyStopComplete),
            13 => Some(DiveAlert::CnsWarning),
            14 => Some(DiveAlert::CnsCritical),
            15 => Some(DiveAlert::OtuWarning),
            16 => Some(DiveAlert::OtuCritical),
            17 => Some(DiveAlert::AscentCritical),
            18 => Some(DiveAlert::AlertDismissedByKey),
            19 => Some(DiveAlert::AlertDismissedByTimeout),
            20 => Some(DiveAlert::BatteryLow),
            21 => Some(DiveAlert::BatteryCritical),
            22 => Some(DiveAlert::SafetyStopStarted),
            23 => Some(DiveAlert::ApproachingFirstDecoStop),
            24 => Some(DiveAlert::SetpointSwitchAutoLow),
            25 => Some(DiveAlert::SetpointSwitchAutoHigh),
            26 => Some(DiveAlert::SetpointSwitchManualLow),
            27 => Some(DiveAlert::SetpointSwitchManualHigh),
            28 => Some(DiveAlert::AutoSetpointSwitchIgnored),
            29 => Some(DiveAlert::SwitchedToOpenCircuit),
            30 => Some(DiveAlert::SwitchedToClosedCircuit),
            32 => Some(DiveAlert::TankBatteryLow),
            33 => Some(DiveAlert::Po2CcrDilLow),
            34 => Some(DiveAlert::DecoStopCleared),
            35 => Some(DiveAlert::ApneaNeutralBuoyancy),
            36 => Some(DiveAlert::ApneaTargetDepth),
            37 => Some(DiveAlert::ApneaSurface),
            38 => Some(DiveAlert::ApneaHighSpeed),
            39 => Some(DiveAlert::ApneaLowSpeed),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "ndl_reached" => Some(DiveAlert::NdlReached),
            "gas_switch_prompted" => Some(DiveAlert::GasSwitchPrompted),
            "near_surface" => Some(DiveAlert::NearSurface),
            "approaching_ndl" => Some(DiveAlert::ApproachingNdl),
            "po2_warn" => Some(DiveAlert::Po2Warn),
            "po2_crit_high" => Some(DiveAlert::Po2CritHigh),
            "po2_crit_low" => Some(DiveAlert::Po2CritLow),
            "time_alert" => Some(DiveAlert::TimeAlert),
            "depth_alert" => Some(DiveAlert::DepthAlert),
            "deco_ceiling_broken" => Some(DiveAlert::DecoCeilingBroken),
            "deco_complete" => Some(DiveAlert::DecoComplete),
            "safety_stop_broken" => Some(DiveAlert::SafetyStopBroken),
            "safety_stop_complete" => Some(DiveAlert::SafetyStopComplete),
            "cns_warning" => Some(DiveAlert::CnsWarning),
            "cns_critical" => Some(DiveAlert::CnsCritical),
            "otu_warning" => Some(DiveAlert::OtuWarning),
            "otu_critical" => Some(DiveAlert::OtuCritical),
            "ascent_critical" => Some(DiveAlert::AscentCritical),
            "alert_dismissed_by_key" => Some(DiveAlert::AlertDismissedByKey),
            "alert_dismissed_by_timeout" => Some(DiveAlert::AlertDismissedByTimeout),
            "battery_low" => Some(DiveAlert::BatteryLow),
            "battery_critical" => Some(DiveAlert::BatteryCritical),
            "safety_stop_started" => Some(DiveAlert::SafetyStopStarted),
            "approaching_first_deco_stop" => Some(DiveAlert::ApproachingFirstDecoStop),
            "setpoint_switch_auto_low" => Some(DiveAlert::SetpointSwitchAutoLow),
            "setpoint_switch_auto_high" => Some(DiveAlert::SetpointSwitchAutoHigh),
            "setpoint_switch_manual_low" => Some(DiveAlert::SetpointSwitchManualLow),
            "setpoint_switch_manual_high" => Some(DiveAlert::SetpointSwitchManualHigh),
            "auto_setpoint_switch_ignored" => Some(DiveAlert::AutoSetpointSwitchIgnored),
            "switched_to_open_circuit" => Some(DiveAlert::SwitchedToOpenCircuit),
            "switched_to_closed_circuit" => Some(DiveAlert::SwitchedToClosedCircuit),
            "tank_battery_low" => Some(DiveAlert::TankBatteryLow),
            "po2_ccr_dil_low" => Some(DiveAlert::Po2CcrDilLow),
            "deco_stop_cleared" => Some(DiveAlert::DecoStopCleared),
            "apnea_neutral_buoyancy" => Some(DiveAlert::ApneaNeutralBuoyancy),
            "apnea_target_depth" => Some(DiveAlert::ApneaTargetDepth),
            "apnea_surface" => Some(DiveAlert::ApneaSurface),
            "apnea_high_speed" => Some(DiveAlert::ApneaHighSpeed),
            "apnea_low_speed" => Some(DiveAlert::ApneaLowSpeed),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum DiveAlarmType {
    Depth = 0,
    Time = 1,
    Speed = 2,
}

impl DiveAlarmType {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            DiveAlarmType::Depth => "depth",
            DiveAlarmType::Time => "time",
            DiveAlarmType::Speed => "speed",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(DiveAlarmType::Depth),
            1 => Some(DiveAlarmType::Time),
            2 => Some(DiveAlarmType::Speed),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "depth" => Some(DiveAlarmType::Depth),
            "time" => Some(DiveAlarmType::Time),
            "speed" => Some(DiveAlarmType::Speed),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum DiveBacklightMode {
    AtDepth = 0,
    AlwaysOn = 1,
}

impl DiveBacklightMode {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            DiveBacklightMode::AtDepth => "at_depth",
            DiveBacklightMode::AlwaysOn => "always_on",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(DiveBacklightMode::AtDepth),
            1 => Some(DiveBacklightMode::AlwaysOn),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "at_depth" => Some(DiveBacklightMode::AtDepth),
            "always_on" => Some(DiveBacklightMode::AlwaysOn),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum SleepLevel {
    Unmeasurable = 0,
    Awake = 1,
    Light = 2,
    Deep = 3,
    Rem = 4,
}

impl SleepLevel {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            SleepLevel::Unmeasurable => "unmeasurable",
            SleepLevel::Awake => "awake",
            SleepLevel::Light => "light",
            SleepLevel::Deep => "deep",
            SleepLevel::Rem => "rem",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(SleepLevel::Unmeasurable),
            1 => Some(SleepLevel::Awake),
            2 => Some(SleepLevel::Light),
            3 => Some(SleepLevel::Deep),
            4 => Some(SleepLevel::Rem),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "unmeasurable" => Some(SleepLevel::Unmeasurable),
            "awake" => Some(SleepLevel::Awake),
            "light" => Some(SleepLevel::Light),
            "deep" => Some(SleepLevel::Deep),
            "rem" => Some(SleepLevel::Rem),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum Spo2MeasurementType {
    OffWrist = 0,
    SpotCheck = 1,
    ContinuousCheck = 2,
    Periodic = 3,
}

impl Spo2MeasurementType {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            Spo2MeasurementType::OffWrist => "off_wrist",
            Spo2MeasurementType::SpotCheck => "spot_check",
            Spo2MeasurementType::ContinuousCheck => "continuous_check",
            Spo2MeasurementType::Periodic => "periodic",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(Spo2MeasurementType::OffWrist),
            1 => Some(Spo2MeasurementType::SpotCheck),
            2 => Some(Spo2MeasurementType::ContinuousCheck),
            3 => Some(Spo2MeasurementType::Periodic),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "off_wrist" => Some(Spo2MeasurementType::OffWrist),
            "spot_check" => Some(Spo2MeasurementType::SpotCheck),
            "continuous_check" => Some(Spo2MeasurementType::ContinuousCheck),
            "periodic" => Some(Spo2MeasurementType::Periodic),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum CcrSetpointSwitchMode {
    Manual = 0,
    Automatic = 1,
}

impl CcrSetpointSwitchMode {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            CcrSetpointSwitchMode::Manual => "manual",
            CcrSetpointSwitchMode::Automatic => "automatic",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(CcrSetpointSwitchMode::Manual),
            1 => Some(CcrSetpointSwitchMode::Automatic),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "manual" => Some(CcrSetpointSwitchMode::Manual),
            "automatic" => Some(CcrSetpointSwitchMode::Automatic),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum DiveGasMode {
    OpenCircuit = 0,
    ClosedCircuitDiluent = 1,
}

impl DiveGasMode {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            DiveGasMode::OpenCircuit => "open_circuit",
            DiveGasMode::ClosedCircuitDiluent => "closed_circuit_diluent",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(DiveGasMode::OpenCircuit),
            1 => Some(DiveGasMode::ClosedCircuitDiluent),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "open_circuit" => Some(DiveGasMode::OpenCircuit),
            "closed_circuit_diluent" => Some(DiveGasMode::ClosedCircuitDiluent),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum ProjectileType {
    Arrow = 0,
    RifleCartridge = 1,
    PistolCartridge = 2,
    Shotshell = 3,
    AirRiflePellet = 4,
    Other = 5,
}

impl ProjectileType {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            ProjectileType::Arrow => "arrow",
            ProjectileType::RifleCartridge => "rifle_cartridge",
            ProjectileType::PistolCartridge => "pistol_cartridge",
            ProjectileType::Shotshell => "shotshell",
            ProjectileType::AirRiflePellet => "air_rifle_pellet",
            ProjectileType::Other => "other",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(ProjectileType::Arrow),
            1 => Some(ProjectileType::RifleCartridge),
            2 => Some(ProjectileType::PistolCartridge),
            3 => Some(ProjectileType::Shotshell),
            4 => Some(ProjectileType::AirRiflePellet),
            5 => Some(ProjectileType::Other),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "arrow" => Some(ProjectileType::Arrow),
            "rifle_cartridge" => Some(ProjectileType::RifleCartridge),
            "pistol_cartridge" => Some(ProjectileType::PistolCartridge),
            "shotshell" => Some(ProjectileType::Shotshell),
            "air_rifle_pellet" => Some(ProjectileType::AirRiflePellet),
            "other" => Some(ProjectileType::Other),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u16)]
#[non_exhaustive]
pub enum FaveroProduct {
    AssiomaUno = 10,
    AssiomaDuo = 12,
}

impl FaveroProduct {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            FaveroProduct::AssiomaUno => "assioma_uno",
            FaveroProduct::AssiomaDuo => "assioma_duo",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u16) -> Option<Self> {
        match value {
            10 => Some(FaveroProduct::AssiomaUno),
            12 => Some(FaveroProduct::AssiomaDuo),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "assioma_uno" => Some(FaveroProduct::AssiomaUno),
            "assioma_duo" => Some(FaveroProduct::AssiomaDuo),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum SplitType {
    AscentSplit = 1,
    DescentSplit = 2,
    IntervalActive = 3,
    IntervalRest = 4,
    IntervalWarmup = 5,
    IntervalCooldown = 6,
    IntervalRecovery = 7,
    IntervalOther = 8,
    ClimbActive = 9,
    ClimbRest = 10,
    SurfActive = 11,
    RunActive = 12,
    RunRest = 13,
    WorkoutRound = 14,
    RwdRun = 17,
    RwdWalk = 18,
    WindsurfActive = 21,
    RwdStand = 22,
    Transition = 23,
    SkiLiftSplit = 28,
    SkiRunSplit = 29,
}

impl SplitType {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            SplitType::AscentSplit => "ascent_split",
            SplitType::DescentSplit => "descent_split",
            SplitType::IntervalActive => "interval_active",
            SplitType::IntervalRest => "interval_rest",
            SplitType::IntervalWarmup => "interval_warmup",
            SplitType::IntervalCooldown => "interval_cooldown",
            SplitType::IntervalRecovery => "interval_recovery",
            SplitType::IntervalOther => "interval_other",
            SplitType::ClimbActive => "climb_active",
            SplitType::ClimbRest => "climb_rest",
            SplitType::SurfActive => "surf_active",
            SplitType::RunActive => "run_active",
            SplitType::RunRest => "run_rest",
            SplitType::WorkoutRound => "workout_round",
            SplitType::RwdRun => "rwd_run",
            SplitType::RwdWalk => "rwd_walk",
            SplitType::WindsurfActive => "windsurf_active",
            SplitType::RwdStand => "rwd_stand",
            SplitType::Transition => "transition",
            SplitType::SkiLiftSplit => "ski_lift_split",
            SplitType::SkiRunSplit => "ski_run_split",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            1 => Some(SplitType::AscentSplit),
            2 => Some(SplitType::DescentSplit),
            3 => Some(SplitType::IntervalActive),
            4 => Some(SplitType::IntervalRest),
            5 => Some(SplitType::IntervalWarmup),
            6 => Some(SplitType::IntervalCooldown),
            7 => Some(SplitType::IntervalRecovery),
            8 => Some(SplitType::IntervalOther),
            9 => Some(SplitType::ClimbActive),
            10 => Some(SplitType::ClimbRest),
            11 => Some(SplitType::SurfActive),
            12 => Some(SplitType::RunActive),
            13 => Some(SplitType::RunRest),
            14 => Some(SplitType::WorkoutRound),
            17 => Some(SplitType::RwdRun),
            18 => Some(SplitType::RwdWalk),
            21 => Some(SplitType::WindsurfActive),
            22 => Some(SplitType::RwdStand),
            23 => Some(SplitType::Transition),
            28 => Some(SplitType::SkiLiftSplit),
            29 => Some(SplitType::SkiRunSplit),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "ascent_split" => Some(SplitType::AscentSplit),
            "descent_split" => Some(SplitType::DescentSplit),
            "interval_active" => Some(SplitType::IntervalActive),
            "interval_rest" => Some(SplitType::IntervalRest),
            "interval_warmup" => Some(SplitType::IntervalWarmup),
            "interval_cooldown" => Some(SplitType::IntervalCooldown),
            "interval_recovery" => Some(SplitType::IntervalRecovery),
            "interval_other" => Some(SplitType::IntervalOther),
            "climb_active" => Some(SplitType::ClimbActive),
            "climb_rest" => Some(SplitType::ClimbRest),
            "surf_active" => Some(SplitType::SurfActive),
            "run_active" => Some(SplitType::RunActive),
            "run_rest" => Some(SplitType::RunRest),
            "workout_round" => Some(SplitType::WorkoutRound),
            "rwd_run" => Some(SplitType::RwdRun),
            "rwd_walk" => Some(SplitType::RwdWalk),
            "windsurf_active" => Some(SplitType::WindsurfActive),
            "rwd_stand" => Some(SplitType::RwdStand),
            "transition" => Some(SplitType::Transition),
            "ski_lift_split" => Some(SplitType::SkiLiftSplit),
            "ski_run_split" => Some(SplitType::SkiRunSplit),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum ClimbProEvent {
    Approach = 0,
    Start = 1,
    Complete = 2,
}

impl ClimbProEvent {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            ClimbProEvent::Approach => "approach",
            ClimbProEvent::Start => "start",
            ClimbProEvent::Complete => "complete",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(ClimbProEvent::Approach),
            1 => Some(ClimbProEvent::Start),
            2 => Some(ClimbProEvent::Complete),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "approach" => Some(ClimbProEvent::Approach),
            "start" => Some(ClimbProEvent::Start),
            "complete" => Some(ClimbProEvent::Complete),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum GasConsumptionRateType {
    PressureSac = 0,
    VolumeSac = 1,
    Rmv = 2,
}

impl GasConsumptionRateType {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            GasConsumptionRateType::PressureSac => "pressure_sac",
            GasConsumptionRateType::VolumeSac => "volume_sac",
            GasConsumptionRateType::Rmv => "rmv",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(GasConsumptionRateType::PressureSac),
            1 => Some(GasConsumptionRateType::VolumeSac),
            2 => Some(GasConsumptionRateType::Rmv),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "pressure_sac" => Some(GasConsumptionRateType::PressureSac),
            "volume_sac" => Some(GasConsumptionRateType::VolumeSac),
            "rmv" => Some(GasConsumptionRateType::Rmv),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum TapSensitivity {
    High = 0,
    Medium = 1,
    Low = 2,
}

impl TapSensitivity {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            TapSensitivity::High => "high",
            TapSensitivity::Medium => "medium",
            TapSensitivity::Low => "low",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(TapSensitivity::High),
            1 => Some(TapSensitivity::Medium),
            2 => Some(TapSensitivity::Low),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "high" => Some(TapSensitivity::High),
            "medium" => Some(TapSensitivity::Medium),
            "low" => Some(TapSensitivity::Low),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum RadarThreatLevelType {
    ThreatUnknown = 0,
    ThreatNone = 1,
    ThreatApproaching = 2,
    ThreatApproachingFast = 3,
}

impl RadarThreatLevelType {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            RadarThreatLevelType::ThreatUnknown => "threat_unknown",
            RadarThreatLevelType::ThreatNone => "threat_none",
            RadarThreatLevelType::ThreatApproaching => "threat_approaching",
            RadarThreatLevelType::ThreatApproachingFast => "threat_approaching_fast",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(RadarThreatLevelType::ThreatUnknown),
            1 => Some(RadarThreatLevelType::ThreatNone),
            2 => Some(RadarThreatLevelType::ThreatApproaching),
            3 => Some(RadarThreatLevelType::ThreatApproachingFast),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "threat_unknown" => Some(RadarThreatLevelType::ThreatUnknown),
            "threat_none" => Some(RadarThreatLevelType::ThreatNone),
            "threat_approaching" => Some(RadarThreatLevelType::ThreatApproaching),
            "threat_approaching_fast" => Some(RadarThreatLevelType::ThreatApproachingFast),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum SleepDisruptionSeverity {
    None = 0,
    Low = 1,
    Medium = 2,
    High = 3,
}

impl SleepDisruptionSeverity {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            SleepDisruptionSeverity::None => "none",
            SleepDisruptionSeverity::Low => "low",
            SleepDisruptionSeverity::Medium => "medium",
            SleepDisruptionSeverity::High => "high",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(SleepDisruptionSeverity::None),
            1 => Some(SleepDisruptionSeverity::Low),
            2 => Some(SleepDisruptionSeverity::Medium),
            3 => Some(SleepDisruptionSeverity::High),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "none" => Some(SleepDisruptionSeverity::None),
            "low" => Some(SleepDisruptionSeverity::Low),
            "medium" => Some(SleepDisruptionSeverity::Medium),
            "high" => Some(SleepDisruptionSeverity::High),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum NapPeriodFeedback {
    None = 0,
    MultipleNapsDuringDay = 1,
    JetlagIdealTimingIdealDuration = 2,
    JetlagIdealTimingLongDuration = 3,
    JetlagLateTimingIdealDuration = 4,
    JetlagLateTimingLongDuration = 5,
    IdealTimingIdealDurationLowNeed = 6,
    IdealTimingIdealDurationHighNeed = 7,
    IdealTimingLongDurationLowNeed = 8,
    IdealTimingLongDurationHighNeed = 9,
    LateTimingIdealDurationLowNeed = 10,
    LateTimingIdealDurationHighNeed = 11,
    LateTimingLongDurationLowNeed = 12,
    LateTimingLongDurationHighNeed = 13,
    IdealDurationLowNeed = 14,
    IdealDurationHighNeed = 15,
    LongDurationLowNeed = 16,
    LongDurationHighNeed = 17,
}

impl NapPeriodFeedback {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            NapPeriodFeedback::None => "none",
            NapPeriodFeedback::MultipleNapsDuringDay => "multiple_naps_during_day",
            NapPeriodFeedback::JetlagIdealTimingIdealDuration => {
                "jetlag_ideal_timing_ideal_duration"
            }
            NapPeriodFeedback::JetlagIdealTimingLongDuration => "jetlag_ideal_timing_long_duration",
            NapPeriodFeedback::JetlagLateTimingIdealDuration => "jetlag_late_timing_ideal_duration",
            NapPeriodFeedback::JetlagLateTimingLongDuration => "jetlag_late_timing_long_duration",
            NapPeriodFeedback::IdealTimingIdealDurationLowNeed => {
                "ideal_timing_ideal_duration_low_need"
            }
            NapPeriodFeedback::IdealTimingIdealDurationHighNeed => {
                "ideal_timing_ideal_duration_high_need"
            }
            NapPeriodFeedback::IdealTimingLongDurationLowNeed => {
                "ideal_timing_long_duration_low_need"
            }
            NapPeriodFeedback::IdealTimingLongDurationHighNeed => {
                "ideal_timing_long_duration_high_need"
            }
            NapPeriodFeedback::LateTimingIdealDurationLowNeed => {
                "late_timing_ideal_duration_low_need"
            }
            NapPeriodFeedback::LateTimingIdealDurationHighNeed => {
                "late_timing_ideal_duration_high_need"
            }
            NapPeriodFeedback::LateTimingLongDurationLowNeed => {
                "late_timing_long_duration_low_need"
            }
            NapPeriodFeedback::LateTimingLongDurationHighNeed => {
                "late_timing_long_duration_high_need"
            }
            NapPeriodFeedback::IdealDurationLowNeed => "ideal_duration_low_need",
            NapPeriodFeedback::IdealDurationHighNeed => "ideal_duration_high_need",
            NapPeriodFeedback::LongDurationLowNeed => "long_duration_low_need",
            NapPeriodFeedback::LongDurationHighNeed => "long_duration_high_need",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(NapPeriodFeedback::None),
            1 => Some(NapPeriodFeedback::MultipleNapsDuringDay),
            2 => Some(NapPeriodFeedback::JetlagIdealTimingIdealDuration),
            3 => Some(NapPeriodFeedback::JetlagIdealTimingLongDuration),
            4 => Some(NapPeriodFeedback::JetlagLateTimingIdealDuration),
            5 => Some(NapPeriodFeedback::JetlagLateTimingLongDuration),
            6 => Some(NapPeriodFeedback::IdealTimingIdealDurationLowNeed),
            7 => Some(NapPeriodFeedback::IdealTimingIdealDurationHighNeed),
            8 => Some(NapPeriodFeedback::IdealTimingLongDurationLowNeed),
            9 => Some(NapPeriodFeedback::IdealTimingLongDurationHighNeed),
            10 => Some(NapPeriodFeedback::LateTimingIdealDurationLowNeed),
            11 => Some(NapPeriodFeedback::LateTimingIdealDurationHighNeed),
            12 => Some(NapPeriodFeedback::LateTimingLongDurationLowNeed),
            13 => Some(NapPeriodFeedback::LateTimingLongDurationHighNeed),
            14 => Some(NapPeriodFeedback::IdealDurationLowNeed),
            15 => Some(NapPeriodFeedback::IdealDurationHighNeed),
            16 => Some(NapPeriodFeedback::LongDurationLowNeed),
            17 => Some(NapPeriodFeedback::LongDurationHighNeed),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "none" => Some(NapPeriodFeedback::None),
            "multiple_naps_during_day" => Some(NapPeriodFeedback::MultipleNapsDuringDay),
            "jetlag_ideal_timing_ideal_duration" => {
                Some(NapPeriodFeedback::JetlagIdealTimingIdealDuration)
            }
            "jetlag_ideal_timing_long_duration" => {
                Some(NapPeriodFeedback::JetlagIdealTimingLongDuration)
            }
            "jetlag_late_timing_ideal_duration" => {
                Some(NapPeriodFeedback::JetlagLateTimingIdealDuration)
            }
            "jetlag_late_timing_long_duration" => {
                Some(NapPeriodFeedback::JetlagLateTimingLongDuration)
            }
            "ideal_timing_ideal_duration_low_need" => {
                Some(NapPeriodFeedback::IdealTimingIdealDurationLowNeed)
            }
            "ideal_timing_ideal_duration_high_need" => {
                Some(NapPeriodFeedback::IdealTimingIdealDurationHighNeed)
            }
            "ideal_timing_long_duration_low_need" => {
                Some(NapPeriodFeedback::IdealTimingLongDurationLowNeed)
            }
            "ideal_timing_long_duration_high_need" => {
                Some(NapPeriodFeedback::IdealTimingLongDurationHighNeed)
            }
            "late_timing_ideal_duration_low_need" => {
                Some(NapPeriodFeedback::LateTimingIdealDurationLowNeed)
            }
            "late_timing_ideal_duration_high_need" => {
                Some(NapPeriodFeedback::LateTimingIdealDurationHighNeed)
            }
            "late_timing_long_duration_low_need" => {
                Some(NapPeriodFeedback::LateTimingLongDurationLowNeed)
            }
            "late_timing_long_duration_high_need" => {
                Some(NapPeriodFeedback::LateTimingLongDurationHighNeed)
            }
            "ideal_duration_low_need" => Some(NapPeriodFeedback::IdealDurationLowNeed),
            "ideal_duration_high_need" => Some(NapPeriodFeedback::IdealDurationHighNeed),
            "long_duration_low_need" => Some(NapPeriodFeedback::LongDurationLowNeed),
            "long_duration_high_need" => Some(NapPeriodFeedback::LongDurationHighNeed),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum NapSource {
    Automatic = 0,
    ManualDevice = 1,
    ManualGc = 2,
}

impl NapSource {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            NapSource::Automatic => "automatic",
            NapSource::ManualDevice => "manual_device",
            NapSource::ManualGc => "manual_gc",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(NapSource::Automatic),
            1 => Some(NapSource::ManualDevice),
            2 => Some(NapSource::ManualGc),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "automatic" => Some(NapSource::Automatic),
            "manual_device" => Some(NapSource::ManualDevice),
            "manual_gc" => Some(NapSource::ManualGc),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum MaxMetSpeedSource {
    OnboardGps = 0,
    ConnectedGps = 1,
    Cadence = 2,
}

impl MaxMetSpeedSource {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            MaxMetSpeedSource::OnboardGps => "onboard_gps",
            MaxMetSpeedSource::ConnectedGps => "connected_gps",
            MaxMetSpeedSource::Cadence => "cadence",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(MaxMetSpeedSource::OnboardGps),
            1 => Some(MaxMetSpeedSource::ConnectedGps),
            2 => Some(MaxMetSpeedSource::Cadence),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "onboard_gps" => Some(MaxMetSpeedSource::OnboardGps),
            "connected_gps" => Some(MaxMetSpeedSource::ConnectedGps),
            "cadence" => Some(MaxMetSpeedSource::Cadence),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum MaxMetHeartRateSource {
    Whr = 0,
    Hrm = 1,
}

impl MaxMetHeartRateSource {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            MaxMetHeartRateSource::Whr => "whr",
            MaxMetHeartRateSource::Hrm => "hrm",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(MaxMetHeartRateSource::Whr),
            1 => Some(MaxMetHeartRateSource::Hrm),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "whr" => Some(MaxMetHeartRateSource::Whr),
            "hrm" => Some(MaxMetHeartRateSource::Hrm),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum HrvStatus {
    None = 0,
    Poor = 1,
    Low = 2,
    Unbalanced = 3,
    Balanced = 4,
}

impl HrvStatus {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            HrvStatus::None => "none",
            HrvStatus::Poor => "poor",
            HrvStatus::Low => "low",
            HrvStatus::Unbalanced => "unbalanced",
            HrvStatus::Balanced => "balanced",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(HrvStatus::None),
            1 => Some(HrvStatus::Poor),
            2 => Some(HrvStatus::Low),
            3 => Some(HrvStatus::Unbalanced),
            4 => Some(HrvStatus::Balanced),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "none" => Some(HrvStatus::None),
            "poor" => Some(HrvStatus::Poor),
            "low" => Some(HrvStatus::Low),
            "unbalanced" => Some(HrvStatus::Unbalanced),
            "balanced" => Some(HrvStatus::Balanced),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum NoFlyTimeMode {
    Standard = 0,
    Flat24Hours = 1,
}

impl NoFlyTimeMode {
    /// Snake-case canonical name from Profile.xlsx.
    pub fn as_str(&self) -> &'static str {
        match self {
            NoFlyTimeMode::Standard => "standard",
            NoFlyTimeMode::Flat24Hours => "flat_24_hours",
        }
    }

    /// Try to construct from the underlying numeric value.
    pub fn from_value(value: u8) -> Option<Self> {
        match value {
            0 => Some(NoFlyTimeMode::Standard),
            1 => Some(NoFlyTimeMode::Flat24Hours),
            _ => None,
        }
    }

    /// Try to construct from the snake-case canonical name.
    pub fn from_str(name: &str) -> Option<Self> {
        match name {
            "standard" => Some(NoFlyTimeMode::Standard),
            "flat_24_hours" => Some(NoFlyTimeMode::Flat24Hours),
            _ => None,
        }
    }
}

/// Resolve the canonical snake_case name for `(type_name, value)`. Used by
/// the M5 transform pipeline when `convert_types_to_strings` is enabled.
pub fn enum_str_by_value(type_name: &str, value: u64) -> Option<&'static str> {
    match type_name {
        "mesg_num" => MesgNum::from_value(value as u16).map(|v| v.as_str()),
        "file" => File::from_value(value as u8).map(|v| v.as_str()),
        "checksum" => Checksum::from_value(value as u8).map(|v| v.as_str()),
        "file_flags" => FileFlags::from_value(value as u8).map(|v| v.as_str()),
        "mesg_count" => MesgCount::from_value(value as u8).map(|v| v.as_str()),
        "date_time" => DateTime::from_value(value as u32).map(|v| v.as_str()),
        "local_date_time" => LocalDateTime::from_value(value as u32).map(|v| v.as_str()),
        "message_index" => MessageIndex::from_value(value as u16).map(|v| v.as_str()),
        "device_index" => DeviceIndex::from_value(value as u8).map(|v| v.as_str()),
        "gender" => Gender::from_value(value as u8).map(|v| v.as_str()),
        "language" => Language::from_value(value as u8).map(|v| v.as_str()),
        "language_bits_0" => LanguageBits0::from_value(value as u8).map(|v| v.as_str()),
        "language_bits_1" => LanguageBits1::from_value(value as u8).map(|v| v.as_str()),
        "language_bits_2" => LanguageBits2::from_value(value as u8).map(|v| v.as_str()),
        "language_bits_3" => LanguageBits3::from_value(value as u8).map(|v| v.as_str()),
        "language_bits_4" => LanguageBits4::from_value(value as u8).map(|v| v.as_str()),
        "time_zone" => TimeZone::from_value(value as u8).map(|v| v.as_str()),
        "display_measure" => DisplayMeasure::from_value(value as u8).map(|v| v.as_str()),
        "display_heart" => DisplayHeart::from_value(value as u8).map(|v| v.as_str()),
        "display_power" => DisplayPower::from_value(value as u8).map(|v| v.as_str()),
        "display_position" => DisplayPosition::from_value(value as u8).map(|v| v.as_str()),
        "switch" => Switch::from_value(value as u8).map(|v| v.as_str()),
        "sport" => Sport::from_value(value as u8).map(|v| v.as_str()),
        "sport_bits_0" => SportBits0::from_value(value as u8).map(|v| v.as_str()),
        "sport_bits_1" => SportBits1::from_value(value as u8).map(|v| v.as_str()),
        "sport_bits_2" => SportBits2::from_value(value as u8).map(|v| v.as_str()),
        "sport_bits_3" => SportBits3::from_value(value as u8).map(|v| v.as_str()),
        "sport_bits_4" => SportBits4::from_value(value as u8).map(|v| v.as_str()),
        "sport_bits_5" => SportBits5::from_value(value as u8).map(|v| v.as_str()),
        "sport_bits_6" => SportBits6::from_value(value as u8).map(|v| v.as_str()),
        "sub_sport" => SubSport::from_value(value as u8).map(|v| v.as_str()),
        "sport_event" => SportEvent::from_value(value as u8).map(|v| v.as_str()),
        "activity" => Activity::from_value(value as u8).map(|v| v.as_str()),
        "intensity" => Intensity::from_value(value as u8).map(|v| v.as_str()),
        "session_trigger" => SessionTrigger::from_value(value as u8).map(|v| v.as_str()),
        "autolap_trigger" => AutolapTrigger::from_value(value as u8).map(|v| v.as_str()),
        "lap_trigger" => LapTrigger::from_value(value as u8).map(|v| v.as_str()),
        "time_mode" => TimeMode::from_value(value as u8).map(|v| v.as_str()),
        "backlight_mode" => BacklightMode::from_value(value as u8).map(|v| v.as_str()),
        "date_mode" => DateMode::from_value(value as u8).map(|v| v.as_str()),
        "backlight_timeout" => BacklightTimeout::from_value(value as u8).map(|v| v.as_str()),
        "event" => Event::from_value(value as u8).map(|v| v.as_str()),
        "event_type" => EventType::from_value(value as u8).map(|v| v.as_str()),
        "timer_trigger" => TimerTrigger::from_value(value as u8).map(|v| v.as_str()),
        "fitness_equipment_state" => {
            FitnessEquipmentState::from_value(value as u8).map(|v| v.as_str())
        }
        "tone" => Tone::from_value(value as u8).map(|v| v.as_str()),
        "autoscroll" => Autoscroll::from_value(value as u8).map(|v| v.as_str()),
        "activity_class" => ActivityClass::from_value(value as u8).map(|v| v.as_str()),
        "hr_zone_calc" => HrZoneCalc::from_value(value as u8).map(|v| v.as_str()),
        "pwr_zone_calc" => PwrZoneCalc::from_value(value as u8).map(|v| v.as_str()),
        "wkt_step_duration" => WktStepDuration::from_value(value as u8).map(|v| v.as_str()),
        "wkt_step_target" => WktStepTarget::from_value(value as u8).map(|v| v.as_str()),
        "goal" => Goal::from_value(value as u8).map(|v| v.as_str()),
        "goal_recurrence" => GoalRecurrence::from_value(value as u8).map(|v| v.as_str()),
        "goal_source" => GoalSource::from_value(value as u8).map(|v| v.as_str()),
        "schedule" => Schedule::from_value(value as u8).map(|v| v.as_str()),
        "course_point" => CoursePoint::from_value(value as u8).map(|v| v.as_str()),
        "manufacturer" => Manufacturer::from_value(value as u16).map(|v| v.as_str()),
        "garmin_product" => GarminProduct::from_value(value as u16).map(|v| v.as_str()),
        "antplus_device_type" => AntplusDeviceType::from_value(value as u8).map(|v| v.as_str()),
        "ant_network" => AntNetwork::from_value(value as u8).map(|v| v.as_str()),
        "workout_capabilities" => WorkoutCapabilities::from_value(value as u32).map(|v| v.as_str()),
        "battery_status" => BatteryStatus::from_value(value as u8).map(|v| v.as_str()),
        "hr_type" => HrType::from_value(value as u8).map(|v| v.as_str()),
        "course_capabilities" => CourseCapabilities::from_value(value as u32).map(|v| v.as_str()),
        "weight" => Weight::from_value(value as u16).map(|v| v.as_str()),
        "workout_hr" => WorkoutHr::from_value(value as u32).map(|v| v.as_str()),
        "workout_power" => WorkoutPower::from_value(value as u32).map(|v| v.as_str()),
        "bp_status" => BpStatus::from_value(value as u8).map(|v| v.as_str()),
        "user_local_id" => UserLocalId::from_value(value as u16).map(|v| v.as_str()),
        "swim_stroke" => SwimStroke::from_value(value as u8).map(|v| v.as_str()),
        "activity_type" => ActivityType::from_value(value as u8).map(|v| v.as_str()),
        "activity_subtype" => ActivitySubtype::from_value(value as u8).map(|v| v.as_str()),
        "activity_level" => ActivityLevel::from_value(value as u8).map(|v| v.as_str()),
        "side" => Side::from_value(value as u8).map(|v| v.as_str()),
        "left_right_balance" => LeftRightBalance::from_value(value as u8).map(|v| v.as_str()),
        "left_right_balance_100" => {
            LeftRightBalance100::from_value(value as u16).map(|v| v.as_str())
        }
        "length_type" => LengthType::from_value(value as u8).map(|v| v.as_str()),
        "day_of_week" => DayOfWeek::from_value(value as u8).map(|v| v.as_str()),
        "connectivity_capabilities" => {
            ConnectivityCapabilities::from_value(value as u32).map(|v| v.as_str())
        }
        "weather_report" => WeatherReport::from_value(value as u8).map(|v| v.as_str()),
        "weather_status" => WeatherStatus::from_value(value as u8).map(|v| v.as_str()),
        "weather_severity" => WeatherSeverity::from_value(value as u8).map(|v| v.as_str()),
        "weather_severe_type" => WeatherSevereType::from_value(value as u8).map(|v| v.as_str()),
        "stroke_type" => StrokeType::from_value(value as u8).map(|v| v.as_str()),
        "body_location" => BodyLocation::from_value(value as u8).map(|v| v.as_str()),
        "segment_lap_status" => SegmentLapStatus::from_value(value as u8).map(|v| v.as_str()),
        "segment_leaderboard_type" => {
            SegmentLeaderboardType::from_value(value as u8).map(|v| v.as_str())
        }
        "segment_delete_status" => SegmentDeleteStatus::from_value(value as u8).map(|v| v.as_str()),
        "segment_selection_type" => {
            SegmentSelectionType::from_value(value as u8).map(|v| v.as_str())
        }
        "source_type" => SourceType::from_value(value as u8).map(|v| v.as_str()),
        "local_device_type" => LocalDeviceType::from_value(value as u8).map(|v| v.as_str()),
        "ble_device_type" => BleDeviceType::from_value(value as u8).map(|v| v.as_str()),
        "ant_channel_id" => AntChannelId::from_value(value as u32).map(|v| v.as_str()),
        "display_orientation" => DisplayOrientation::from_value(value as u8).map(|v| v.as_str()),
        "workout_equipment" => WorkoutEquipment::from_value(value as u8).map(|v| v.as_str()),
        "watchface_mode" => WatchfaceMode::from_value(value as u8).map(|v| v.as_str()),
        "digital_watchface_layout" => {
            DigitalWatchfaceLayout::from_value(value as u8).map(|v| v.as_str())
        }
        "analog_watchface_layout" => {
            AnalogWatchfaceLayout::from_value(value as u8).map(|v| v.as_str())
        }
        "rider_position_type" => RiderPositionType::from_value(value as u8).map(|v| v.as_str()),
        "power_phase_type" => PowerPhaseType::from_value(value as u8).map(|v| v.as_str()),
        "camera_event_type" => CameraEventType::from_value(value as u8).map(|v| v.as_str()),
        "sensor_type" => SensorType::from_value(value as u8).map(|v| v.as_str()),
        "bike_light_network_config_type" => {
            BikeLightNetworkConfigType::from_value(value as u8).map(|v| v.as_str())
        }
        "comm_timeout_type" => CommTimeoutType::from_value(value as u16).map(|v| v.as_str()),
        "camera_orientation_type" => {
            CameraOrientationType::from_value(value as u8).map(|v| v.as_str())
        }
        "attitude_stage" => AttitudeStage::from_value(value as u8).map(|v| v.as_str()),
        "attitude_validity" => AttitudeValidity::from_value(value as u16).map(|v| v.as_str()),
        "auto_sync_frequency" => AutoSyncFrequency::from_value(value as u8).map(|v| v.as_str()),
        "exd_layout" => ExdLayout::from_value(value as u8).map(|v| v.as_str()),
        "exd_display_type" => ExdDisplayType::from_value(value as u8).map(|v| v.as_str()),
        "exd_data_units" => ExdDataUnits::from_value(value as u8).map(|v| v.as_str()),
        "exd_qualifiers" => ExdQualifiers::from_value(value as u8).map(|v| v.as_str()),
        "exd_descriptors" => ExdDescriptors::from_value(value as u8).map(|v| v.as_str()),
        "auto_activity_detect" => AutoActivityDetect::from_value(value as u32).map(|v| v.as_str()),
        "supported_exd_screen_layouts" => {
            SupportedExdScreenLayouts::from_value(value as u32).map(|v| v.as_str())
        }
        "fit_base_type" => FitBaseType::from_value(value as u8).map(|v| v.as_str()),
        "turn_type" => TurnType::from_value(value as u8).map(|v| v.as_str()),
        "bike_light_beam_angle_mode" => {
            BikeLightBeamAngleMode::from_value(value as u8).map(|v| v.as_str())
        }
        "fit_base_unit" => FitBaseUnit::from_value(value as u16).map(|v| v.as_str()),
        "set_type" => SetType::from_value(value as u8).map(|v| v.as_str()),
        "max_met_category" => MaxMetCategory::from_value(value as u8).map(|v| v.as_str()),
        "exercise_category" => ExerciseCategory::from_value(value as u16).map(|v| v.as_str()),
        "bench_press_exercise_name" => {
            BenchPressExerciseName::from_value(value as u16).map(|v| v.as_str())
        }
        "calf_raise_exercise_name" => {
            CalfRaiseExerciseName::from_value(value as u16).map(|v| v.as_str())
        }
        "cardio_exercise_name" => CardioExerciseName::from_value(value as u16).map(|v| v.as_str()),
        "carry_exercise_name" => CarryExerciseName::from_value(value as u16).map(|v| v.as_str()),
        "chop_exercise_name" => ChopExerciseName::from_value(value as u16).map(|v| v.as_str()),
        "core_exercise_name" => CoreExerciseName::from_value(value as u16).map(|v| v.as_str()),
        "crunch_exercise_name" => CrunchExerciseName::from_value(value as u16).map(|v| v.as_str()),
        "curl_exercise_name" => CurlExerciseName::from_value(value as u16).map(|v| v.as_str()),
        "deadlift_exercise_name" => {
            DeadliftExerciseName::from_value(value as u16).map(|v| v.as_str())
        }
        "flye_exercise_name" => FlyeExerciseName::from_value(value as u16).map(|v| v.as_str()),
        "hip_raise_exercise_name" => {
            HipRaiseExerciseName::from_value(value as u16).map(|v| v.as_str())
        }
        "hip_stability_exercise_name" => {
            HipStabilityExerciseName::from_value(value as u16).map(|v| v.as_str())
        }
        "hip_swing_exercise_name" => {
            HipSwingExerciseName::from_value(value as u16).map(|v| v.as_str())
        }
        "hyperextension_exercise_name" => {
            HyperextensionExerciseName::from_value(value as u16).map(|v| v.as_str())
        }
        "lateral_raise_exercise_name" => {
            LateralRaiseExerciseName::from_value(value as u16).map(|v| v.as_str())
        }
        "leg_curl_exercise_name" => {
            LegCurlExerciseName::from_value(value as u16).map(|v| v.as_str())
        }
        "leg_raise_exercise_name" => {
            LegRaiseExerciseName::from_value(value as u16).map(|v| v.as_str())
        }
        "lunge_exercise_name" => LungeExerciseName::from_value(value as u16).map(|v| v.as_str()),
        "olympic_lift_exercise_name" => {
            OlympicLiftExerciseName::from_value(value as u16).map(|v| v.as_str())
        }
        "plank_exercise_name" => PlankExerciseName::from_value(value as u16).map(|v| v.as_str()),
        "plyo_exercise_name" => PlyoExerciseName::from_value(value as u16).map(|v| v.as_str()),
        "pull_up_exercise_name" => PullUpExerciseName::from_value(value as u16).map(|v| v.as_str()),
        "push_up_exercise_name" => PushUpExerciseName::from_value(value as u16).map(|v| v.as_str()),
        "row_exercise_name" => RowExerciseName::from_value(value as u16).map(|v| v.as_str()),
        "shoulder_press_exercise_name" => {
            ShoulderPressExerciseName::from_value(value as u16).map(|v| v.as_str())
        }
        "shoulder_stability_exercise_name" => {
            ShoulderStabilityExerciseName::from_value(value as u16).map(|v| v.as_str())
        }
        "shrug_exercise_name" => ShrugExerciseName::from_value(value as u16).map(|v| v.as_str()),
        "sit_up_exercise_name" => SitUpExerciseName::from_value(value as u16).map(|v| v.as_str()),
        "squat_exercise_name" => SquatExerciseName::from_value(value as u16).map(|v| v.as_str()),
        "total_body_exercise_name" => {
            TotalBodyExerciseName::from_value(value as u16).map(|v| v.as_str())
        }
        "move_exercise_name" => MoveExerciseName::from_value(value as u16).map(|v| v.as_str()),
        "pose_exercise_name" => PoseExerciseName::from_value(value as u16).map(|v| v.as_str()),
        "triceps_extension_exercise_name" => {
            TricepsExtensionExerciseName::from_value(value as u16).map(|v| v.as_str())
        }
        "warm_up_exercise_name" => WarmUpExerciseName::from_value(value as u16).map(|v| v.as_str()),
        "run_exercise_name" => RunExerciseName::from_value(value as u16).map(|v| v.as_str()),
        "bike_exercise_name" => BikeExerciseName::from_value(value as u16).map(|v| v.as_str()),
        "banded_exercises_exercise_name" => {
            BandedExercisesExerciseName::from_value(value as u16).map(|v| v.as_str())
        }
        "battle_rope_exercise_name" => {
            BattleRopeExerciseName::from_value(value as u16).map(|v| v.as_str())
        }
        "elliptical_exercise_name" => {
            EllipticalExerciseName::from_value(value as u16).map(|v| v.as_str())
        }
        "floor_climb_exercise_name" => {
            FloorClimbExerciseName::from_value(value as u16).map(|v| v.as_str())
        }
        "indoor_bike_exercise_name" => {
            IndoorBikeExerciseName::from_value(value as u16).map(|v| v.as_str())
        }
        "indoor_row_exercise_name" => {
            IndoorRowExerciseName::from_value(value as u16).map(|v| v.as_str())
        }
        "ladder_exercise_name" => LadderExerciseName::from_value(value as u16).map(|v| v.as_str()),
        "sandbag_exercise_name" => {
            SandbagExerciseName::from_value(value as u16).map(|v| v.as_str())
        }
        "sled_exercise_name" => SledExerciseName::from_value(value as u16).map(|v| v.as_str()),
        "sledge_hammer_exercise_name" => {
            SledgeHammerExerciseName::from_value(value as u16).map(|v| v.as_str())
        }
        "stair_stepper_exercise_name" => {
            StairStepperExerciseName::from_value(value as u16).map(|v| v.as_str())
        }
        "suspension_exercise_name" => {
            SuspensionExerciseName::from_value(value as u16).map(|v| v.as_str())
        }
        "tire_exercise_name" => TireExerciseName::from_value(value as u16).map(|v| v.as_str()),
        "bike_outdoor_exercise_name" => {
            BikeOutdoorExerciseName::from_value(value as u16).map(|v| v.as_str())
        }
        "run_indoor_exercise_name" => {
            RunIndoorExerciseName::from_value(value as u16).map(|v| v.as_str())
        }
        "water_type" => WaterType::from_value(value as u8).map(|v| v.as_str()),
        "tissue_model_type" => TissueModelType::from_value(value as u8).map(|v| v.as_str()),
        "dive_gas_status" => DiveGasStatus::from_value(value as u8).map(|v| v.as_str()),
        "dive_alert" => DiveAlert::from_value(value as u8).map(|v| v.as_str()),
        "dive_alarm_type" => DiveAlarmType::from_value(value as u8).map(|v| v.as_str()),
        "dive_backlight_mode" => DiveBacklightMode::from_value(value as u8).map(|v| v.as_str()),
        "sleep_level" => SleepLevel::from_value(value as u8).map(|v| v.as_str()),
        "spo2_measurement_type" => Spo2MeasurementType::from_value(value as u8).map(|v| v.as_str()),
        "ccr_setpoint_switch_mode" => {
            CcrSetpointSwitchMode::from_value(value as u8).map(|v| v.as_str())
        }
        "dive_gas_mode" => DiveGasMode::from_value(value as u8).map(|v| v.as_str()),
        "projectile_type" => ProjectileType::from_value(value as u8).map(|v| v.as_str()),
        "favero_product" => FaveroProduct::from_value(value as u16).map(|v| v.as_str()),
        "split_type" => SplitType::from_value(value as u8).map(|v| v.as_str()),
        "climb_pro_event" => ClimbProEvent::from_value(value as u8).map(|v| v.as_str()),
        "gas_consumption_rate_type" => {
            GasConsumptionRateType::from_value(value as u8).map(|v| v.as_str())
        }
        "tap_sensitivity" => TapSensitivity::from_value(value as u8).map(|v| v.as_str()),
        "radar_threat_level_type" => {
            RadarThreatLevelType::from_value(value as u8).map(|v| v.as_str())
        }
        "sleep_disruption_severity" => {
            SleepDisruptionSeverity::from_value(value as u8).map(|v| v.as_str())
        }
        "nap_period_feedback" => NapPeriodFeedback::from_value(value as u8).map(|v| v.as_str()),
        "nap_source" => NapSource::from_value(value as u8).map(|v| v.as_str()),
        "max_met_speed_source" => MaxMetSpeedSource::from_value(value as u8).map(|v| v.as_str()),
        "max_met_heart_rate_source" => {
            MaxMetHeartRateSource::from_value(value as u8).map(|v| v.as_str())
        }
        "hrv_status" => HrvStatus::from_value(value as u8).map(|v| v.as_str()),
        "no_fly_time_mode" => NoFlyTimeMode::from_value(value as u8).map(|v| v.as_str()),
        _ => None,
    }
}

/// Resolve the numeric value for `(type_name, snake_case_name)`. Used by
/// the encoder to reverse enum-string lookups.
pub fn enum_value_by_str(type_name: &str, name: &str) -> Option<u64> {
    match type_name {
        "mesg_num" => MesgNum::from_name(name).map(|v| v as u64),
        "file" => File::from_str(name).map(|v| v as u64),
        "checksum" => Checksum::from_str(name).map(|v| v as u64),
        "file_flags" => FileFlags::from_str(name).map(|v| v as u64),
        "mesg_count" => MesgCount::from_str(name).map(|v| v as u64),
        "date_time" => DateTime::from_str(name).map(|v| v as u64),
        "local_date_time" => LocalDateTime::from_str(name).map(|v| v as u64),
        "message_index" => MessageIndex::from_str(name).map(|v| v as u64),
        "device_index" => DeviceIndex::from_str(name).map(|v| v as u64),
        "gender" => Gender::from_str(name).map(|v| v as u64),
        "language" => Language::from_str(name).map(|v| v as u64),
        "language_bits_0" => LanguageBits0::from_str(name).map(|v| v as u64),
        "language_bits_1" => LanguageBits1::from_str(name).map(|v| v as u64),
        "language_bits_2" => LanguageBits2::from_str(name).map(|v| v as u64),
        "language_bits_3" => LanguageBits3::from_str(name).map(|v| v as u64),
        "language_bits_4" => LanguageBits4::from_str(name).map(|v| v as u64),
        "time_zone" => TimeZone::from_str(name).map(|v| v as u64),
        "display_measure" => DisplayMeasure::from_str(name).map(|v| v as u64),
        "display_heart" => DisplayHeart::from_str(name).map(|v| v as u64),
        "display_power" => DisplayPower::from_str(name).map(|v| v as u64),
        "display_position" => DisplayPosition::from_str(name).map(|v| v as u64),
        "switch" => Switch::from_str(name).map(|v| v as u64),
        "sport" => Sport::from_str(name).map(|v| v as u64),
        "sport_bits_0" => SportBits0::from_str(name).map(|v| v as u64),
        "sport_bits_1" => SportBits1::from_str(name).map(|v| v as u64),
        "sport_bits_2" => SportBits2::from_str(name).map(|v| v as u64),
        "sport_bits_3" => SportBits3::from_str(name).map(|v| v as u64),
        "sport_bits_4" => SportBits4::from_str(name).map(|v| v as u64),
        "sport_bits_5" => SportBits5::from_str(name).map(|v| v as u64),
        "sport_bits_6" => SportBits6::from_str(name).map(|v| v as u64),
        "sub_sport" => SubSport::from_str(name).map(|v| v as u64),
        "sport_event" => SportEvent::from_str(name).map(|v| v as u64),
        "activity" => Activity::from_str(name).map(|v| v as u64),
        "intensity" => Intensity::from_str(name).map(|v| v as u64),
        "session_trigger" => SessionTrigger::from_str(name).map(|v| v as u64),
        "autolap_trigger" => AutolapTrigger::from_str(name).map(|v| v as u64),
        "lap_trigger" => LapTrigger::from_str(name).map(|v| v as u64),
        "time_mode" => TimeMode::from_str(name).map(|v| v as u64),
        "backlight_mode" => BacklightMode::from_str(name).map(|v| v as u64),
        "date_mode" => DateMode::from_str(name).map(|v| v as u64),
        "backlight_timeout" => BacklightTimeout::from_str(name).map(|v| v as u64),
        "event" => Event::from_str(name).map(|v| v as u64),
        "event_type" => EventType::from_str(name).map(|v| v as u64),
        "timer_trigger" => TimerTrigger::from_str(name).map(|v| v as u64),
        "fitness_equipment_state" => FitnessEquipmentState::from_str(name).map(|v| v as u64),
        "tone" => Tone::from_str(name).map(|v| v as u64),
        "autoscroll" => Autoscroll::from_str(name).map(|v| v as u64),
        "activity_class" => ActivityClass::from_str(name).map(|v| v as u64),
        "hr_zone_calc" => HrZoneCalc::from_str(name).map(|v| v as u64),
        "pwr_zone_calc" => PwrZoneCalc::from_str(name).map(|v| v as u64),
        "wkt_step_duration" => WktStepDuration::from_str(name).map(|v| v as u64),
        "wkt_step_target" => WktStepTarget::from_str(name).map(|v| v as u64),
        "goal" => Goal::from_str(name).map(|v| v as u64),
        "goal_recurrence" => GoalRecurrence::from_str(name).map(|v| v as u64),
        "goal_source" => GoalSource::from_str(name).map(|v| v as u64),
        "schedule" => Schedule::from_str(name).map(|v| v as u64),
        "course_point" => CoursePoint::from_str(name).map(|v| v as u64),
        "manufacturer" => Manufacturer::from_str(name).map(|v| v as u64),
        "garmin_product" => GarminProduct::from_str(name).map(|v| v as u64),
        "antplus_device_type" => AntplusDeviceType::from_str(name).map(|v| v as u64),
        "ant_network" => AntNetwork::from_str(name).map(|v| v as u64),
        "workout_capabilities" => WorkoutCapabilities::from_str(name).map(|v| v as u64),
        "battery_status" => BatteryStatus::from_str(name).map(|v| v as u64),
        "hr_type" => HrType::from_str(name).map(|v| v as u64),
        "course_capabilities" => CourseCapabilities::from_str(name).map(|v| v as u64),
        "weight" => Weight::from_str(name).map(|v| v as u64),
        "workout_hr" => WorkoutHr::from_str(name).map(|v| v as u64),
        "workout_power" => WorkoutPower::from_str(name).map(|v| v as u64),
        "bp_status" => BpStatus::from_str(name).map(|v| v as u64),
        "user_local_id" => UserLocalId::from_str(name).map(|v| v as u64),
        "swim_stroke" => SwimStroke::from_str(name).map(|v| v as u64),
        "activity_type" => ActivityType::from_str(name).map(|v| v as u64),
        "activity_subtype" => ActivitySubtype::from_str(name).map(|v| v as u64),
        "activity_level" => ActivityLevel::from_str(name).map(|v| v as u64),
        "side" => Side::from_str(name).map(|v| v as u64),
        "left_right_balance" => LeftRightBalance::from_str(name).map(|v| v as u64),
        "left_right_balance_100" => LeftRightBalance100::from_str(name).map(|v| v as u64),
        "length_type" => LengthType::from_str(name).map(|v| v as u64),
        "day_of_week" => DayOfWeek::from_str(name).map(|v| v as u64),
        "connectivity_capabilities" => ConnectivityCapabilities::from_str(name).map(|v| v as u64),
        "weather_report" => WeatherReport::from_str(name).map(|v| v as u64),
        "weather_status" => WeatherStatus::from_str(name).map(|v| v as u64),
        "weather_severity" => WeatherSeverity::from_str(name).map(|v| v as u64),
        "weather_severe_type" => WeatherSevereType::from_str(name).map(|v| v as u64),
        "stroke_type" => StrokeType::from_str(name).map(|v| v as u64),
        "body_location" => BodyLocation::from_str(name).map(|v| v as u64),
        "segment_lap_status" => SegmentLapStatus::from_str(name).map(|v| v as u64),
        "segment_leaderboard_type" => SegmentLeaderboardType::from_str(name).map(|v| v as u64),
        "segment_delete_status" => SegmentDeleteStatus::from_str(name).map(|v| v as u64),
        "segment_selection_type" => SegmentSelectionType::from_str(name).map(|v| v as u64),
        "source_type" => SourceType::from_str(name).map(|v| v as u64),
        "local_device_type" => LocalDeviceType::from_str(name).map(|v| v as u64),
        "ble_device_type" => BleDeviceType::from_str(name).map(|v| v as u64),
        "ant_channel_id" => AntChannelId::from_str(name).map(|v| v as u64),
        "display_orientation" => DisplayOrientation::from_str(name).map(|v| v as u64),
        "workout_equipment" => WorkoutEquipment::from_str(name).map(|v| v as u64),
        "watchface_mode" => WatchfaceMode::from_str(name).map(|v| v as u64),
        "digital_watchface_layout" => DigitalWatchfaceLayout::from_str(name).map(|v| v as u64),
        "analog_watchface_layout" => AnalogWatchfaceLayout::from_str(name).map(|v| v as u64),
        "rider_position_type" => RiderPositionType::from_str(name).map(|v| v as u64),
        "power_phase_type" => PowerPhaseType::from_str(name).map(|v| v as u64),
        "camera_event_type" => CameraEventType::from_str(name).map(|v| v as u64),
        "sensor_type" => SensorType::from_str(name).map(|v| v as u64),
        "bike_light_network_config_type" => {
            BikeLightNetworkConfigType::from_str(name).map(|v| v as u64)
        }
        "comm_timeout_type" => CommTimeoutType::from_str(name).map(|v| v as u64),
        "camera_orientation_type" => CameraOrientationType::from_str(name).map(|v| v as u64),
        "attitude_stage" => AttitudeStage::from_str(name).map(|v| v as u64),
        "attitude_validity" => AttitudeValidity::from_str(name).map(|v| v as u64),
        "auto_sync_frequency" => AutoSyncFrequency::from_str(name).map(|v| v as u64),
        "exd_layout" => ExdLayout::from_str(name).map(|v| v as u64),
        "exd_display_type" => ExdDisplayType::from_str(name).map(|v| v as u64),
        "exd_data_units" => ExdDataUnits::from_str(name).map(|v| v as u64),
        "exd_qualifiers" => ExdQualifiers::from_str(name).map(|v| v as u64),
        "exd_descriptors" => ExdDescriptors::from_str(name).map(|v| v as u64),
        "auto_activity_detect" => AutoActivityDetect::from_str(name).map(|v| v as u64),
        "supported_exd_screen_layouts" => {
            SupportedExdScreenLayouts::from_str(name).map(|v| v as u64)
        }
        "fit_base_type" => FitBaseType::from_str(name).map(|v| v as u64),
        "turn_type" => TurnType::from_str(name).map(|v| v as u64),
        "bike_light_beam_angle_mode" => BikeLightBeamAngleMode::from_str(name).map(|v| v as u64),
        "fit_base_unit" => FitBaseUnit::from_str(name).map(|v| v as u64),
        "set_type" => SetType::from_str(name).map(|v| v as u64),
        "max_met_category" => MaxMetCategory::from_str(name).map(|v| v as u64),
        "exercise_category" => ExerciseCategory::from_str(name).map(|v| v as u64),
        "bench_press_exercise_name" => BenchPressExerciseName::from_str(name).map(|v| v as u64),
        "calf_raise_exercise_name" => CalfRaiseExerciseName::from_str(name).map(|v| v as u64),
        "cardio_exercise_name" => CardioExerciseName::from_str(name).map(|v| v as u64),
        "carry_exercise_name" => CarryExerciseName::from_str(name).map(|v| v as u64),
        "chop_exercise_name" => ChopExerciseName::from_str(name).map(|v| v as u64),
        "core_exercise_name" => CoreExerciseName::from_str(name).map(|v| v as u64),
        "crunch_exercise_name" => CrunchExerciseName::from_str(name).map(|v| v as u64),
        "curl_exercise_name" => CurlExerciseName::from_str(name).map(|v| v as u64),
        "deadlift_exercise_name" => DeadliftExerciseName::from_str(name).map(|v| v as u64),
        "flye_exercise_name" => FlyeExerciseName::from_str(name).map(|v| v as u64),
        "hip_raise_exercise_name" => HipRaiseExerciseName::from_str(name).map(|v| v as u64),
        "hip_stability_exercise_name" => HipStabilityExerciseName::from_str(name).map(|v| v as u64),
        "hip_swing_exercise_name" => HipSwingExerciseName::from_str(name).map(|v| v as u64),
        "hyperextension_exercise_name" => {
            HyperextensionExerciseName::from_str(name).map(|v| v as u64)
        }
        "lateral_raise_exercise_name" => LateralRaiseExerciseName::from_str(name).map(|v| v as u64),
        "leg_curl_exercise_name" => LegCurlExerciseName::from_str(name).map(|v| v as u64),
        "leg_raise_exercise_name" => LegRaiseExerciseName::from_str(name).map(|v| v as u64),
        "lunge_exercise_name" => LungeExerciseName::from_str(name).map(|v| v as u64),
        "olympic_lift_exercise_name" => OlympicLiftExerciseName::from_str(name).map(|v| v as u64),
        "plank_exercise_name" => PlankExerciseName::from_str(name).map(|v| v as u64),
        "plyo_exercise_name" => PlyoExerciseName::from_str(name).map(|v| v as u64),
        "pull_up_exercise_name" => PullUpExerciseName::from_str(name).map(|v| v as u64),
        "push_up_exercise_name" => PushUpExerciseName::from_str(name).map(|v| v as u64),
        "row_exercise_name" => RowExerciseName::from_str(name).map(|v| v as u64),
        "shoulder_press_exercise_name" => {
            ShoulderPressExerciseName::from_str(name).map(|v| v as u64)
        }
        "shoulder_stability_exercise_name" => {
            ShoulderStabilityExerciseName::from_str(name).map(|v| v as u64)
        }
        "shrug_exercise_name" => ShrugExerciseName::from_str(name).map(|v| v as u64),
        "sit_up_exercise_name" => SitUpExerciseName::from_str(name).map(|v| v as u64),
        "squat_exercise_name" => SquatExerciseName::from_str(name).map(|v| v as u64),
        "total_body_exercise_name" => TotalBodyExerciseName::from_str(name).map(|v| v as u64),
        "move_exercise_name" => MoveExerciseName::from_str(name).map(|v| v as u64),
        "pose_exercise_name" => PoseExerciseName::from_str(name).map(|v| v as u64),
        "triceps_extension_exercise_name" => {
            TricepsExtensionExerciseName::from_str(name).map(|v| v as u64)
        }
        "warm_up_exercise_name" => WarmUpExerciseName::from_str(name).map(|v| v as u64),
        "run_exercise_name" => RunExerciseName::from_str(name).map(|v| v as u64),
        "bike_exercise_name" => BikeExerciseName::from_str(name).map(|v| v as u64),
        "banded_exercises_exercise_name" => {
            BandedExercisesExerciseName::from_str(name).map(|v| v as u64)
        }
        "battle_rope_exercise_name" => BattleRopeExerciseName::from_str(name).map(|v| v as u64),
        "elliptical_exercise_name" => EllipticalExerciseName::from_str(name).map(|v| v as u64),
        "floor_climb_exercise_name" => FloorClimbExerciseName::from_str(name).map(|v| v as u64),
        "indoor_bike_exercise_name" => IndoorBikeExerciseName::from_str(name).map(|v| v as u64),
        "indoor_row_exercise_name" => IndoorRowExerciseName::from_str(name).map(|v| v as u64),
        "ladder_exercise_name" => LadderExerciseName::from_str(name).map(|v| v as u64),
        "sandbag_exercise_name" => SandbagExerciseName::from_str(name).map(|v| v as u64),
        "sled_exercise_name" => SledExerciseName::from_str(name).map(|v| v as u64),
        "sledge_hammer_exercise_name" => SledgeHammerExerciseName::from_str(name).map(|v| v as u64),
        "stair_stepper_exercise_name" => StairStepperExerciseName::from_str(name).map(|v| v as u64),
        "suspension_exercise_name" => SuspensionExerciseName::from_str(name).map(|v| v as u64),
        "tire_exercise_name" => TireExerciseName::from_str(name).map(|v| v as u64),
        "bike_outdoor_exercise_name" => BikeOutdoorExerciseName::from_str(name).map(|v| v as u64),
        "run_indoor_exercise_name" => RunIndoorExerciseName::from_str(name).map(|v| v as u64),
        "water_type" => WaterType::from_str(name).map(|v| v as u64),
        "tissue_model_type" => TissueModelType::from_str(name).map(|v| v as u64),
        "dive_gas_status" => DiveGasStatus::from_str(name).map(|v| v as u64),
        "dive_alert" => DiveAlert::from_str(name).map(|v| v as u64),
        "dive_alarm_type" => DiveAlarmType::from_str(name).map(|v| v as u64),
        "dive_backlight_mode" => DiveBacklightMode::from_str(name).map(|v| v as u64),
        "sleep_level" => SleepLevel::from_str(name).map(|v| v as u64),
        "spo2_measurement_type" => Spo2MeasurementType::from_str(name).map(|v| v as u64),
        "ccr_setpoint_switch_mode" => CcrSetpointSwitchMode::from_str(name).map(|v| v as u64),
        "dive_gas_mode" => DiveGasMode::from_str(name).map(|v| v as u64),
        "projectile_type" => ProjectileType::from_str(name).map(|v| v as u64),
        "favero_product" => FaveroProduct::from_str(name).map(|v| v as u64),
        "split_type" => SplitType::from_str(name).map(|v| v as u64),
        "climb_pro_event" => ClimbProEvent::from_str(name).map(|v| v as u64),
        "gas_consumption_rate_type" => GasConsumptionRateType::from_str(name).map(|v| v as u64),
        "tap_sensitivity" => TapSensitivity::from_str(name).map(|v| v as u64),
        "radar_threat_level_type" => RadarThreatLevelType::from_str(name).map(|v| v as u64),
        "sleep_disruption_severity" => SleepDisruptionSeverity::from_str(name).map(|v| v as u64),
        "nap_period_feedback" => NapPeriodFeedback::from_str(name).map(|v| v as u64),
        "nap_source" => NapSource::from_str(name).map(|v| v as u64),
        "max_met_speed_source" => MaxMetSpeedSource::from_str(name).map(|v| v as u64),
        "max_met_heart_rate_source" => MaxMetHeartRateSource::from_str(name).map(|v| v as u64),
        "hrv_status" => HrvStatus::from_str(name).map(|v| v as u64),
        "no_fly_time_mode" => NoFlyTimeMode::from_str(name).map(|v| v as u64),
        _ => None,
    }
}

/// Map a Profile type_name to its underlying wire [`crate::base_type::BaseType`].
/// Returns `None` for raw base type names like `"uint16"` (those
/// are resolved separately by the encoder) and for unknown names.
pub fn base_type_for_type_name(type_name: &str) -> Option<crate::base_type::BaseType> {
    use crate::base_type::BaseType;
    match type_name {
        "mesg_num" => Some(BaseType::UInt16),
        "file" => Some(BaseType::Enum),
        "checksum" => Some(BaseType::UInt8),
        "file_flags" => Some(BaseType::UInt8z),
        "mesg_count" => Some(BaseType::Enum),
        "date_time" => Some(BaseType::UInt32),
        "local_date_time" => Some(BaseType::UInt32),
        "message_index" => Some(BaseType::UInt16),
        "device_index" => Some(BaseType::UInt8),
        "gender" => Some(BaseType::Enum),
        "language" => Some(BaseType::Enum),
        "language_bits_0" => Some(BaseType::UInt8z),
        "language_bits_1" => Some(BaseType::UInt8z),
        "language_bits_2" => Some(BaseType::UInt8z),
        "language_bits_3" => Some(BaseType::UInt8z),
        "language_bits_4" => Some(BaseType::UInt8z),
        "time_zone" => Some(BaseType::Enum),
        "display_measure" => Some(BaseType::Enum),
        "display_heart" => Some(BaseType::Enum),
        "display_power" => Some(BaseType::Enum),
        "display_position" => Some(BaseType::Enum),
        "switch" => Some(BaseType::Enum),
        "sport" => Some(BaseType::Enum),
        "sport_bits_0" => Some(BaseType::UInt8z),
        "sport_bits_1" => Some(BaseType::UInt8z),
        "sport_bits_2" => Some(BaseType::UInt8z),
        "sport_bits_3" => Some(BaseType::UInt8z),
        "sport_bits_4" => Some(BaseType::UInt8z),
        "sport_bits_5" => Some(BaseType::UInt8z),
        "sport_bits_6" => Some(BaseType::UInt8z),
        "sub_sport" => Some(BaseType::Enum),
        "sport_event" => Some(BaseType::Enum),
        "activity" => Some(BaseType::Enum),
        "intensity" => Some(BaseType::Enum),
        "session_trigger" => Some(BaseType::Enum),
        "autolap_trigger" => Some(BaseType::Enum),
        "lap_trigger" => Some(BaseType::Enum),
        "time_mode" => Some(BaseType::Enum),
        "backlight_mode" => Some(BaseType::Enum),
        "date_mode" => Some(BaseType::Enum),
        "backlight_timeout" => Some(BaseType::UInt8),
        "event" => Some(BaseType::Enum),
        "event_type" => Some(BaseType::Enum),
        "timer_trigger" => Some(BaseType::Enum),
        "fitness_equipment_state" => Some(BaseType::Enum),
        "tone" => Some(BaseType::Enum),
        "autoscroll" => Some(BaseType::Enum),
        "activity_class" => Some(BaseType::Enum),
        "hr_zone_calc" => Some(BaseType::Enum),
        "pwr_zone_calc" => Some(BaseType::Enum),
        "wkt_step_duration" => Some(BaseType::Enum),
        "wkt_step_target" => Some(BaseType::Enum),
        "goal" => Some(BaseType::Enum),
        "goal_recurrence" => Some(BaseType::Enum),
        "goal_source" => Some(BaseType::Enum),
        "schedule" => Some(BaseType::Enum),
        "course_point" => Some(BaseType::Enum),
        "manufacturer" => Some(BaseType::UInt16),
        "garmin_product" => Some(BaseType::UInt16),
        "antplus_device_type" => Some(BaseType::UInt8),
        "ant_network" => Some(BaseType::Enum),
        "workout_capabilities" => Some(BaseType::UInt32z),
        "battery_status" => Some(BaseType::UInt8),
        "hr_type" => Some(BaseType::Enum),
        "course_capabilities" => Some(BaseType::UInt32z),
        "weight" => Some(BaseType::UInt16),
        "workout_hr" => Some(BaseType::UInt32),
        "workout_power" => Some(BaseType::UInt32),
        "bp_status" => Some(BaseType::Enum),
        "user_local_id" => Some(BaseType::UInt16),
        "swim_stroke" => Some(BaseType::Enum),
        "activity_type" => Some(BaseType::Enum),
        "activity_subtype" => Some(BaseType::Enum),
        "activity_level" => Some(BaseType::Enum),
        "side" => Some(BaseType::Enum),
        "left_right_balance" => Some(BaseType::UInt8),
        "left_right_balance_100" => Some(BaseType::UInt16),
        "length_type" => Some(BaseType::Enum),
        "day_of_week" => Some(BaseType::Enum),
        "connectivity_capabilities" => Some(BaseType::UInt32z),
        "weather_report" => Some(BaseType::Enum),
        "weather_status" => Some(BaseType::Enum),
        "weather_severity" => Some(BaseType::Enum),
        "weather_severe_type" => Some(BaseType::Enum),
        "stroke_type" => Some(BaseType::Enum),
        "body_location" => Some(BaseType::Enum),
        "segment_lap_status" => Some(BaseType::Enum),
        "segment_leaderboard_type" => Some(BaseType::Enum),
        "segment_delete_status" => Some(BaseType::Enum),
        "segment_selection_type" => Some(BaseType::Enum),
        "source_type" => Some(BaseType::Enum),
        "local_device_type" => Some(BaseType::UInt8),
        "ble_device_type" => Some(BaseType::UInt8),
        "ant_channel_id" => Some(BaseType::UInt32z),
        "display_orientation" => Some(BaseType::Enum),
        "workout_equipment" => Some(BaseType::Enum),
        "watchface_mode" => Some(BaseType::Enum),
        "digital_watchface_layout" => Some(BaseType::Enum),
        "analog_watchface_layout" => Some(BaseType::Enum),
        "rider_position_type" => Some(BaseType::Enum),
        "power_phase_type" => Some(BaseType::Enum),
        "camera_event_type" => Some(BaseType::Enum),
        "sensor_type" => Some(BaseType::Enum),
        "bike_light_network_config_type" => Some(BaseType::Enum),
        "comm_timeout_type" => Some(BaseType::UInt16),
        "camera_orientation_type" => Some(BaseType::Enum),
        "attitude_stage" => Some(BaseType::Enum),
        "attitude_validity" => Some(BaseType::UInt16),
        "auto_sync_frequency" => Some(BaseType::Enum),
        "exd_layout" => Some(BaseType::Enum),
        "exd_display_type" => Some(BaseType::Enum),
        "exd_data_units" => Some(BaseType::Enum),
        "exd_qualifiers" => Some(BaseType::Enum),
        "exd_descriptors" => Some(BaseType::Enum),
        "auto_activity_detect" => Some(BaseType::UInt32),
        "supported_exd_screen_layouts" => Some(BaseType::UInt32z),
        "fit_base_type" => Some(BaseType::UInt8),
        "turn_type" => Some(BaseType::Enum),
        "bike_light_beam_angle_mode" => Some(BaseType::UInt8),
        "fit_base_unit" => Some(BaseType::UInt16),
        "set_type" => Some(BaseType::UInt8),
        "max_met_category" => Some(BaseType::Enum),
        "exercise_category" => Some(BaseType::UInt16),
        "bench_press_exercise_name" => Some(BaseType::UInt16),
        "calf_raise_exercise_name" => Some(BaseType::UInt16),
        "cardio_exercise_name" => Some(BaseType::UInt16),
        "carry_exercise_name" => Some(BaseType::UInt16),
        "chop_exercise_name" => Some(BaseType::UInt16),
        "core_exercise_name" => Some(BaseType::UInt16),
        "crunch_exercise_name" => Some(BaseType::UInt16),
        "curl_exercise_name" => Some(BaseType::UInt16),
        "deadlift_exercise_name" => Some(BaseType::UInt16),
        "flye_exercise_name" => Some(BaseType::UInt16),
        "hip_raise_exercise_name" => Some(BaseType::UInt16),
        "hip_stability_exercise_name" => Some(BaseType::UInt16),
        "hip_swing_exercise_name" => Some(BaseType::UInt16),
        "hyperextension_exercise_name" => Some(BaseType::UInt16),
        "lateral_raise_exercise_name" => Some(BaseType::UInt16),
        "leg_curl_exercise_name" => Some(BaseType::UInt16),
        "leg_raise_exercise_name" => Some(BaseType::UInt16),
        "lunge_exercise_name" => Some(BaseType::UInt16),
        "olympic_lift_exercise_name" => Some(BaseType::UInt16),
        "plank_exercise_name" => Some(BaseType::UInt16),
        "plyo_exercise_name" => Some(BaseType::UInt16),
        "pull_up_exercise_name" => Some(BaseType::UInt16),
        "push_up_exercise_name" => Some(BaseType::UInt16),
        "row_exercise_name" => Some(BaseType::UInt16),
        "shoulder_press_exercise_name" => Some(BaseType::UInt16),
        "shoulder_stability_exercise_name" => Some(BaseType::UInt16),
        "shrug_exercise_name" => Some(BaseType::UInt16),
        "sit_up_exercise_name" => Some(BaseType::UInt16),
        "squat_exercise_name" => Some(BaseType::UInt16),
        "total_body_exercise_name" => Some(BaseType::UInt16),
        "move_exercise_name" => Some(BaseType::UInt16),
        "pose_exercise_name" => Some(BaseType::UInt16),
        "triceps_extension_exercise_name" => Some(BaseType::UInt16),
        "warm_up_exercise_name" => Some(BaseType::UInt16),
        "run_exercise_name" => Some(BaseType::UInt16),
        "bike_exercise_name" => Some(BaseType::UInt16),
        "banded_exercises_exercise_name" => Some(BaseType::UInt16),
        "battle_rope_exercise_name" => Some(BaseType::UInt16),
        "elliptical_exercise_name" => Some(BaseType::UInt16),
        "floor_climb_exercise_name" => Some(BaseType::UInt16),
        "indoor_bike_exercise_name" => Some(BaseType::UInt16),
        "indoor_row_exercise_name" => Some(BaseType::UInt16),
        "ladder_exercise_name" => Some(BaseType::UInt16),
        "sandbag_exercise_name" => Some(BaseType::UInt16),
        "sled_exercise_name" => Some(BaseType::UInt16),
        "sledge_hammer_exercise_name" => Some(BaseType::UInt16),
        "stair_stepper_exercise_name" => Some(BaseType::UInt16),
        "suspension_exercise_name" => Some(BaseType::UInt16),
        "tire_exercise_name" => Some(BaseType::UInt16),
        "bike_outdoor_exercise_name" => Some(BaseType::UInt16),
        "run_indoor_exercise_name" => Some(BaseType::UInt16),
        "water_type" => Some(BaseType::Enum),
        "tissue_model_type" => Some(BaseType::Enum),
        "dive_gas_status" => Some(BaseType::Enum),
        "dive_alert" => Some(BaseType::Enum),
        "dive_alarm_type" => Some(BaseType::Enum),
        "dive_backlight_mode" => Some(BaseType::Enum),
        "sleep_level" => Some(BaseType::Enum),
        "spo2_measurement_type" => Some(BaseType::Enum),
        "ccr_setpoint_switch_mode" => Some(BaseType::Enum),
        "dive_gas_mode" => Some(BaseType::Enum),
        "projectile_type" => Some(BaseType::Enum),
        "favero_product" => Some(BaseType::UInt16),
        "split_type" => Some(BaseType::Enum),
        "climb_pro_event" => Some(BaseType::Enum),
        "gas_consumption_rate_type" => Some(BaseType::Enum),
        "tap_sensitivity" => Some(BaseType::Enum),
        "radar_threat_level_type" => Some(BaseType::Enum),
        "sleep_disruption_severity" => Some(BaseType::Enum),
        "nap_period_feedback" => Some(BaseType::Enum),
        "nap_source" => Some(BaseType::Enum),
        "max_met_speed_source" => Some(BaseType::Enum),
        "max_met_heart_rate_source" => Some(BaseType::Enum),
        "hrv_status" => Some(BaseType::Enum),
        "no_fly_time_mode" => Some(BaseType::Enum),
        _ => None,
    }
}
