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