codes_check_digits/sedol.rs
1/*!
2The type [CheckDigitAlgorithm] provides an implementation of the check
3digit calculation as part of the SEDOL specification.
4
5# Example
6
7```rust
8use codes_check_digits::{sedol, Calculator};
9
10let calculator = sedol::get_algorithm_instance();
11assert!(calculator.is_valid("0540528"));
12assert!(calculator.validate("0540528").is_ok());
13assert_eq!(calculator.calculate("054052"), Ok(8));
14 ```
15
16*/
17
18use crate::{
19 common::{ascii_alphanum_to_u8, is_ascii_alphanumeric_upper_no_vowels, is_length_eq},
20 error::CheckDigitError,
21 Calculator,
22};
23
24// ------------------------------------------------------------------------------------------------
25// Public Types
26// ------------------------------------------------------------------------------------------------
27
28///
29/// Validate the SEDOL numbers defined by the London Stock Exchange
30///
31#[derive(Clone, Copy, Debug, Default)]
32pub struct CheckDigitAlgorithm {}
33
34// ------------------------------------------------------------------------------------------------
35// Public Functions
36// ------------------------------------------------------------------------------------------------
37
38const SHARED_INSTANCE: CheckDigitAlgorithm = CheckDigitAlgorithm {};
39
40pub const fn get_algorithm_instance() -> &'static CheckDigitAlgorithm {
41 &SHARED_INSTANCE
42}
43
44// ------------------------------------------------------------------------------------------------
45// Implementations
46// ------------------------------------------------------------------------------------------------
47
48const WEIGHTS: [u16; 6] = [1, 3, 1, 7, 3, 9];
49
50impl Calculator<u8> for CheckDigitAlgorithm {
51 fn name(&self) -> &'static str {
52 "Stock Exchange Daily Official List (SEDOL)"
53 }
54
55 fn calculate(&self, s: &str) -> Result<u8, CheckDigitError> {
56 is_length_eq(s, 6)?;
57 is_ascii_alphanumeric_upper_no_vowels(s)?;
58 let sum: u16 = s
59 .chars()
60 .enumerate()
61 .map(|(i, c)| (ascii_alphanum_to_u8(c) as u16) * WEIGHTS[i])
62 .sum();
63
64 Ok(((10 - (sum % 10)) % 10) as u8)
65 }
66}
67
68// ------------------------------------------------------------------------------------------------
69// Unit Tests
70// ------------------------------------------------------------------------------------------------
71
72#[cfg(test)]
73mod tests {
74 use crate::sedol::CheckDigitAlgorithm;
75 use crate::Calculator;
76
77 #[test]
78 fn test_validate_hsbc() {
79 let sedol = CheckDigitAlgorithm::default();
80 assert!(sedol.is_valid("0540528"));
81 assert_eq!(sedol.calculate("054052"), Ok(8));
82 }
83}