SS3WJJYQDOWW5XXQG2I7PF4NB45ON6QXU46MLH2C35WSGT2HKEZQC
use crate::{Rg, EmitterOrg};
use std::fmt;
use std::fmt::Formatter;
impl Rg {
/// Creates a new RG object
///
/// # Example
/// ```
/// use validbr::Rg;
/// use validbr::UF::SP;
/// use validbr::EmitterOrg::SSP;
///
/// let rg = Rg::new("A15987B-X", SSP(SP));
/// assert_eq!(rg, Rg { code: "A15987B-X".to_string(), emitter_org: SSP(SP) })
/// ```
pub fn new(code: &str, emitter_org: EmitterOrg) -> Rg {
Rg {
code: code.to_string(),
emitter_org
}
}
/// Creates a new RG object
///
/// # Example
/// ```
/// use validbr::Rg;
/// use validbr::UF::SP;
/// use validbr::EmitterOrg::SSP;
///
/// let rg = Rg::from_string("A15987B-X".to_string(), SSP(SP));
/// assert_eq!(rg, Rg { code: "A15987B-X".to_string(), emitter_org: SSP(SP) })
/// ```
pub fn from_string(code: String, emitter_org: EmitterOrg) -> Rg {
Rg {
code,
emitter_org
}
}
}
impl fmt::Display for Rg {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{} {}", self.code, self.emitter_org)
}
}
// validbr - Brazilian registry validator, provides structures for representing CPF, CNPJ, RG, CNH, CEP and Credit Card Number!
//
// The MIT License (MIT)
//
// Copyright (c) Obliter Software (https://github.com/oblitersoftware/)
// Copyright (c) contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
/// Converts every [`i32`] in iterator `$iter` to a [`u8`] value.
#[macro_export]
macro_rules! convert_to_u8 {
($iter:expr) => {
$iter.map(|i| {
let u: Option<u8> = i.to_digit(10).and_then(|i| i.try_into().ok());
u
})
};
}
/// Converts each item of `$expr` to [`String`] and then join all them into a single [`String`]
/// without any separator.
#[macro_export]
macro_rules! join_to_string {
($exp:expr) => {
$exp.iter().map(|d| d.to_string()).collect::<String>()
};
}
// validbr - Brazilian registry validator, provides structures for representing CPF, CNPJ, RG, CNH, CEP and Credit Card Number!
//
// The MIT License (MIT)
//
// Copyright (c) Obliter Software (https://github.com/oblitersoftware/)
// Copyright (c) contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//! Representation of Brazilian registries: CPF, CNPJ, RG, CNH, CEP and Credit Card Number.
//!
//! validbr also provides validation for CPJ, CNPJ, CNH and Credit Card Number and a builtin database
//! of brazilian CEP, Cities and States.
//!
//! # Cpf
//!
//! Consist in 9 digits separated in partitions of 3 with `.` and two verifier digits separated by a `-` prefix,
//! for example: `123.456.789-09`.
//!
//! ## Example of usage of CPF struct
//!
//! ```
//! use validbr::Cpf;
//! let cpf = Cpf::parse_str("123.456.789-09");
//! assert_eq!(cpf, Ok(Cpf { digits: [1, 2, 3, 4, 5, 6, 7, 8, 9], verifier_digits: [0, 9]}));
//! ```
//!
//! ## Supported formats
//!
//! [`Cpf::parse_str`] only supports following formats:
//! - `###.###.###-##` (Commonly represented CPF)
//! - `###########` (Only digits CPF).
//!
//! # CNPJ
//!
//! Consists in eight numbers separated by a `.` in partitions for 3 (except for the first two digits
//! which are separated from the last two groups), a company branch number digit composed of four digits,
//! separated by a prefix `/` and two last verifier digits prefixed with `-`, example: `12.345.678/0001-95`.
//!
//! ## Example of usage of CNPJ struct
//!
//! ```
//! use validbr::Cnpj;
//! let cpf = Cnpj::parse_str("12.345.678/0001-95");
//! assert_eq!(cpf, Ok(Cnpj { digits: [1, 2, 3, 4, 5, 6, 7, 8], branch_digits: [0, 0, 0, 1], verifier_digits: [9, 5]}));
//! ```
//!
//! ## Supported formats
//!
//! [`Cnpj::parse_str`] only supports following formats:
//! - `##.###.###/####-##` (Commonly represented CNPJ)
//! - `##############` (Only digits CNPJ).
//!
//! # Features
//!
//! ## [Serde](https://crates.io/crates/serde) support
//!
//! validbr supports [serde](https://crates.io/crates/serde) serialization, which must be enabled with feature flag, for example:
//!
//! ```toml
//! [dependencies]
//! validbr = { version = "0.2", features = ["serde"] }
//! ```
//!
//! ## [rand](https://crates.io/crates/rand) support
//!
//! validbr also supports randomly generated CPF and CNPJ through [rand](https://crates.io/crates/serde) crate,
//! which must be enabled with feature flag, for example:
//!
//! ```toml
//! [dependencies]
//! validbr = { version = "0.2", features = ["rand"] }
//! ```
//!
//! ## Enable all
//!
//! You could enable all features using `complete` flag:
//! ```toml
//! [dependencies]
//! validbr = { version = "0.2", features = ["complete"] }
//! ```
#![feature(doc_cfg)]
#![feature(const_evaluatable_checked, const_generics, const_panic)]
#![allow(incomplete_features)]
#[macro_use]
extern crate lazy_static;
use regex::Regex;
#[macro_use] pub(crate) mod macros;
/// Array append utilities.
pub mod append;
/// Cnpj utility functions
pub mod cnpj;
/// Cpf utility functions
pub mod cpf;
/// RG utility functions
pub mod rg;
#[cfg(feature = "serde")]
use {
serde::Serialize,
serde::Deserialize
};
use crate::EmitterOrg::SSP;
use std::fmt::Formatter;
lazy_static! {
pub(crate) static ref NOT_NUMBERS: Regex = Regex::new(r"[^0-9]+").unwrap();
pub(crate) static ref ONLY_NUMBERS: Regex = Regex::new(r"^[0-9]+$").unwrap();
}
/// CPF consists of nine digits and two verifier digits.
///
/// The algorithm to calculate the first verifier digit is:
///
/// ```
/// let digits = [0u16; 9];
/// let checker_digits = [0u16; 2];
///
/// let sum_of_mul = ((digits[8] * 10) + (digits[7] * 9) + (digits[6] * 8) + (digits[5] * 7) + (digits[4] * 6) +
/// (digits[3] * 5) + (digits[2] * 4) + (digits[1] * 3) + (digits[0] * 2)) as u16;
/// let pre_first_digit = ((sum_of_mul * 10) % 11) as u8;
/// let first_digit = if pre_first_digit == 10 {
/// 0
/// } else {
/// pre_first_digit
/// };
/// ```
///
/// And the algorithm to calculate the second verifier digit is:
///
/// ```
/// let digits = [0u16; 9];
/// let checker_digits = [0u16; 2];
///
/// let sum_of_mul = ((digits[8] * 11) + (digits[7] * 10) + (digits[6] * 9) + (digits[5] * 8) + (digits[4] * 7) +
/// (digits[3] * 6) + (digits[2] * 5) + (digits[1] * 4) + (digits[0] * 3) + (checker_digits[0] * 2)) as u16;
/// let pre_second_digit = ((sum_of_mul * 10) % 11) as u8;
/// let second_digit = if pre_second_digit == 10 {
/// 0
/// } else {
/// pre_second_digit
/// };
/// ```
///
///
/// These numbers could be obtained through `[calculate_verifier_digits]`.
#[derive(Debug, Eq, PartialEq, Hash, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Cpf {
/// First 9 digits of CPF.
pub digits: [u8; 9],
/// Last 2 digits of CPF (the verifier digits).
pub verifier_digits: [u8; 2],
}
/// CNPJ consists of eight based digits, four digits for the branch (the number of the registered
/// company) and two verifier digits.
///
/// The algorithm to calculate the first verifier digit is:
///
/// ```
/// let digits = [0u16; 8];
/// let branch_num_digits = [0u16; 4];
/// let checker_digits = [0u16; 2];
///
/// let sum_of_mul = ((digits[0] * 5) + (digits[1] * 4) + (digits[2] * 3) + (digits[3] * 2) + (digits[4] * 9) +
/// (digits[5] * 8) + (digits[6] * 7) + (digits[7] * 6) + (branch_num_digits[0] * 5) + (branch_num_digits[1] * 4) +
/// (branch_num_digits[2] * 3) + (branch_num_digits[3] * 2)) as u16;
/// let pre_first_digit = (sum_of_mul % 11) as u8;
/// let first_digit = if pre_first_digit < 2 {
/// 0
/// } else {
/// 11 - pre_first_digit
/// };
///
/// // And the algorithm to calculate the second verifier digit is:
///
/// let sum_of_mul_2 = ((digits[0] * 5) + (digits[1] * 4) + (digits[2] * 3) + (digits[3] * 2) + (digits[4] * 9) +
/// (digits[5] * 8) + (digits[6] * 7) + (digits[7] * 6) + (branch_num_digits[0] * 5) + (branch_num_digits[1] * 4) +
/// (branch_num_digits[2] * 3) + (branch_num_digits[3] * 2)) as u16;
/// let pre_second_digit = (sum_of_mul_2 % 11) as u8;
/// let second_digit = if pre_second_digit < 2 {
/// 0
/// } else {
/// 11 - pre_second_digit
/// };
/// ```
///
///
/// These numbers could be obtained through `[calculate_verifier_digits]`.
#[derive(Debug, Eq, PartialEq, Hash, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Cnpj {
/// First 8 digits of Cnpj.
pub digits: [u8; 8],
/// Four digits of branch.
pub branch_digits: [u8; 4],
/// Last 2 digits of CPF (the verifier digits).
pub verifier_digits: [u8; 2],
}
/// RG does not have a standard for its format,
/// so validbr uses [`String`] representing the RG code.
/// Some emitters uses modulo 11 validation, others don't, some of them uses number only
/// with verifier digit, others don't and includes Letters and special chars.
///
/// See [`Rg::new`] for examples of Rg construction.
#[derive(Debug, Eq, PartialEq, Hash, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Rg {
/// RG code/Number.
pub code: String,
// RG emitter organization.
pub emitter_org: EmitterOrg
}
/// List of governmental organizations which emits Brazilian Registries.
#[derive(Debug, Eq, PartialEq, Hash, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum EmitterOrg {
SSP(UF),
PoliciaFedaral,
CartorioCivil,
Other(String)
}
impl std::fmt::Display for EmitterOrg {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
return match self {
SSP(uf) => {
write!(f, "SSP{}", uf)
},
EmitterOrg::PoliciaFedaral => {
write!(f, "Polícia Federal")
},
EmitterOrg::CartorioCivil => {
write!(f, "Cartório Civil")
}
EmitterOrg::Other(other) => {
write!(f, "{}", other)
}
}
}
}
/// List of Brazilian Federative Units (Unidades Federativas).
#[derive(Debug, Eq, PartialEq, Hash, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum UF {
AC,
AL,
AP,
AM,
BA,
CE,
DF,
ES,
GO,
MA,
MT,
MS,
MG,
PA,
PB,
PR,
PE,
PI,
RJ,
RN,
RS,
RO,
RR,
SC,
SP,
SE,
TO
}
impl std::fmt::Display for UF {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self)
}
}
#[cfg(test)]
mod tests {
use crate::EmitterOrg::SSP;
use crate::UF::SP;
#[cfg(feature = "rand")]
#[test]
fn random_cpf() {
use rand::Rng;
use crate::Cpf;
let mut rng = rand::thread_rng();
let cpf: Cpf = rng.gen();
let verifier = crate::cpf::calculate_verifier_digits(cpf.digits);
assert_eq!(verifier.0, cpf.verifier_digits[0]);
assert_eq!(verifier.1, cpf.verifier_digits[1]);
}
#[cfg(feature = "rand")]
#[test]
fn random_cnpj() {
use rand::Rng;
use crate::Cnpj;
let mut rng = rand::thread_rng();
let cnpj: Cnpj = rng.gen();
let verifier = crate::cnpj::calculate_verifier_digits(cnpj.digits, cnpj.branch_digits);
assert_eq!(verifier.0, cnpj.verifier_digits[0]);
assert_eq!(verifier.1, cnpj.verifier_digits[1]);
}
#[cfg(feature = "rand")]
#[test]
fn random_cnpj_with_specific_branch() {
use rand::Rng;
use crate::Cnpj;
use crate::cnpj::Branch;
let mut rng = rand::thread_rng();
let branch = Branch::from_u8(0012).unwrap();
let cnpj: Cnpj = rng.sample(branch);
assert_eq!([0, 0, 1, 2], cnpj.branch_digits);
let verifier = crate::cnpj::calculate_verifier_digits(cnpj.digits, cnpj.branch_digits);
assert_eq!(verifier.0, cnpj.verifier_digits[0]);
assert_eq!(verifier.1, cnpj.verifier_digits[1]);
}
#[test]
fn rg() {
use crate::Rg;
let rg = Rg::new("A8974B-X", SSP(SP));
assert_eq!(format!("{}", rg), "A8974B-X SSPSP");
}
}
// validbr - Brazilian registry validator, provides structures for representing CPF, CNPJ, RG, CNH, CEP and Credit Card Number!
//
// The MIT License (MIT)
//
// Copyright (c) Obliter Software (https://github.com/oblitersoftware/)
// Copyright (c) contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//! # CPF
//!
//! This module provides utility for constructing and manipulating CPF, as well as validating CPFs. If
//! a CPF was successfully constructed with [`Cpf::new`] or [`Cpf::parse_str`] it means that the CPF
//! is valid.
use crate::append::ArrayAppend;
use crate::{ONLY_NUMBERS, Cpf};
use crate::NOT_NUMBERS;
use crate::convert_to_u8;
use crate::join_to_string;
use crate::cpf::CpfCreationError::CouldNotConvertCpfToDigits;
use regex::Regex;
use std::convert::TryInto;
use std::fmt;
use std::fmt::Formatter;
#[cfg(feature = "rand")]
use {
rand::distributions::{Distribution, Standard, Uniform},
rand::Rng,
};
lazy_static! {
static ref WELL_FORMATTED_CPF: Regex = Regex::new(r"\d{3}\.\d{3}\.\d{3}-\d{2}").unwrap();
}
/// Formats Cpf in the well known format:
/// 000.000.000-00
/// # Example
///
/// ```
/// use validbr::Cpf;
/// let cpf = Cpf::parse_str("887.614.320-32").expect("Invalid cpf.");
/// assert_eq!(format!("{}", cpf), "887.614.320-32")
/// ```
impl fmt::Display for Cpf {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let f3 = join_to_string!(&self.digits[..3]);
let m3 = join_to_string!(&self.digits[3..6]);
let e3 = join_to_string!(&self.digits[6..9]);
let verifier = join_to_string!(self.verifier_digits);
write!(f, "{}.{}.{}-{}", f3, m3, e3, verifier)
}
}
#[derive(Debug, Eq, PartialEq)]
pub enum CpfCreationError {
/// When provided Cpf digits could not be validated against their verifier digits, in other
/// words, when provided Cpf is not valid.
InvalidCpfDigits,
/// When provided Cpf string is not a valid Cpf format.
///
/// Supported Cpf formats are:
/// - 000.000.000-00
/// - 00000000000
InvalidCpfStringFormat,
/// When type conversion failure occurs.
CouldNotConvertCpfToDigits,
/// When provided Cpf string is too short.
ShortCpfString,
/// When provided numbers for digits (cpf digits or validation digits)
/// are out of bounds, in other words, they are not respecting the range of `0..=9`.
/// All numbers in the digits array must respect the range `0..=9`.
DigitsOutOfBounds,
}
#[derive(Debug, Eq, PartialEq)]
pub enum DigitCalculationError {
/// When the amount of digits provided for calculation does
WrongAmountOfDigits(usize),
}
type VerifierDigits = (u8, u8);
impl Cpf {
/// Creates a new Cpf if the provided `[digits]` and `[verifier_digits]` are valid.
///
/// # Example
/// ```
/// use validbr::Cpf;
///
/// let cpf = Cpf::new([3, 1, 0, 1, 2, 6, 6, 5, 0], [5, 4]); // Valid CPF
/// assert!(cpf.is_ok());
/// ```
///
/// ```
/// use validbr::Cpf;
/// use validbr::cpf::CpfCreationError;
///
/// let cpf = Cpf::new([1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 0]); // Invalid CPF
/// assert_eq!(cpf, Err(CpfCreationError::InvalidCpfDigits));
/// ```
pub fn new(digits: [u8; 9], verifier_digits: [u8; 2]) -> Result<Cpf, CpfCreationError> {
let digits_is_valid = digits.iter().all(|i| *i <= 9);
let verifier_digits_is_valid = verifier_digits.iter().all(|i| *i <= 9);
if !digits_is_valid || !verifier_digits_is_valid {
return Err(CpfCreationError::DigitsOutOfBounds)
}
let (first_verifier_digit, second_verifier_digit) = calculate_verifier_digits(digits);
if first_verifier_digit != verifier_digits[0]
|| second_verifier_digit != verifier_digits[1] {
Err(CpfCreationError::InvalidCpfDigits)
} else {
Ok(Cpf {
digits,
verifier_digits,
})
}
}
/// Parses a Cpf String to a [`Cpf`].
///
/// Supported Cpf formats are:
///
/// - 000.000.000-00
/// - 00000000000
///
/// # Examples
///
/// ```
/// use validbr::Cpf;
/// let cpf = Cpf::parse_str("261.442.230-45");
/// assert!(cpf.is_ok());
/// assert_eq!(cpf, Ok(Cpf { digits: [2, 6, 1, 4, 4, 2, 2, 3, 0], verifier_digits: [4, 5]}));
/// ```
///
/// ```
/// use validbr::Cpf;
/// let cpf = Cpf::parse_str("26144223045");
/// assert!(cpf.is_ok());
/// assert_eq!(cpf, Ok(Cpf { digits: [2, 6, 1, 4, 4, 2, 2, 3, 0], verifier_digits: [4, 5]}));
/// ```
///
/// ```
/// use validbr::Cpf;
/// let cpf = Cpf::parse_str("12345678909");
/// assert!(cpf.is_ok());
/// assert_eq!(cpf, Ok(Cpf { digits: [1, 2, 3, 4, 5, 6, 7, 8, 9], verifier_digits: [0, 9]}));
/// ```
pub fn parse_str(cpf: &str) -> Result<Cpf, CpfCreationError> {
let only_numbers = ONLY_NUMBERS.is_match(cpf);
if only_numbers && cpf.len() != 11 {
return Err(CpfCreationError::ShortCpfString);
}
if (ONLY_NUMBERS.is_match(cpf) && cpf.len() == 11) || (WELL_FORMATTED_CPF.is_match(cpf)) {
let cpf_only_with_numbers = NOT_NUMBERS.replace_all(cpf, "");
let digits_vec: Option<Vec<u8>> =
convert_to_u8!(cpf_only_with_numbers.chars().take(9)).collect();
let validators_vec: Option<Vec<u8>> =
convert_to_u8!(cpf_only_with_numbers.chars().skip(9)).collect();
let digits_array: Option<[u8; 9]> = digits_vec.and_then(|v| v.try_into().ok());
let validators_array: Option<[u8; 2]> = validators_vec.and_then(|v| v.try_into().ok());
if let Some(digits) = digits_array {
if let Some(validators) = validators_array {
Cpf::new(digits, validators)
} else {
Err(CouldNotConvertCpfToDigits)
}
} else {
Err(CouldNotConvertCpfToDigits)
}
} else {
Err(CpfCreationError::InvalidCpfStringFormat)
}
}
}
/// Calculates the verifier digit given input `cpf_digits`.
///
/// This function does not care about the amount of digits provided to it, but the correct amount
/// of digits to be provided to this function is either 9 CPF digits or 10 values
/// (9 CPF digits and first verifier digit). When provided with 9 CPF digits, the function calculates
/// the first verifier digits, when provided with 10 values (9 CPF digits and first verifier digit),
/// the function calculates the second verifier digits.
///
/// # Example
///
/// ```
/// use validbr::cpf::calculate_verifier_digit;
/// use validbr::cpf::DigitCalculationError::WrongAmountOfDigits;
///
/// assert_eq!(calculate_verifier_digit([4, 1, 4, 9, 0, 4, 2, 5, 7]), 8);
/// assert_eq!(calculate_verifier_digit([4, 1, 4, 9, 0, 4, 2, 5, 7, 8]), 0);
/// assert_eq!(calculate_verifier_digit([4, 1, 4, 9, 0, 4, 2, 5, 7, 8, 10]), 2);
/// assert_eq!(calculate_verifier_digit([4, 1, 4, 9, 0, 4, 2, 5]), 7);
/// assert_eq!(calculate_verifier_digit([4, 1, 4, 9, 0, 4, 2]), 8);
/// ```
///
pub fn calculate_verifier_digit<const S: usize>(cpf_digits: [u8; S]) -> u8 {
let modulo_num = S + 1;
let digits_sum: u16 = cpf_digits
.iter()
.enumerate()
.map(|(pos, digit)| (*digit as u16) * ((modulo_num - pos) as u16))
.sum();
let pre_verifier = ((digits_sum * 10) % 11) as u8;
if pre_verifier == 10 {
0
} else {
pre_verifier
}
}
/// Calculate both first and second verifier digits, given the `digits` input.
///
/// # Example
///
/// ```
/// use validbr::Cpf;
/// use validbr::cpf::DigitCalculationError::WrongAmountOfDigits;
/// use validbr::cpf::calculate_verifier_digits;
///
/// assert_eq!(calculate_verifier_digits([4, 1, 4, 9, 0, 4, 2, 5, 7]), (8, 0));
/// assert_eq!(calculate_verifier_digits([1, 2, 3, 4, 5, 6, 7, 8, 9]), (0, 9));
/// ```
pub fn calculate_verifier_digits(digits: [u8; 9]) -> VerifierDigits {
let first_digit = calculate_verifier_digit::<9>(digits);
let digits_with_first_verifier: [u8; 10] = digits.append(first_digit);
let second_digit = calculate_verifier_digit::<10>(digits_with_first_verifier);
(first_digit, second_digit)
}
/// ## Random CPF Example
///
/// ```
/// use validbr::Cpf;
/// use validbr::cpf::*;
/// use rand::Rng;
/// let mut rng = rand::thread_rng();
/// let cpf: Cpf = rng.gen();
/// let verifier = validbr::cpf::calculate_verifier_digits(cpf.digits);
///
/// assert_eq!(verifier.0, cpf.verifier_digits[0]);
/// assert_eq!(verifier.1, cpf.verifier_digits[1]);
/// ```
#[cfg(feature = "rand")]
impl Distribution<Cpf> for Standard {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Cpf {
let uniform_int = Uniform::from(0u8..=9u8);
let digits: Vec<u8> = rng.sample_iter(uniform_int)
.take(9)
.collect();
let digits_array: [u8; 9] = digits.try_into()
.expect("Conversion of Vec with 9 elements MUST be possible at this point.");
let (first, second) = calculate_verifier_digits(digits_array);
Cpf::new(digits_array, [first, second])
.expect("Generated Cpf MUST be valid at this point")
}
}
// validbr - Brazilian registry validator, provides structures for representing CPF, CNPJ, RG, CNH, CEP and Credit Card Number!
//
// The MIT License (MIT)
//
// Copyright (c) Obliter Software (https://github.com/oblitersoftware/)
// Copyright (c) contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//! # CNPJ
//!
//! This module provides utility for constructing and manipulating CNPJ, as well as validating CNPJs. If
//! a CNPJ was successfully constructed with [`Cnpj::new`] or [`Cnpj::parse_str`] it means that the CNPJ
//! is valid.
//!
//!
//!
use crate::append::ArrayAppend;
use crate::cnpj::CnpjCreationError::CouldNotConvertCnpjToDigits;
use crate::{ONLY_NUMBERS, Cnpj};
use crate::NOT_NUMBERS;
use crate::convert_to_u8;
use crate::join_to_string;
use regex::Regex;
use std::convert::TryInto;
use std::fmt;
use std::fmt::Formatter;
#[cfg(feature = "rand")]
use {
rand::distributions::{Distribution, Standard, Uniform},
rand::Rng,
};
lazy_static! {
static ref WELL_FORMATTED_CNPJ: Regex = Regex::new(r"\d{2}\.\d{3}\.\d{3}/\d{4}-\d{2}").unwrap();
}
/// Formats Cnpj in the well known format:
/// 00.000.000/0000-00
/// # Example
///
/// ```
/// use validbr::Cnpj;
///
/// let cnpj = Cnpj::parse_str("80.906.404/0001-88").expect("Invalid cnpj.");
/// assert_eq!(format!("{}", cnpj), "80.906.404/0001-88")
/// ```
impl fmt::Display for Cnpj {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let f3 = join_to_string!(&self.digits[..2]);
let m3 = join_to_string!(&self.digits[2..5]);
let e3 = join_to_string!(&self.digits[5..8]);
let branch = join_to_string!(self.branch_digits);
let verifier = join_to_string!(self.verifier_digits);
write!(f, "{}.{}.{}/{}-{}", f3, m3, e3, branch, verifier)
}
}
#[derive(Debug, Eq, PartialEq)]
pub enum CnpjCreationError {
/// When provided Cnpj digits could not be validated against their verifier digits, in other
/// words, when provided Cnpj is not valid.
InvalidCnpjDigits,
/// When provided Cnpj string is not a valid Cnpj format.
///
/// Supported Cpf formats are:
/// - 00.000.000/0000-00
/// - 00000000000000
InvalidCnpjStringFormat,
/// When type conversion failure occurs.
CouldNotConvertCnpjToDigits,
/// When provided Cnpj string is too short.
ShortCnpjString,
/// When provided numbers for digits (cnpj digits, branch digits or validation digits)
/// are out of bounds, in other words, they are not respecting the range of `0..=9`.
/// All numbers in the digits array must respect the range `0..=9`.
DigitsOutOfBounds,
}
#[derive(Debug, Eq, PartialEq)]
pub enum DigitCalculationError {
/// When the amount of digits provided for calculation does
WrongAmountOfDigits(usize),
}
type VerifierDigits = (u8, u8);
impl Cnpj {
/// Creates a new Cnpj if the provided `[digits]`, `[branch_digits]` and `[verifier_digits]` are valid.
///
/// # Example
/// ```
/// use validbr::Cnpj;
///
/// let cnpj = Cnpj::new([5, 3, 8, 7, 1, 1, 4, 3], [0, 0, 0, 1], [3, 5]); // Valid CPF
/// assert!(cnpj.is_ok());
/// ```
///
/// ```
/// use validbr::Cnpj;
/// use validbr::cnpj::CnpjCreationError;
///
/// let cnpj = Cnpj::new([8, 0, 9, 0, 6, 4, 0, 4], [0, 0, 0, 3], [8, 8]); // Invalid CPF
/// assert_eq!(cnpj, Err(CnpjCreationError::InvalidCnpjDigits));
/// ```
pub fn new(
digits: [u8; 8],
branch_digits: [u8; 4],
verifier_digits: [u8; 2],
) -> Result<Cnpj, CnpjCreationError> {
let digits_is_valid = digits.iter().all(|i| *i <= 9);
let branch_digits_is_valid = branch_digits.iter().all(|i| *i <= 9);
let verifier_digits_is_valid = verifier_digits.iter().all(|i| *i <= 9);
if !digits_is_valid || !branch_digits_is_valid || !verifier_digits_is_valid {
return Err(CnpjCreationError::DigitsOutOfBounds)
}
let (first_verifier_digit, second_verifier_digit) =
calculate_verifier_digits(digits, branch_digits);
if first_verifier_digit != verifier_digits[0]
|| second_verifier_digit != verifier_digits[1] {
Err(CnpjCreationError::InvalidCnpjDigits)
} else {
Ok(Cnpj {
digits,
branch_digits,
verifier_digits,
})
}
}
/// Parses a Cnpj String to a [`Cnpj`].
///
/// Supported Cnpj formats are:
///
/// - 000.000.000-00
/// - 00000000000
///
/// # Examples
///
/// ```
/// use validbr::Cnpj;
/// let cnpj = Cnpj::parse_str("53.871.143/0001-35");
/// assert!(cnpj.is_ok());
/// assert_eq!(cnpj, Ok(Cnpj { digits: [5, 3, 8, 7, 1, 1, 4, 3], branch_digits: [0, 0, 0, 1], verifier_digits: [3, 5]}));
/// ```
///
/// ```
/// use validbr::Cnpj;
/// let cnpj = Cnpj::parse_str("53871143000135");
/// assert!(cnpj.is_ok());
/// assert_eq!(cnpj, Ok(Cnpj { digits: [5, 3, 8, 7, 1, 1, 4, 3], branch_digits: [0, 0, 0, 1], verifier_digits: [3, 5]}));
/// ```
pub fn parse_str(cnpj: &str) -> Result<Cnpj, CnpjCreationError> {
let only_numbers = ONLY_NUMBERS.is_match(cnpj);
if only_numbers && cnpj.len() != 14 {
return Err(CnpjCreationError::ShortCnpjString);
}
return if (ONLY_NUMBERS.is_match(cnpj) && cnpj.len() == 14) || (WELL_FORMATTED_CNPJ.is_match(cnpj))
{
let cnpj_only_with_numbers = NOT_NUMBERS.replace_all(cnpj, "");
let digits_vec: Option<Vec<u8>> =
convert_to_u8!(cnpj_only_with_numbers.chars().take(8)).collect();
let branch_digits_vec: Option<Vec<u8>> =
convert_to_u8!(cnpj_only_with_numbers.chars().skip(8).take(4)).collect();
let validators_vec: Option<Vec<u8>> =
convert_to_u8!(cnpj_only_with_numbers.chars().skip(12)).collect();
let digits_array: Option<[u8; 8]> = digits_vec.and_then(|v| v.try_into().ok());
let branch_digits_array: Option<[u8; 4]> =
branch_digits_vec.and_then(|v| v.try_into().ok());
let validators_array: Option<[u8; 2]> = validators_vec.and_then(|v| v.try_into().ok());
if let Some(digits) = digits_array {
if let Some(validators) = validators_array {
if let Some(branch_digits) = branch_digits_array {
Cnpj::new(digits, branch_digits, validators)
} else {
Err(CouldNotConvertCnpjToDigits)
}
} else {
Err(CouldNotConvertCnpjToDigits)
}
} else {
Err(CouldNotConvertCnpjToDigits)
}
} else {
Err(CnpjCreationError::InvalidCnpjStringFormat)
};
}
}
/// Calculates the verifier digit given input `[cnpj_digits]`.
///
/// This function does not care about the amount of digits provided to it, but the correct amount
/// of digits to be provided to this function is either 12 CNPJ digits with branch digits or 13 values
/// (12 CNPJ digits with branch digits and first verifier digit). When provided with 12 CPF digits, the function calculates
/// the first verifier digits, when provided with 13 values (12 CNPJ digits and first verifier digit),
/// the function calculates the second verifier digits.
///
/// # Example
///
/// ```
/// use validbr::cnpj::calculate_verifier_digit;
/// use validbr::cnpj::DigitCalculationError::WrongAmountOfDigits;
///
/// assert_eq!(calculate_verifier_digit([5, 3, 8, 7, 1, 1, 4, 3, 0, 0, 0, 1]), 3);
/// assert_eq!(calculate_verifier_digit([5, 3, 8, 7, 1, 1, 4, 3, 0, 0, 0, 1, 3]), 5);
///
/// assert_eq!(calculate_verifier_digit([3, 4, 8, 5, 4, 6, 7, 8, 0, 0, 0, 1]), 5);
/// assert_eq!(calculate_verifier_digit([3, 4, 8, 5, 4, 6, 7, 8, 0, 0, 0, 1, 5]), 3);
///
/// assert_eq!(calculate_verifier_digit([3, 1, 2, 3, 8, 8, 2, 6, 0, 0, 0, 1]), 1);
/// assert_eq!(calculate_verifier_digit([3, 1, 2, 3, 8, 8, 2, 6, 0, 0, 0, 1, 1]), 7);
/// ```
///
pub fn calculate_verifier_digit<const S: usize>(cnpj_digits: [u8; S]) -> u8 {
let mul_digits: Vec<u8> = get_multiplier_values(S);
let digits_sum: u16 = cnpj_digits
.iter()
.enumerate()
.map(|(pos, digit)| (*digit as u16) * (mul_digits[pos] as u16))
.sum();
let pre_verifier_digit = (digits_sum % 11) as u8;
if pre_verifier_digit < 2 {
0
} else {
11 - pre_verifier_digit
}
}
/// Calculates the multiplier values for CNPJ verifier digit calculation given the `[amount]`
/// of digits.
///
/// The multiplier values must always end in 9, cycling from 9 to 2, and when reach 2, starts in 9 again
/// until 2.
///
/// # Example
///
/// ```
/// use validbr::cnpj::get_multiplier_values;
///
/// assert_eq!(get_multiplier_values(12), vec![5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2]);
/// assert_eq!(get_multiplier_values(13), vec![6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2]);
/// ```
///
pub fn get_multiplier_values(amount: usize) -> Vec<u8> {
let range = 2u8..=9u8;
let range_rev_cycle = range.cycle();
range_rev_cycle
.take(amount)
.collect::<Vec<u8>>()
.into_iter()
.rev()
.collect()
}
/// Calculate both first and second verifier digits, given the `[digits]` input.
///
/// # Example
///
/// ```
/// use validbr::Cnpj;
/// use validbr::cnpj::calculate_verifier_digits;
/// use validbr::cnpj::DigitCalculationError::WrongAmountOfDigits;
///
/// assert_eq!(calculate_verifier_digits([2, 7, 1, 4, 8, 7, 3, 4], [0, 0, 0, 1]), (7, 9));
/// assert_eq!(calculate_verifier_digits([1, 2, 3, 4, 5, 6, 7, 8], [9, 0, 1, 2]), (3, 0));
/// ```
pub fn calculate_verifier_digits(digits: [u8; 8], branch_digits: [u8; 4]) -> VerifierDigits {
let cnpj_digits: [u8; 12] = digits.append_array::<4>(branch_digits);
let first_digit = calculate_verifier_digit::<12>(cnpj_digits);
let digits_with_first_verifier: [u8; 13] = cnpj_digits.append(first_digit);
let second_digit = calculate_verifier_digit::<13>(digits_with_first_verifier);
(first_digit, second_digit)
}
/// ## Random CNPJ Example
///
/// ```
/// use validbr::Cnpj;
/// use validbr::cnpj::*;
/// use rand::Rng;
/// let mut rng = rand::thread_rng();
/// let cnpj: Cnpj = rng.gen();
///
/// let verifier = validbr::cnpj::calculate_verifier_digits(cnpj.digits, cnpj.branch_digits);
/// assert_eq!(verifier.0, cnpj.verifier_digits[0]);
/// assert_eq!(verifier.1, cnpj.verifier_digits[1]);
/// ```
#[cfg(feature = "rand")]
impl Distribution<Cnpj> for Standard {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Cnpj {
let uniform_int = Uniform::from(0u8..=9u8);
let digits: Vec<u8> = rng.sample_iter(uniform_int)
.take(8)
.collect();
let branch_digits: Vec<u8> = rng.sample_iter(uniform_int)
.take(4)
.collect();
let digits_array: [u8; 8] = digits.try_into()
.expect("Conversion of Vec with 8 elements MUST be possible at this point.");
let branch_digits_array: [u8; 4] = branch_digits.try_into()
.expect("Conversion of Vec with 4 elements MUST be possible at this point.");
let (first, second) = calculate_verifier_digits(digits_array, branch_digits_array);
Cnpj::new(digits_array, branch_digits_array, [first, second])
.expect("Generated Cnpj MUST be valid at this point")
}
}
/// Struct object used to generate random [`Cnpj`] based in provided [`Branch::0`] instead of
/// generating a random branch digit.
#[cfg_attr(feature = "rand", derive(Debug, Eq, PartialEq, Hash, Clone))]
pub struct Branch([u8; 4]);
#[cfg(feature = "rand")]
impl fmt::Display for Branch {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}", join_to_string!(self.0))
}
}
/// When branch number is not in the range of `0..=9999`.
#[cfg_attr(feature = "rand", derive(Debug, Eq, PartialEq, Hash, Clone))]
pub struct InvalidBranchNumber;
#[cfg(feature = "rand")]
impl Branch {
/// Creates the [`Branch`] object representing the first
/// company Cnpj number registered in the Brazilian Governmental Organizations responsible
/// for the Cnpj registration.
///
/// The first company branch is represented by the number `0001`.
pub fn first() -> Branch {
Branch([0, 0, 0, 1])
}
/// Creates a branch from provided `branch_digits`.
///
/// Every number in the `branch_digits` array must be in the range of `0..=9`,
/// otherwise this method will fail.
pub fn new(branch_digits: [u8; 4]) -> Result<Branch, InvalidBranchNumber> {
for b in &branch_digits {
if *b > 9 {
return Err(InvalidBranchNumber)
}
}
Ok(Branch(branch_digits))
}
/// Creates a Branch object from provided `branch_number`.
///
/// The `branch_number` must be in the range of `0..=9999`, otherwise this method will fail.
pub fn from_u8(branch_number: u16) -> Result<Branch, InvalidBranchNumber> {
if branch_number > 9999 {
return Err(InvalidBranchNumber)
}
let first_digit = (branch_number / 1000) as u8;
let second_digit = ((branch_number % 1000) / 100) as u8;
let third_digit = (((branch_number % 1000) % 100) / 10) as u8;
let fourth_digit = (((branch_number % 1000) % 100) % 10) as u8;
Branch::new([first_digit, second_digit, third_digit, fourth_digit])
}
}
/// ## Random CNPJ with specific branch example
///
/// ```
/// use validbr::Cnpj;
/// use validbr::cnpj::*;
/// use rand::Rng;
/// let mut rng = rand::thread_rng();
/// let branch = Branch::from_u8(0004).unwrap();
/// let cnpj: Cnpj = rng.sample(branch);
/// assert_eq!(cnpj.branch_digits, [0, 0, 0, 4])
/// ```
#[cfg(feature = "rand")]
impl Distribution<Cnpj> for Branch {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Cnpj {
let uniform_int = Uniform::from(0u8..=9u8);
let digits: Vec<u8> = rng.sample_iter(uniform_int)
.take(8)
.collect();
let digits_array: [u8; 8] = digits.try_into()
.expect("Conversion of Vec with 8 elements MUST be possible at this point.");
let (first, second) = calculate_verifier_digits(digits_array, self.0);
Cnpj::new(digits_array, self.0, [first, second])
.expect("Generated Cnpj MUST be valid at this point")
}
}
// validbr - Brazilian registry validator, provides structures for representing CPF, CNPJ, RG, CNH, CEP and Credit Card Number!
//
// The MIT License (MIT)
//
// Copyright (c) Obliter Software (https://github.com/oblitersoftware/)
// Copyright (c) contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
use std::convert::TryInto;
pub trait ArrayAppend<T, const S: usize> {
fn append(self, element: T) -> [T; S + 1];
fn append_array<const N: usize>(self, array: [T; N]) -> [T; S + N];
}
impl<T, const S: usize> ArrayAppend<T, S> for [T; S]
where
T: Clone,
{
fn append(self, element: T) -> [T; S + 1] {
let vec: Vec<T> = self
.to_vec()
.iter()
.map(|i| i.clone())
.chain(std::iter::once(element))
.collect();
let n_array: Result<[T; S + 1], _> = vec.try_into();
if let Ok(n_array) = n_array {
n_array
} else {
panic!();
}
}
fn append_array<const N: usize>(self, array: [T; N]) -> [T; S + N] {
let vec: Vec<T> = self
.to_vec()
.iter()
.map(|i| i.clone())
.chain(array.iter().map(|i| i.clone()))
.collect();
let n_array: Result<[T; S + N], _> = vec.try_into();
if let Ok(n_array) = n_array {
n_array
} else {
panic!();
}
}
}
[![Doc](https://docs.rs/validbr/badge.svg)](https://docs.rs/validbr)
[![Crate](https://img.shields.io/crates/v/validbr.svg)](https://crates.io/crates/validbr)
[![Github Release](https://img.shields.io/github/v/release/oblitersoftware/validbr?label=github%20release)](https://github.com/oblitersoftware/validbr/releases)
[![License: MIT](https://img.shields.io/crates/l/validbr)](https://opensource.org/licenses/MIT)
[![Build](https://github.com/oblitersoftware/validbr/workflows/Build/badge.svg)](https://github.com/oblitersoftware/validbr/actions?query=workflow%3ABuild)
[![Publish Crate](https://github.com/oblitersoftware/validbr/workflows/Publish%20Crate/badge.svg)](https://github.com/oblitersoftware/validbr/actions?query=workflow%3A%22Publish+Crate%22)
# validbr
Providing data structures and utilities for Brazilian Registries. Validbr is currently capable of validating CPF and CNPJ, but is planned to support:
- RG (structure only)
- CNH (validation and structure)
- CEP (database)
- State and City (database)
## Validation
validbr is capable of validating some Brazilian Registries types in regards of the number of these documents being valid, not in regards of them being registered in Brazilian Organizations. Currently there is no easy way of checking these values against Brazilian Organizations without paid services.
## Databases
validbr will be frequently updated to keep CEP, State and City databases updated. We may add neighbourhood database in the future, initially they will not be supported because the huge amount of them.
Examples:
# CPF
```rust
use validbr::Cpf;
let cpf = Cpf::parse_str("123.456.789-09");
assert_eq!(cpf, Ok(Cpf { digits: [1, 2, 3, 4, 5, 6, 7, 8, 9], verifier_digits: [0, 9]}));
```
# CNPJ
```rust
use validbr::Cnpj;
let cpf = Cnpj::parse_str("12.345.678/0001-95");
assert_eq!(cpf, Ok(Cnpj { digits: [1, 2, 3, 4, 5, 6, 7, 8], branch_digits: [0, 0, 0, 1], verifier_digits: [9, 5]}));
```
validbr - Brazilian registry validator, provides structures for representing CPF, CNPJ, RG, CNH, CEP and Credit Card Number!
The MIT License (MIT)
Copyright (c) Obliter Software (https://github.com/oblitersoftware/)
Copyright (c) contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
[package]
name = "validbr"
version = "0.2.1"
authors = ["oblitersofware", "JonathanxD <jhrldev@gmail.com>"]
edition = "2018"
license = "MIT"
license-file = "LICENSE"
description = "Provides data structure and validation for Brazilian Registries, such as CPF, CNPJ and CNH (currently only CPF and CNPJ is supported)"
homepage = "https://github.com/oblitersoftware/validbr"
repository = "https://github.com/oblitersoftware/validbr"
readme = "README.md"
keywords = ["validation", "brazil", "cpf", "cnpj"]
categories = ["data-structures", "internationalization", "parsing"]
documentation = "https://docs.rs/validbr/"
[package.metadata.docs.rs]
all-features = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[features]
complete = ["serde", "rand"]
[dependencies]
regex = "1.4.2"
lazy_static = "1.4.0"
serde = { version = "1.0.118", features = ["derive"], optional = true}
rand = { version = "0.8.0", optional = true}