#[must_use]
pub fn gs1_check_digit(data_digits: &[u8]) -> u8 {
let sum: u32 = data_digits
.iter()
.rev()
.enumerate()
.map(|(i, &d)| u32::from(d) * if i % 2 == 0 { 3 } else { 1 })
.sum();
((10 - (sum % 10)) % 10) as u8
}
pub(super) enum Gs1KeyCheck {
InvalidFormat,
InvalidCheckDigit { expected: u8, actual: u8 },
}
pub(super) fn check_gs1_key(s: &str, len: usize) -> Result<(), Gs1KeyCheck> {
if s.len() != len || !s.bytes().all(|b| b.is_ascii_digit()) {
return Err(Gs1KeyCheck::InvalidFormat);
}
debug_assert!(
len <= 14,
"check_gs1_key only supports keys up to 14 digits"
);
let mut digits = [0u8; 14];
for (i, b) in s.bytes().enumerate() {
digits[i] = b - b'0';
}
let expected = gs1_check_digit(&digits[..len - 1]);
if digits[len - 1] != expected {
return Err(Gs1KeyCheck::InvalidCheckDigit {
expected,
actual: digits[len - 1],
});
}
Ok(())
}