rust_grib_decoder/
param_alias.rs

1/// Centralized parameter alias mapping for `grib_preview_cli` and other consumers.
2///
3/// Moved from `atmosGUI` to allow reuse across CLI/UI and the decoder helpers.
4
5#[derive(Debug, Clone)]
6pub struct ParamAlias {
7    pub file_prefixes: Vec<String>,
8    pub tokens: Vec<String>,
9    pub unit_tag: Option<&'static str>,
10}
11
12impl ParamAlias {
13    pub fn for_param(param: &str) -> Self {
14        let p = param.to_lowercase();
15        match p.as_str() {
16            // 2m temperature: files commonly use '2t' prefix
17            "2t" | "t2m" | "t2" => ParamAlias {
18                file_prefixes: vec!["2t".to_string()],
19                tokens: vec!["t2".into(), "t2m".into(), "2t".into(), "temperature".into(), "temperatur".into(), "temp".into()],
20                unit_tag: Some("degC"),
21            },
22            // mean sea-level pressure
23            "msl" => ParamAlias {
24                file_prefixes: vec!["msl".into()],
25                tokens: vec!["msl".into(), "mslp".into(), "pressure".into(), "press".into(), "mass".into(), "sea".into()],
26                unit_tag: Some("hPa"),
27            },
28            // total precipitation
29            "tp" => ParamAlias {
30                file_prefixes: vec!["tp".into()],
31                tokens: vec!["tp".into(), "precip".into(), "precipitation".into(), "total precipitation".into(), "accumulated".into()],
32                unit_tag: Some("mm"),
33            },
34            // u/v wind at 10m
35            "u10" => ParamAlias {
36                file_prefixes: vec!["u10".into()],
37                tokens: vec!["u10".into(), "u-10".into(), "u10m".into(), "u component".into(), "uwind".into()],
38                unit_tag: Some("m/s"),
39            },
40            "v10" => ParamAlias {
41                file_prefixes: vec!["v10".into()],
42                tokens: vec!["v10".into(), "v-10".into(), "v10m".into(), "v component".into(), "vwind".into()],
43                unit_tag: Some("m/s"),
44            },
45            // geopotential height
46            "gh" => ParamAlias {
47                file_prefixes: vec!["gh".into()],
48                tokens: vec!["gh".into(), "geopotential".into(), "geopotentialheight".into()],
49                unit_tag: Some("dagpm"),
50            },
51            // u/v winds at pressure level
52            "u" => ParamAlias {
53                file_prefixes: vec!["u".into()],
54                tokens: vec!["u".into(), "uwind".into(), "u component".into()],
55                unit_tag: Some("m/s"),
56            },
57            "v" => ParamAlias {
58                file_prefixes: vec!["v".into()],
59                tokens: vec!["v".into(), "vwind".into(), "v component".into()],
60                unit_tag: Some("m/s"),
61            },
62            other => ParamAlias {
63                file_prefixes: vec![other.to_string()],
64                tokens: vec![other.to_string()],
65                unit_tag: None,
66            },
67        }
68    }
69
70    /// Heuristic match: check tokens then a normalized fallback
71    pub fn matches_key(&self, key: &str, param: &str) -> bool {
72        let key_l = key.to_lowercase();
73        for t in &self.tokens {
74            if key_l.contains(t) {
75                return true;
76            }
77        }
78        // fallback: normalize (remove non-alphanumeric) and check contains
79        let norm = |s: &str| s.chars().filter(|c| c.is_ascii_alphanumeric()).collect::<String>();
80        let nparam = norm(param);
81        let nkey = norm(&key_l);
82        if !nparam.is_empty() && nkey.contains(&nparam) {
83            return true;
84        }
85        false
86    }
87}