use std::sync::Arc;
use super::Document;
use crate::prelude::*;
const CNPJ_LENGTH: usize = 14;
#[derive(PartialEq, Eq, Hash)]
pub struct Cnpj(Arc<str>);
impl AsRef<str> for Cnpj {
fn as_ref(&self) -> &str {
self.0.as_ref()
}
}
impl Cnpj {
fn generate_digit(digits: &[u8]) -> u8 {
let c = digits.len();
let result = digits
.iter()
.enumerate()
.map(|(index, digit)| *digit as usize * ((c - 1 - index) % 8 + 2))
.sum::<usize>();
let result = 11 - (result % 11);
if result < 10 {
result as u8
} else {
0
}
}
}
impl Document for Cnpj {
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() != CNPJ_LENGTH {
return false;
}
let first_digit = Self::generate_digit(&digits[..CNPJ_LENGTH - 2]);
if first_digit != digits[CNPJ_LENGTH - 2] {
return false;
}
let second_digit = Self::generate_digit(&digits[..CNPJ_LENGTH - 1]);
second_digit == digits[CNPJ_LENGTH - 1]
}
fn document_name(&self) -> &'static str {
"cnpj"
}
}