Functional Weave
Code in TypeScript

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()))
}