Skip to main content

easyofd_core/signatures/
check_method.rs

1//! 摘要算法枚举(CheckMethod)。
2//!
3//! 对应 Java: org.ofdrw.core.signatures.range.CheckMethod
4//!
5//! GB/T 33190 第 18.2.2 节,用于签名范围(References)中指定摘要算法。
6
7/// 摘要算法枚举。
8///
9/// 对应 Java: `org.ofdrw.core.signatures.range.CheckMethod`
10///
11/// 在签名的范围(References)中使用,标识对受保护文件计算摘要时所用的算法。
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
13pub enum CheckMethod {
14    /// MD5 摘要算法(默认值)。
15    Md5,
16    /// SHA-1 摘要算法。
17    Sha1,
18    /// SHA-256 摘要算法。
19    Sha256,
20    /// SM3 国密杂凑算法。
21    Sm3,
22}
23
24impl CheckMethod {
25    /// 返回与 Java `CheckMethod.toString()` 一致的属性字符串。
26    ///
27    /// 产出值直接用于 XML 属性 `CheckMethod="..."` 的值。
28    ///
29    /// # 示例
30    ///
31    /// ```
32    /// use easyofd_core::signatures::CheckMethod;
33    ///
34    /// assert_eq!(CheckMethod::Md5.as_str(), "MD5");
35    /// assert_eq!(CheckMethod::Sha1.as_str(), "SHA1");
36    /// assert_eq!(CheckMethod::Sha256.as_str(), "SHA256");
37    /// assert_eq!(CheckMethod::Sm3.as_str(), "SM3");
38    /// ```
39    #[must_use]
40    pub fn as_str(&self) -> &'static str {
41        match self {
42            Self::Md5 => "MD5",
43            Self::Sha1 => "SHA1",
44            Self::Sha256 => "SHA256",
45            Self::Sm3 => "SM3",
46        }
47    }
48
49    /// 从字符串解析摘要算法(不区分大小写)。
50    ///
51    /// # 错误
52    ///
53    /// 无法识别的算法名称返回 `Err`。
54    ///
55    /// # 示例
56    ///
57    /// ```
58    /// use easyofd_core::signatures::CheckMethod;
59    ///
60    /// assert_eq!(CheckMethod::try_from_str("SM3").unwrap(), CheckMethod::Sm3);
61    /// assert_eq!(CheckMethod::try_from_str("sha256").unwrap(), CheckMethod::Sha256);
62    /// assert!(CheckMethod::try_from_str("UNKNOWN").is_err());
63    /// ```
64    pub fn try_from_str(s: &str) -> Result<Self, String> {
65        match s.to_uppercase().as_str() {
66            "MD5" => Ok(Self::Md5),
67            "SHA1" => Ok(Self::Sha1),
68            "SHA256" => Ok(Self::Sha256),
69            "SM3" => Ok(Self::Sm3),
70            other => Err(format!("未知的摘要算法: {other}")),
71        }
72    }
73}
74
75/// 为 `CheckMethod` 实现 `Display`,产出与 `as_str()` 一致。
76impl std::fmt::Display for CheckMethod {
77    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
78        f.write_str(self.as_str())
79    }
80}
81
82#[cfg(test)]
83mod tests {
84    use super::*;
85
86    #[test]
87    fn as_str_matches_java() {
88        // 确保与 Java 枚举 toString() 产出完全一致
89        assert_eq!(CheckMethod::Md5.as_str(), "MD5");
90        assert_eq!(CheckMethod::Sha1.as_str(), "SHA1");
91        assert_eq!(CheckMethod::Sha256.as_str(), "SHA256");
92        assert_eq!(CheckMethod::Sm3.as_str(), "SM3");
93    }
94
95    #[test]
96    fn display_matches_as_str() {
97        for method in [
98            CheckMethod::Md5,
99            CheckMethod::Sha1,
100            CheckMethod::Sha256,
101            CheckMethod::Sm3,
102        ] {
103            assert_eq!(method.to_string(), method.as_str());
104        }
105    }
106
107    #[test]
108    fn try_from_str_roundtrip() {
109        for method in [
110            CheckMethod::Md5,
111            CheckMethod::Sha1,
112            CheckMethod::Sha256,
113            CheckMethod::Sm3,
114        ] {
115            let s = method.as_str();
116            let parsed = CheckMethod::try_from_str(s).unwrap();
117            assert_eq!(parsed, method);
118        }
119    }
120
121    #[test]
122    fn try_from_str_case_insensitive() {
123        assert_eq!(
124            CheckMethod::try_from_str("sha1").unwrap(),
125            CheckMethod::Sha1
126        );
127        assert_eq!(
128            CheckMethod::try_from_str("Sha256").unwrap(),
129            CheckMethod::Sha256
130        );
131        assert_eq!(CheckMethod::try_from_str("sm3").unwrap(), CheckMethod::Sm3);
132        assert_eq!(CheckMethod::try_from_str("md5").unwrap(), CheckMethod::Md5);
133    }
134
135    #[test]
136    fn try_from_str_unknown() {
137        assert!(CheckMethod::try_from_str("UNKNOWN").is_err());
138        assert!(CheckMethod::try_from_str("").is_err());
139    }
140
141    #[test]
142    fn copy_eq() {
143        let a = CheckMethod::Sm3;
144        let b = a;
145        assert_eq!(a, b);
146    }
147
148    #[test]
149    fn hash_works() {
150        use std::collections::HashSet;
151        let mut set = HashSet::new();
152        set.insert(CheckMethod::Md5);
153        set.insert(CheckMethod::Sha1);
154        set.insert(CheckMethod::Sha256);
155        set.insert(CheckMethod::Sm3);
156        assert_eq!(set.len(), 4);
157        assert!(set.contains(&CheckMethod::Sm3));
158    }
159}