document_validator 0.2.0

Document validation library
Documentation
use std::sync::Arc;

use super::Document;
use crate::prelude::*;

const LAWSUIT_NUMBER_LENGTH: usize = 20;

#[derive(PartialEq, Eq, Hash)]
pub struct LawsuitNumber(Arc<str>);

impl AsRef<str> for LawsuitNumber {
    fn as_ref(&self) -> &str {
        self.0.as_ref()
    }
}

impl Document for LawsuitNumber {
    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 document = document.replace(|x: char| !x.is_ascii_digit(), "");

        if document.len() != LAWSUIT_NUMBER_LENGTH {
            return false;
        }

        // The `unwrap`s below will never panic, because `document` is
        // a 20 character long string containing only digits
        let seed = format!("{}{}", &document[..7], &document[9..]);

        let r1 = seed[..7].parse::<u32>().unwrap() % 97;
        let r2 = format!("{r1}{}", &seed[7..14]).parse::<u32>().unwrap() % 97;
        let r3 = format!("{r2}{}00", &seed[14..]).parse::<u32>().unwrap() % 97;

        let digits = 98 - r3;

        document[7..9].parse::<u32>().unwrap() == digits
    }

    fn document_name(&self) -> &'static str {
        "lawsuit_number"
    }
}