domain_core/bits/
serial.rs1use std::{cmp, fmt, str};
9use bytes::BufMut;
10use chrono::{Utc, TimeZone};
11use ::master::scan::{CharSource, Scan, ScanError, Scanner, SyntaxError};
12use super::compose::Compose;
13use super::parse::{Parse, ParseAll, Parser};
14
15
16#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
39pub struct Serial(pub u32);
40
41impl Serial {
42 #[allow(should_implement_trait)]
53 pub fn add(self, other: u32) -> Self {
54 assert!(other <= 0x7FFF_FFFF);
55 Serial(self.0.wrapping_add(other))
56 }
57
58 pub fn scan_rrsig<C: CharSource>(
64 scanner: &mut Scanner<C>
65 ) -> Result<Self, ScanError> {
66 scanner.scan_phrase(
67 (0, [0u8; 14]),
68 |&mut (ref mut pos, ref mut buf), symbol| {
69 let ch = symbol.into_digit(10)? as u8;
70 if *pos == 14 {
71 return Err(SyntaxError::IllegalInteger) }
73 buf[*pos] = ch;
74 *pos += 1;
75 Ok(())
76 },
77 |(pos, buf)| {
78 if pos <= 10 {
79 let mut res = 0u64;
82 for ch in &buf[..pos] {
83 res = res *10 + (u64::from(*ch));
84 }
85 if res > u64::from(::std::u32::MAX) {
86 Err(SyntaxError::IllegalInteger)
87 }
88 else {
89 Ok(Serial(res as u32))
90 }
91 }
92 else if pos == 14 {
93 let year = u32_from_buf(&buf[0..4]) as i32;
94 let month = u32_from_buf(&buf[4..6]);
95 let day = u32_from_buf(&buf[6..8]);
96 let hour = u32_from_buf(&buf[8..10]);
97 let minute = u32_from_buf(&buf[10..12]);
98 let second = u32_from_buf(&buf[12..14]);
99 match month {
100 1 | 3 | 5 | 7 | 8 | 10 | 12 => {
101 if month > 31 {
102 return Err(SyntaxError::IllegalInteger)
103 }
104 }
105 4 | 6 | 9 | 11 => {
106 if month > 30 {
107 return Err(SyntaxError::IllegalInteger)
108 }
109 }
110 2 => {
111 if year % 4 == 0 && year % 100 != 0 {
112 if month > 29 {
113 return Err(SyntaxError::IllegalInteger)
114 }
115 }
116 else if month > 28 {
117 return Err(SyntaxError::IllegalInteger)
118 }
119 }
120 _ => {
121 return Err(SyntaxError::IllegalInteger)
122 }
123 }
124 if month < 1 || hour > 23 || minute > 59 || second > 59 {
125 return Err(SyntaxError::IllegalInteger)
126 }
127 Ok(Serial(
128 Utc.ymd(year, month, day)
129 .and_hms(hour, minute, second)
130 .timestamp() as u32
131 ))
132 }
133 else {
134 Err(SyntaxError::IllegalInteger) }
136 }
137 )
138 }
139}
140
141
142impl From<u32> for Serial {
145 fn from(value: u32) -> Serial {
146 Serial(value)
147 }
148}
149
150impl From<Serial> for u32 {
151 fn from(serial: Serial) -> u32 {
152 serial.0
153 }
154}
155
156impl str::FromStr for Serial {
157 type Err = <u32 as str::FromStr>::Err;
158
159 fn from_str(s: &str) -> Result<Self, Self::Err> {
160 <u32 as str::FromStr>::from_str(s).map(Into::into)
161 }
162}
163
164
165impl Parse for Serial {
168 type Err = <u32 as Parse>::Err;
169
170 fn parse(parser: &mut Parser) -> Result<Self, Self::Err> {
171 u32::parse(parser).map(Into::into)
172 }
173
174 fn skip(parser: &mut Parser) -> Result<(), Self::Err> {
175 u32::skip(parser)
176 }
177}
178
179impl ParseAll for Serial {
180 type Err = <u32 as ParseAll>::Err;
181
182 fn parse_all(parser: &mut Parser, len: usize) -> Result<Self, Self::Err> {
183 u32::parse_all(parser, len).map(Into::into)
184 }
185}
186
187impl Compose for Serial {
188 fn compose_len(&self) -> usize {
189 self.0.compose_len()
190 }
191
192 fn compose<B: BufMut>(&self, buf: &mut B) {
193 self.0.compose(buf)
194 }
195}
196
197
198impl Scan for Serial {
201 fn scan<C: CharSource>(scanner: &mut Scanner<C>)
202 -> Result<Self, ScanError> {
203 u32::scan(scanner).map(Into::into)
204 }
205}
206
207impl fmt::Display for Serial {
208 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
209 write!(f, "{}", self.0)
210 }
211}
212
213
214impl cmp::PartialOrd for Serial {
217 fn partial_cmp(&self, other: &Serial) -> Option<cmp::Ordering> {
218 if self.0 == other.0 {
219 Some(cmp::Ordering::Equal)
220 }
221 else if self.0 < other.0 {
222 let sub = other.0 - self.0;
223 if sub < 0x8000_0000 {
224 Some(cmp::Ordering::Less)
225 }
226 else if sub > 0x8000_0000 {
227 Some(cmp::Ordering::Greater)
228 }
229 else {
230 None
231 }
232 }
233 else {
234 let sub = self.0 - other.0;
235 if sub < 0x8000_0000 {
236 Some(cmp::Ordering::Greater)
237 }
238 else if sub > 0x8000_0000 {
239 Some(cmp::Ordering::Less)
240 }
241 else {
242 None
243 }
244 }
245 }
246}
247
248
249fn u32_from_buf(buf: &[u8]) -> u32 {
252 let mut res = 0;
253 for ch in buf {
254 res = res * 10 + (u32::from(*ch));
255 }
256 res
257}
258
259
260#[cfg(test)]
263mod test {
264 use super::*;
265
266 #[test]
267 fn good_addition() {
268 assert_eq!(Serial(0).add(4), Serial(4));
269 assert_eq!(Serial(0xFF00_0000).add(0x0F00_0000),
270 Serial(((0xFF00_0000u64 + 0x0F00_0000u64)
271 % 0x1_0000_0000) as u32));
272 }
273
274 #[test]
275 #[should_panic]
276 fn bad_addition() {
277 let _ = Serial(0).add(0x8000_0000);
278 }
279
280 #[test]
281 fn comparison() {
282 use std::cmp::Ordering::*;
283
284 assert_eq!(Serial(12), Serial(12));
285 assert_ne!(Serial(12), Serial(112));
286
287 assert_eq!(Serial(12).partial_cmp(&Serial(12)), Some(Equal));
288
289 assert_eq!(Serial(12).partial_cmp(&Serial(13)), Some(Less));
292 assert_ne!(Serial(12).partial_cmp(&Serial(3_000_000_012)), Some(Less));
293
294 assert_eq!(Serial(3_000_000_012).partial_cmp(&Serial(12)), Some(Less));
296 assert_ne!(Serial(13).partial_cmp(&Serial(12)), Some(Less));
297
298 assert_eq!(Serial(12).partial_cmp(&Serial(3_000_000_012)),
301 Some(Greater));
302 assert_ne!(Serial(12).partial_cmp(&Serial(13)), Some(Greater));
303
304 assert_eq!(Serial(13).partial_cmp(&Serial(12)), Some(Greater));
306 assert_ne!(Serial(3_000_000_012).partial_cmp(&Serial(12)),
307 Some(Greater));
308
309 assert_eq!(Serial(1).partial_cmp(&Serial(0x8000_0001)), None);
311 assert_eq!(Serial(0x8000_0001).partial_cmp(&Serial(1)), None);
312 }
313}