Functional Weave
Code in Rust

text.mask@1.0.0

impl/rust.rs

1,595 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

/// 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<char> = value.chars().collect();
    let mut out: Vec<char> = 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(),
    ))
}