1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
use std::cmp;

const CPF_LENGTH: usize = 11;

pub fn reserved_numbers() -> Vec<String> {
    vec![
        String::from("00000000000"),
        String::from("11111111111"),
        String::from("22222222222"),
        String::from("33333333333"),
        String::from("44444444444"),
        String::from("55555555555"),
        String::from("66666666666"),
        String::from("77777777777"),
        String::from("88888888888"),
        String::from("99999999999"),
    ]
}

pub fn format(cpf: &str) -> String {
    let cpf = cpf.matches(char::is_numeric).collect::<Vec<_>>().concat();

    if cpf.len() > 3 && cpf.len() <= 6 {
        format!("{}.{}", &cpf[0..3], &cpf[3..cpf.len()])
    } else if cpf.len() >= 7 && cpf.len() <= 9 {
        format!("{}.{}.{}", &cpf[0..3], &cpf[3..6], &cpf[6..cpf.len()])
    } else if cpf.len() >= 10 {
        let end_position = cmp::min(cpf.len(), CPF_LENGTH);
        format!(
            "{}.{}.{}-{}",
            &cpf[0..3],
            &cpf[3..6],
            &cpf[6..9],
            &cpf[9..end_position]
        )
    } else {
        cpf
    }
}

pub fn is_valid(cpf: &str) -> bool {
    if cpf.matches(char::is_lowercase).count() > 0 || cpf.matches(char::is_uppercase).count() > 0 {
        return false;
    }

    let cpf = cpf.matches(char::is_numeric).collect::<Vec<_>>().concat();

    let reserved_numbers = reserved_numbers();

    !cpf.is_empty() && cpf.len() == CPF_LENGTH && !reserved_numbers.contains(&cpf) && validate(cpf)
}

fn validate(cpf: String) -> bool {
    let cpf = cpf.matches(char::is_numeric).collect::<Vec<_>>();

    let sum = check_sum(&cpf, 10);

    let digit1: u32 = calc_digit(sum);

    let mut sum: u32 = check_sum(&cpf, 11);
    sum += digit1 * 2;
    let digit2: u32 = calc_digit(sum);

    cpf[9].parse::<u32>().unwrap() == digit1 && cpf[10].parse::<u32>().unwrap() == digit2
}

fn check_sum(cpf: &[&str], factor: u32) -> u32 {
    let mut sum: u32 = 0;
    let mut factor: u32 = factor;
    for n in cpf.iter().take(9) {
        sum += n.parse::<u32>().unwrap() * factor;
        factor -= 1;
    }

    sum
}

fn calc_digit(sum: u32) -> u32 {
    let mod_sum1 = sum % 11;

    if mod_sum1 < 2 {
        0
    } else {
        11 - mod_sum1
    }
}