pesel_rs/
human_redable.rs

1use super::*;
2
3/// Stores the PESEL as is, in human redable form.
4///
5/// Used when frequently reading the human redable representation without accessing the individual
6/// fields.
7#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
8#[cfg_attr(feature = "serde", derive(serde::Serialize))]
9pub struct Pesel(u64);
10
11impl_try_from_str_for_pesel!(Pesel);
12
13#[cfg(feature = "serde")]
14impl_pesel_deserializer!(Pesel);
15
16impl From<Pesel> for u64 {
17    fn from(value: Pesel) -> Self {
18        value.0
19    }
20}
21
22impl From<&Pesel> for u64 {
23    fn from(value: &Pesel) -> Self {
24        value.0
25    }
26}
27
28impl TryFrom<u64> for Pesel {
29    type Error = ValidationError;
30
31    fn try_from(value: u64) -> Result<Self, Self::Error> {
32        validate(value)?;
33        Ok(Self(value))
34    }
35}
36
37impl From<crate::bit_fields::Pesel> for Pesel {
38    fn from(value: crate::bit_fields::Pesel) -> Self {
39        Self(u64::from(value))
40    }
41}
42
43impl PeselTrait for Pesel {
44    fn day_section(&self) -> u8 {
45        day_section(self)
46    }
47
48    fn month_section(&self) -> u8 {
49        month_section(self)
50    }
51
52    fn year_section(&self) -> u8 {
53        year_section(self)
54    }
55
56    fn ordinal_section(&self) -> u16 {
57        ordinal_section(self)
58    }
59
60    fn control_section(&self) -> u8 {
61        control_section(self)
62    }
63}
64
65impl AsRef<u64> for Pesel {
66    fn as_ref(&self) -> &u64 {
67        &self.0
68    }
69}
70
71#[cfg(test)]
72mod tests {
73    use super::*;
74    use std::sync::LazyLock;
75
76    static PESEL1: LazyLock<Pesel> = LazyLock::new(|| Pesel::try_from(02290486168).unwrap());
77    static PESEL2: LazyLock<Pesel> = LazyLock::new(|| Pesel::try_from(01302534699).unwrap());
78    static PESEL3: LazyLock<Pesel> = LazyLock::new(|| Pesel::try_from(00010128545).unwrap());
79    static PESEL4: LazyLock<Pesel> = LazyLock::new(|| Pesel::try_from(98250993285).unwrap());
80    static PESEL5: LazyLock<Pesel> = LazyLock::new(|| Pesel::try_from(60032417874).unwrap());
81
82    #[test]
83    fn day_section() {
84        assert_eq!(PESEL1.day_section(), 04);
85        assert_eq!(PESEL2.day_section(), 25);
86        assert_eq!(PESEL3.day_section(), 01);
87        assert_eq!(PESEL4.day_section(), 09);
88        assert_eq!(PESEL5.day_section(), 24);
89    }
90
91    #[test]
92    fn month_section() {
93        assert_eq!(PESEL1.month_section(), 29);
94        assert_eq!(PESEL2.month_section(), 30);
95        assert_eq!(PESEL3.month_section(), 01);
96        assert_eq!(PESEL4.month_section(), 25);
97        assert_eq!(PESEL5.month_section(), 03);
98    }
99
100    #[test]
101    fn year_section() {
102        assert_eq!(PESEL1.year_section(), 02);
103        assert_eq!(PESEL2.year_section(), 01);
104        assert_eq!(PESEL3.year_section(), 00);
105        assert_eq!(PESEL4.year_section(), 98);
106        assert_eq!(PESEL5.year_section(), 60);
107    }
108
109    #[test]
110    fn ordinal_section() {
111        assert_eq!(PESEL1.ordinal_section(), 8616);
112        assert_eq!(PESEL2.ordinal_section(), 3469);
113        assert_eq!(PESEL3.ordinal_section(), 2854);
114        assert_eq!(PESEL4.ordinal_section(), 9328);
115        assert_eq!(PESEL5.ordinal_section(), 1787);
116    }
117
118    #[test]
119    fn control_section() {
120        assert_eq!(PESEL1.control_section(), 8);
121        assert_eq!(PESEL2.control_section(), 9);
122        assert_eq!(PESEL3.control_section(), 5);
123        assert_eq!(PESEL4.control_section(), 5);
124        assert_eq!(PESEL5.control_section(), 4);
125    }
126
127    #[test]
128    fn day() {
129        assert_eq!(PESEL1.day(), 04);
130        assert_eq!(PESEL2.day(), 25);
131        assert_eq!(PESEL3.day(), 01);
132        assert_eq!(PESEL4.day(), 09);
133        assert_eq!(PESEL5.day(), 24);
134    }
135
136    #[test]
137    fn month() {
138        assert_eq!(PESEL1.month(), 09);
139        assert_eq!(PESEL2.month(), 10);
140        assert_eq!(PESEL3.month(), 01);
141        assert_eq!(PESEL4.month(), 05);
142        assert_eq!(PESEL5.month(), 03);
143    }
144
145    #[test]
146    fn year() {
147        assert_eq!(PESEL1.year(), 2002);
148        assert_eq!(PESEL2.year(), 2001);
149        assert_eq!(PESEL3.year(), 1900);
150        assert_eq!(PESEL4.year(), 2098);
151        assert_eq!(PESEL5.year(), 1960);
152    }
153
154    #[test]
155    fn date_of_birth() {
156        assert_eq!(
157            PESEL1.date_of_birth(),
158            NaiveDate::from_ymd_opt(2002, 09, 04).unwrap()
159        );
160        assert_eq!(
161            PESEL2.date_of_birth(),
162            NaiveDate::from_ymd_opt(2001, 10, 25).unwrap()
163        );
164        assert_eq!(
165            PESEL3.date_of_birth(),
166            NaiveDate::from_ymd_opt(1900, 01, 01).unwrap()
167        );
168        assert_eq!(
169            PESEL4.date_of_birth(),
170            NaiveDate::from_ymd_opt(2098, 05, 09).unwrap()
171        );
172        assert_eq!(
173            PESEL5.date_of_birth(),
174            NaiveDate::from_ymd_opt(1960, 03, 24).unwrap()
175        );
176    }
177
178    #[test]
179    fn gender() {
180        assert_eq!(PESEL1.gender(), Gender::Female);
181        assert_eq!(PESEL2.gender(), Gender::Male);
182        assert_eq!(PESEL3.gender(), Gender::Female);
183        assert_eq!(PESEL4.gender(), Gender::Female);
184        assert_eq!(PESEL5.gender(), Gender::Male);
185    }
186
187    #[test]
188    fn invalid_pesels() {
189        assert_eq!(Pesel::try_from(4355), Err(ValidationError::TooShort(4)));
190        assert_eq!(
191            Pesel::try_from(435585930294485),
192            Err(ValidationError::TooLong(15))
193        );
194        assert_eq!(
195            Pesel::try_from(99990486167),
196            Err(ValidationError::BirthDate)
197        );
198        assert_eq!(
199            Pesel::try_from(02290486167),
200            Err(ValidationError::ControlDigit)
201        );
202    }
203
204    #[test]
205    fn try_from_strings() {
206        assert_eq!(
207            PESEL1.to_owned(),
208            Pesel::try_from(&String::from("02290486168")).unwrap()
209        );
210        assert_eq!(
211            PESEL2.to_owned(),
212            Pesel::try_from(&String::from("01302534699")).unwrap()
213        );
214        assert_eq!(
215            PESEL3.to_owned(),
216            Pesel::try_from(&String::from("00010128545")).unwrap()
217        );
218        assert_eq!(
219            PESEL4.to_owned(),
220            Pesel::try_from(&String::from("98250993285")).unwrap()
221        );
222        assert_eq!(
223            PESEL5.to_owned(),
224            Pesel::try_from(&String::from("60032417874")).unwrap()
225        );
226    }
227
228    #[test]
229    #[cfg(feature = "serde")]
230    fn deserialize() {
231        use serde_json::{from_value, json};
232
233        assert_eq!(
234            PESEL1.to_owned(),
235            from_value::<Pesel>(json!("02290486168")).expect("Valid PESEL")
236        );
237        assert_eq!(
238            PESEL1.to_owned(),
239            from_value::<Pesel>(json!(02290486168u64)).expect("Valid PESEL")
240        );
241
242        assert_eq!(
243            PESEL2.to_owned(),
244            from_value::<Pesel>(json!("01302534699")).expect("Valid PESEL")
245        );
246        assert_eq!(
247            PESEL2.to_owned(),
248            from_value::<Pesel>(json!(01302534699u64)).expect("Valid PESEL")
249        );
250
251        assert_eq!(
252            PESEL3.to_owned(),
253            from_value::<Pesel>(json!("00010128545")).expect("Valid PESEL")
254        );
255        assert_eq!(
256            PESEL3.to_owned(),
257            from_value::<Pesel>(json!(00010128545u64)).expect("Valid PESEL")
258        );
259
260        assert_eq!(
261            PESEL4.to_owned(),
262            from_value::<Pesel>(json!("98250993285")).expect("Valid PESEL")
263        );
264        assert_eq!(
265            PESEL4.to_owned(),
266            from_value::<Pesel>(json!(98250993285u64)).expect("Valid PESEL")
267        );
268
269        assert_eq!(
270            PESEL5.to_owned(),
271            from_value::<Pesel>(json!("60032417874")).expect("Valid PESEL")
272        );
273        assert_eq!(
274            PESEL5.to_owned(),
275            from_value::<Pesel>(json!(60032417874u64)).expect("Valid PESEL")
276        );
277    }
278
279    #[test]
280    #[cfg(feature = "serde")]
281    fn invalid_deserialize() {
282        use serde_json::{from_value, json};
283
284        from_value::<Pesel>(json!("60036817874")).expect_err("Invalid PESEL");
285        from_value::<Pesel>(json!(60036817874u64)).expect_err("Invalid PESEL");
286
287        from_value::<Pesel>(json!("00006817874")).expect_err("Invalid PESEL");
288        from_value::<Pesel>(json!(00006817874u64)).expect_err("Invalid PESEL");
289
290        from_value::<Pesel>(json!("02290486167")).expect_err("Invalid PESEL");
291        from_value::<Pesel>(json!(02290486167u64)).expect_err("Invalid PESEL");
292    }
293}