validation.gs1-check-digit@1.0.0
impl/rust/gs1_check_digit.rs
1,223 bytes · the Rust implementation · view raw
Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.
use super::funejson::Value; ← the fune runtime: the JSON value the test vectors use; fune build keeps it only where a signature takes one
/// The GS1 mod-10 check digit for `data`, the digits of a GS1 key without its
/// check digit. One rule serves every key length because the weights are
/// counted from the right: 3, 1, 3, 1 ... starting with the digit that will sit
/// next to the check digit. Counting from the left instead only works for
/// EAN-13 and the other even-length data strings.
///
/// # Panics
/// Panics unless `data` is one or more ASCII digits.
pub fn gs1_check_digit(data: &str) -> i64 {
if data.is_empty() || !data.bytes().all(|b| b.is_ascii_digit()) {
panic!("GS1 data must be one or more ASCII digits, received {:?}", data);
}
let mut total: u32 = 0;
let mut weight: u32 = 3;
for b in data.bytes().rev() {
// Reducing as we go keeps the sum small for data of any length.
total = (total + (b - b'0') as u32 * weight) % 10;
weight = if weight == 3 { 1 } else { 3 };
}
((10 - total) % 10) as i64
}
pub fn fune_vector(args: &[Value]) -> Value {
// A non-string argument arrives as an empty string, which is refused with
// the same message the other two languages give for a non-string.
Value::Int(gs1_check_digit(args[0].as_str()))
}