warlocks_cauldron/providers/spec/
da.rs

1use std::iter::zip;
2
3use super::super::{Datetime, Datelike, Local, dependencies::*};
4
5
6/// Methods collection provides special data for Denmark (da)
7pub struct DenmarkSpecProvider;
8
9impl DenmarkSpecProvider {
10    fn calculate_century_selector(year: i32) -> i32 {
11        if 1858 <= year && year < 1900 {
12            return randint(5, 8);
13        } else if 1900 <= year && year < 1937 {
14            return randint(0, 3);
15        } else if 1937 <= year && year < 2000 {
16            return get_random_element(vec![4, 9].into_iter());
17        } else if 2000 <= year && year < 2037 {
18            return randint(4, 9);
19        }
20
21        panic!("Invalid year!")
22    }
23
24    /// 
25    fn calculate_checksum(cpr_nr_no_checksum: String) -> u32 {
26        let cpr_digits: Vec<u32> = cpr_nr_no_checksum.chars()
27            .into_iter().map(|c| c.to_digit(10).unwrap()).collect();
28        
29        let checksum_factors = vec![4, 3, 2, 7, 6, 5, 4, 3, 2];
30
31        let remainder: u32 = zip(cpr_digits, checksum_factors)
32            .into_iter().map(|(d, c)| d * c).sum();
33
34        match remainder % 11 {
35            0 => 0,
36            other => 11 - other,
37        }
38    }
39
40    /// Generate a serial number and checksum from cpr_century
41    fn generate_serial_checksum(cpr_century: &str) -> (String, u32) {
42        let serial_number = format!("{:02}", randint(0, 99));
43        let cpr_nr_no_checksum  = format!("{cpr_century}{serial_number}");
44        let checksum = Self::calculate_checksum(cpr_nr_no_checksum);
45
46        if checksum == 10 {
47            Self::generate_serial_checksum(cpr_century)
48        } else {
49            (serial_number, checksum)
50        }
51    }
52
53    /// Generate a random CPR number (Central Person Registry)
54    pub fn cpr() -> String {
55        let now = Local::now().year();
56        let date = Datetime::date(now - 100, now);
57        let cpr_date = date.format("%d%m%y").to_string();
58        let century_selector = Self::calculate_century_selector(date.year());
59        let cpr_century = format!("{cpr_date}{century_selector}");
60        let (serial_number, checksum) = Self::generate_serial_checksum(&cpr_century);
61        format!("{cpr_century}{serial_number}{checksum}")
62    }
63}