use super::funejson::Value; /// Only these two are separators: they are how card and sort-code numbers are /// printed. fn is_separator(ch: char) -> bool { ch == ' ' || ch == '-' } /// Mask all but the last `visible` characters of `value` with `mask_char`. /// /// Characters are Unicode code points (`char`), so an emoji counts once and /// the result has as many code points as the input. /// /// # Panics /// Panics if `visible` is negative or `mask_char` is not exactly one character. pub fn mask(value: &str, visible: i64, mask_char: &str, keep_separators: bool) -> String { if visible < 0 { panic!("visible must be 0 or greater, received {}", visible); } let mut mask_chars = mask_char.chars(); let replacement = match (mask_chars.next(), mask_chars.next()) { (Some(c), None) => c, _ => panic!("maskChar must be exactly one character, received \"{}\"", mask_char), }; let chars: Vec = value.chars().collect(); let mut out: Vec = vec![replacement; chars.len()]; let mut shown: i64 = 0; // Walk from the end so "the last n" is counted without a second pass. for i in (0..chars.len()).rev() { let ch = chars[i]; if keep_separators && is_separator(ch) { out[i] = ch; } else if shown < visible { out[i] = ch; shown += 1; } } out.into_iter().collect() } pub fn fune_vector(args: &[Value]) -> Value { Value::Str(mask( args[0].as_str(), args[1].as_i64(), args[2].as_str(), args[3].as_bool(), )) }