1use super::*;
2
3#[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}