use super::funejson::Value; use super::validation_gs1_check_digit::gs1_check_digit; /// Build an 18-digit SSCC: extension digit, GS1 company prefix, zero-padded /// serial reference and GS1 mod-10 check digit. /// /// # Panics /// Panics on an extension digit outside 0-9, a prefix that is not 4 to 12 /// ASCII digits, or a serial reference that is negative or too long. pub fn build_sscc(extension_digit: i64, company_prefix: &str, serial_reference: i64) -> String { if !(0..=9).contains(&extension_digit) { panic!("extensionDigit must be 0 to 9, received {}", extension_digit); } let len = company_prefix.len(); if !(4..=12).contains(&len) || !company_prefix.bytes().all(|b| b.is_ascii_digit()) { panic!("companyPrefix must be 4 to 12 digits, received \"{}\"", company_prefix); } if serial_reference < 0 { panic!("serialReference must not be negative, received {}", serial_reference); } // Prefix and serial share 16 digits, so a longer prefix leaves less room. // Too large is an error: truncating would reuse another unit's number. let room = 16 - len; let serial = serial_reference.to_string(); if serial.len() > room { panic!( "serialReference must fit in {} digits after a {}-digit company prefix, received {}", room, len, serial_reference ); } let data = format!("{}{}{:0>width$}", extension_digit, company_prefix, serial, width = room); format!("{}{}", data, gs1_check_digit(&data)) } pub fn fune_vector(args: &[Value]) -> Value { Value::str(&build_sscc(args[0].as_i64(), args[1].as_str(), args[2].as_i64())) }