{{
    const champions = require('./.champion.json')
        .filter(({ id }) => id > 0)
        .sort(({ name: a }, { name: b }) => a > b ? 1 : -1);
    const hashFactor = 256;
    const enumName = name => name.replace(/[^a-z]+/i, '');
    const strHash = function(str) {
        let h = 0;
        for (let c of str)
            h = hashFactor * h + c.charCodeAt(0);
        return h;
    };
    const padId = function(id) { return ('' + id).padEnd(3); };
}}{{= require('./dotUtils.js').preamble() }}

use std::fmt;
use num_enum::{ IntoPrimitive, TryFromPrimitive };
use serde_repr::{ Serialize_repr, Deserialize_repr };

/// League of Legend's champions.
///
/// The documentation of each variant specifies:<br>
/// NAME (`IDENTIFIER`, ID).
#[derive(Debug, Copy, Clone)]
#[derive(IntoPrimitive, TryFromPrimitive)]
#[derive(Serialize_repr, Deserialize_repr)]
#[repr(i16)]
pub enum Champion {
    /// A champion that doesn't exist. Used in TeamBans when no ban occured.
    None = -1,

{{
    for (let { id, alias, name } of champions) {
        const comment = `${name.padEnd(14)} (\`${alias}\`, ${id}).`.padEnd(36);
        const ename = enumName(name).padEnd(12);
}}
    /** {{= comment }} */ {{= ename }} = {{= id }},
{{
    }
}}
}

impl Champion {
    pub fn name(self) -> &'static str {
        match self {
            Self::None => "None",
{{
    for (let { id, name } of champions) {
}}
            Self::{{= enumName(name).padEnd(12) }} => "{{= name }}",
{{
    }
}}
        }
    }

    pub fn identifier(self) -> &'static str {
        match self {
            Self::None => "None",
{{
    for (let { name, alias } of champions) {
}}
            Self::{{= enumName(name).padEnd(12) }} => "{{= alias }}",
{{
    }
}}
        }
    }
}

impl std::str::FromStr for Champion {
    type Err = ();

    fn from_str(val: &str) -> Result<Self, Self::Err> {
        // 4 characters encoded as an int.
        match val.chars()
            .filter(|c| c.is_ascii_alphabetic())
            .take(4)
            .map(|c| c.to_ascii_uppercase() as u32)
            .fold(0u32, |hash, next| hash * {{= hashFactor }} + next)
        {
{{
    let keyStrings = (name, alias) => new Set([].concat(...[ name, alias ].map(s => s.toUpperCase())
        .map(s => [
            s.replace(/[^A-Z]+/, '').substring(0, 4),
            s.split(/[^A-Z]/, 1)[0].substring(0, 4)
        ])));
    for (let { id, alias, name } of champions) {
        for (let prefix of keyStrings(name, alias)) {
}}
            {{= ('' + strHash(prefix)).padEnd(10) }} /* {{= prefix.padEnd(4) }} */ => Ok(Self::{{= enumName(name) }}),
{{
        }
    }
}}
            _ => Err(()),
        }
    }
}

impl fmt::Display for Champion {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self)
    }
}