Skip to main content

mongol_convert/
code_type.rs

1//! Encoding type system. Port of `translate/enumeration/CodeType.java` + `CodeSeries.java`.
2//!
3//! Java `CodeType.get` matches `enumName.toLowerCase()`, e.g. `Menk_Shape` -> `"menk_shape"`.
4//! That lowercased-enum-name form is the **canonical** string here; the PHP underscore-stripped
5//! form (`"menkshape"`) is accepted as a compatibility alias (design decision #1).
6
7use crate::error::MongolConvertError;
8use std::str::FromStr;
9
10/// Dispatch classification: a code is decoded/encoded either via the letter rules or the shape rules.
11/// Port of `CodeSeries.java`.
12#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
13pub enum CodeSeries {
14    Letter,
15    Shape,
16}
17
18/// The supported Mongolian encodings. One variant per Java `CodeType` (in declaration order).
19/// `Zvvnmod` is the intermediate hub. Port of `CodeType.java` lines 14-20.
20///
21/// `Oyun` and `Utn57` are parseable. `Oyun` remains unsupported in both directions; UTN #57
22/// converts both ways through the in-process `zvvnmod-utn57` backend.
23///
24/// `Utn57Shape` has no Java counterpart: it is the written-unit spelling of a UTN #57 text
25/// (ᠰᠠᠢᠨ as `SAIIA`), read and written through `Utn57`.
26#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
27pub enum CodeType {
28    Zvvnmod,
29    Delehi,
30    MenkShape,
31    MenkLetter,
32    Oyun,
33    Utn57,
34    Z52,
35    Utn57Shape,
36}
37
38impl CodeType {
39    /// The code's series. Port of Java's stored `codeSeries` final field, as a `const fn`.
40    pub const fn code_series(self) -> CodeSeries {
41        match self {
42            CodeType::Zvvnmod => CodeSeries::Shape,
43            CodeType::Delehi => CodeSeries::Letter,
44            CodeType::MenkShape => CodeSeries::Shape,
45            CodeType::MenkLetter => CodeSeries::Letter,
46            CodeType::Oyun => CodeSeries::Letter,
47            CodeType::Utn57 => CodeSeries::Letter,
48            CodeType::Z52 => CodeSeries::Shape,
49            CodeType::Utn57Shape => CodeSeries::Letter,
50        }
51    }
52
53    /// Canonical string form (the Java lowercased-enum-name form).
54    pub const fn canonical_str(self) -> &'static str {
55        match self {
56            CodeType::Zvvnmod => "zvvnmod",
57            CodeType::Delehi => "delehi",
58            CodeType::MenkShape => "menk_shape",
59            CodeType::MenkLetter => "menk_letter",
60            CodeType::Oyun => "oyun",
61            CodeType::Utn57 => "utn57",
62            CodeType::Z52 => "z52",
63            CodeType::Utn57Shape => "utn57_shape",
64        }
65    }
66
67    /// Case-insensitive lookup, mirroring Java `CodeType.get`. Accepts the canonical Java form
68    /// and the PHP underscore-stripped alias. Errors with [`MongolConvertError::UnsupportedEnumType`].
69    pub fn get(value: &str) -> Result<CodeType, MongolConvertError> {
70        value.parse()
71    }
72}
73
74impl FromStr for CodeType {
75    type Err = MongolConvertError;
76
77    fn from_str(s: &str) -> Result<CodeType, MongolConvertError> {
78        match s.to_ascii_lowercase().as_str() {
79            "zvvnmod" => Ok(CodeType::Zvvnmod),
80            "delehi" => Ok(CodeType::Delehi),
81            "menk_shape" | "menkshape" => Ok(CodeType::MenkShape),
82            "menk_letter" | "menkletter" => Ok(CodeType::MenkLetter),
83            "oyun" => Ok(CodeType::Oyun),
84            "utn57" => Ok(CodeType::Utn57),
85            "z52" => Ok(CodeType::Z52),
86            "utn57_shape" | "utn57shape" => Ok(CodeType::Utn57Shape),
87            _ => Err(MongolConvertError::UnsupportedEnumType(s.to_string())),
88        }
89    }
90}
91
92#[cfg(test)]
93mod tests {
94    use super::*;
95
96    #[test]
97    fn series_matches_java() {
98        assert_eq!(CodeType::Zvvnmod.code_series(), CodeSeries::Shape);
99        assert_eq!(CodeType::Delehi.code_series(), CodeSeries::Letter);
100        assert_eq!(CodeType::MenkShape.code_series(), CodeSeries::Shape);
101        assert_eq!(CodeType::MenkLetter.code_series(), CodeSeries::Letter);
102        assert_eq!(CodeType::Oyun.code_series(), CodeSeries::Letter);
103        assert_eq!(CodeType::Utn57.code_series(), CodeSeries::Letter);
104        assert_eq!(CodeType::Z52.code_series(), CodeSeries::Shape);
105    }
106
107    #[test]
108    fn parse_canonical_java_form() {
109        assert_eq!("menk_shape".parse::<CodeType>().unwrap(), CodeType::MenkShape);
110        assert_eq!("Menk_Shape".parse::<CodeType>().unwrap(), CodeType::MenkShape);
111        assert_eq!("ZVVNMOD".parse::<CodeType>().unwrap(), CodeType::Zvvnmod);
112        assert_eq!("z52".parse::<CodeType>().unwrap(), CodeType::Z52);
113    }
114
115    #[test]
116    fn parse_php_alias() {
117        assert_eq!("menkshape".parse::<CodeType>().unwrap(), CodeType::MenkShape);
118        assert_eq!("menkletter".parse::<CodeType>().unwrap(), CodeType::MenkLetter);
119    }
120
121    #[test]
122    fn canonical_roundtrips() {
123        for ct in [
124            CodeType::Zvvnmod,
125            CodeType::Delehi,
126            CodeType::MenkShape,
127            CodeType::MenkLetter,
128            CodeType::Oyun,
129            CodeType::Utn57,
130            CodeType::Z52,
131        ] {
132            assert_eq!(ct.canonical_str().parse::<CodeType>().unwrap(), ct);
133        }
134    }
135
136    #[test]
137    fn unknown_errors() {
138        assert!(matches!(
139            "nope".parse::<CodeType>(),
140            Err(MongolConvertError::UnsupportedEnumType(_))
141        ));
142        assert!(CodeType::get("").is_err());
143    }
144
145    #[test]
146    fn utn57_shape_parses_and_prints_like_menk_shape() {
147        assert_eq!(CodeType::get("utn57_shape").unwrap(), CodeType::Utn57Shape);
148        assert_eq!(CodeType::get("UTN57SHAPE").unwrap(), CodeType::Utn57Shape);
149        assert_eq!(CodeType::Utn57Shape.canonical_str(), "utn57_shape");
150        assert_eq!(CodeType::Utn57Shape.code_series(), CodeSeries::Letter);
151    }
152}