use std::sync::Arc;
use super::Document;
use crate::prelude::*;
const CPF_LENGTH: usize = 11;
#[derive(PartialEq, Eq, Hash)]
pub struct Cpf(Arc<str>);
impl AsRef<str> for Cpf {
fn as_ref(&self) -> &str {
self.0.as_ref()
}
}
impl Cpf {
fn generate_digit(digits: &[u8]) -> u8 {
let c = digits.len();
let result = digits
.iter()
.enumerate()
.map(|(index, digit)| *digit as usize * (c + 1 - index))
.sum::<usize>();
let result = 11 - (result % 11);
if result < 10 {
result as u8
} else {
0
}
}
}
impl Document for Cpf {
fn new(document: impl Into<Arc<str>>) -> Result<Self> {
let document: Arc<str> = document
.into()
.chars()
.filter(char::is_ascii_digit)
.collect::<String>()
.into();
if Self::validate(Arc::clone(&document)) {
Ok(Self(document))
} else {
Err(Error::ParseError(document))
}
}
fn validate(document: impl Into<Arc<str>>) -> bool {
let document: Arc<str> = document.into();
let digits = document
.bytes()
.filter(u8::is_ascii_digit)
.map(|x| x - b'0')
.collect::<Vec<_>>();
if digits.len() != CPF_LENGTH {
return false;
}
let first_digit = Self::generate_digit(&digits[..CPF_LENGTH - 2]);
if first_digit != digits[CPF_LENGTH - 2] {
return false;
}
let second_digit = Self::generate_digit(&digits[..CPF_LENGTH - 1]);
second_digit == digits[CPF_LENGTH - 1]
}
fn document_name(&self) -> &'static str {
"cpf"
}
}