rust-grib-decoder 0.1.1

Utilities to decode GRIB2 CCSDS/AEC (template 5.0=42) payloads and extract Section 7 payloads per message.
Documentation
/// Centralized parameter alias mapping for `grib_preview_cli` and other consumers.
///
/// Moved from `atmosGUI` to allow reuse across CLI/UI and the decoder helpers.

#[derive(Debug, Clone)]
pub struct ParamAlias {
    pub file_prefixes: Vec<String>,
    pub tokens: Vec<String>,
    pub unit_tag: Option<&'static str>,
}

impl ParamAlias {
    pub fn for_param(param: &str) -> Self {
        let p = param.to_lowercase();
        match p.as_str() {
            // 2m temperature: files commonly use '2t' prefix
            "2t" | "t2m" | "t2" => ParamAlias {
                file_prefixes: vec!["2t".to_string()],
                tokens: vec!["t2".into(), "t2m".into(), "2t".into(), "temperature".into(), "temperatur".into(), "temp".into()],
                unit_tag: Some("degC"),
            },
            // mean sea-level pressure
            "msl" => ParamAlias {
                file_prefixes: vec!["msl".into()],
                tokens: vec!["msl".into(), "mslp".into(), "pressure".into(), "press".into(), "mass".into(), "sea".into()],
                unit_tag: Some("hPa"),
            },
            // total precipitation
            "tp" => ParamAlias {
                file_prefixes: vec!["tp".into()],
                tokens: vec!["tp".into(), "precip".into(), "precipitation".into(), "total precipitation".into(), "accumulated".into()],
                unit_tag: Some("mm"),
            },
            // u/v wind at 10m
            "u10" => ParamAlias {
                file_prefixes: vec!["u10".into()],
                tokens: vec!["u10".into(), "u-10".into(), "u10m".into(), "u component".into(), "uwind".into()],
                unit_tag: Some("m/s"),
            },
            "v10" => ParamAlias {
                file_prefixes: vec!["v10".into()],
                tokens: vec!["v10".into(), "v-10".into(), "v10m".into(), "v component".into(), "vwind".into()],
                unit_tag: Some("m/s"),
            },
            // geopotential height
            "gh" => ParamAlias {
                file_prefixes: vec!["gh".into()],
                tokens: vec!["gh".into(), "geopotential".into(), "geopotentialheight".into()],
                unit_tag: Some("dagpm"),
            },
            // u/v winds at pressure level
            "u" => ParamAlias {
                file_prefixes: vec!["u".into()],
                tokens: vec!["u".into(), "uwind".into(), "u component".into()],
                unit_tag: Some("m/s"),
            },
            "v" => ParamAlias {
                file_prefixes: vec!["v".into()],
                tokens: vec!["v".into(), "vwind".into(), "v component".into()],
                unit_tag: Some("m/s"),
            },
            other => ParamAlias {
                file_prefixes: vec![other.to_string()],
                tokens: vec![other.to_string()],
                unit_tag: None,
            },
        }
    }

    /// Heuristic match: check tokens then a normalized fallback
    pub fn matches_key(&self, key: &str, param: &str) -> bool {
        let key_l = key.to_lowercase();
        for t in &self.tokens {
            if key_l.contains(t) {
                return true;
            }
        }
        // fallback: normalize (remove non-alphanumeric) and check contains
        let norm = |s: &str| s.chars().filter(|c| c.is_ascii_alphanumeric()).collect::<String>();
        let nparam = norm(param);
        let nkey = norm(&key_l);
        if !nparam.is_empty() && nkey.contains(&nparam) {
            return true;
        }
        false
    }
}