warlocks_cauldron/providers/spec/
da.rs1use std::iter::zip;
2
3use super::super::{Datetime, Datelike, Local, dependencies::*};
4
5
6pub 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 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 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 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}