1use crate::{
2 AsciiStr, Drift, Dt, Every, GregorianTime, Meridiem, Offset, Scale, Spacetime, TimeParts,
3 TimeRange, Weekday,
4};
5
6impl Dt {
7 pub const WIRE_VERSION: u8 = 1;
9
10 pub const WIRE_SIZE: usize = 17;
12
13 pub fn to_wire_bytes(&self) -> [u8; Self::WIRE_SIZE] {
24 let mut buf = [0u8; Self::WIRE_SIZE];
25 buf[0] = Self::WIRE_VERSION;
26 buf[1..9].copy_from_slice(&self.sec.to_le_bytes());
27 buf[9..17].copy_from_slice(&self.attos.to_le_bytes());
28 buf
29 }
30
31 pub fn from_wire_bytes(bytes: &[u8]) -> Option<Self> {
44 if bytes.len() != Self::WIRE_SIZE {
45 return None;
46 }
47
48 if bytes[0] != Self::WIRE_VERSION {
49 return None;
50 }
51
52 let sec = i64::from_le_bytes([
53 bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], bytes[8],
54 ]);
55 let subsec = u64::from_le_bytes([
56 bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15], bytes[16],
57 ]);
58
59 Some(Self::new(sec, subsec))
60 }
61}
62
63impl Drift {
64 pub const WIRE_VERSION: u8 = 1;
66
67 pub const WIRE_SIZE: usize = 3 * Dt::WIRE_SIZE; pub fn to_wire_bytes(&self) -> [u8; Self::WIRE_SIZE] {
74 let mut buf = [0u8; Self::WIRE_SIZE];
75 let c = self.constant.to_wire_bytes();
76 let r = self.rate.to_wire_bytes();
77 let a = self.accel.to_wire_bytes();
78
79 buf[0..Dt::WIRE_SIZE].copy_from_slice(&c);
80 buf[Dt::WIRE_SIZE..2 * Dt::WIRE_SIZE].copy_from_slice(&r);
81 buf[2 * Dt::WIRE_SIZE..].copy_from_slice(&a);
82 buf
83 }
84
85 pub fn from_wire_bytes(bytes: &[u8]) -> Option<Self> {
97 if bytes.len() != Self::WIRE_SIZE {
98 return None;
99 }
100
101 if bytes[0] != Self::WIRE_VERSION {
102 return None;
103 }
104
105 let constant = Dt::from_wire_bytes(&bytes[0..Dt::WIRE_SIZE])?;
106 let rate = Dt::from_wire_bytes(&bytes[Dt::WIRE_SIZE..2 * Dt::WIRE_SIZE])?;
107 let accel = Dt::from_wire_bytes(&bytes[2 * Dt::WIRE_SIZE..])?;
108
109 Some(Self::new(constant, rate, accel))
110 }
111}
112
113impl Spacetime {
114 pub const WIRE_SIZE: usize = 24;
116
117 pub fn to_wire_bytes(&self) -> [u8; Self::WIRE_SIZE] {
121 let mut buf = [0u8; Self::WIRE_SIZE];
122 buf[0..8].copy_from_slice(&self.alpha.to_le_bytes());
123 buf[8..16].copy_from_slice(&self.beta.to_le_bytes());
124 buf[16..24].copy_from_slice(&self.kretschmann.to_le_bytes());
125 buf
126 }
127
128 pub fn from_wire_bytes(bytes: &[u8]) -> Option<Self> {
136 if bytes.len() != Self::WIRE_SIZE {
137 return None;
138 }
139 let alpha = f64::from_le_bytes([
140 bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
141 ]);
142 let beta = f64::from_le_bytes([
143 bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15],
144 ]);
145 let kretschmann = f64::from_le_bytes([
146 bytes[16], bytes[17], bytes[18], bytes[19], bytes[20], bytes[21], bytes[22], bytes[23],
147 ]);
148 Some(Self {
149 alpha,
150 beta,
151 kretschmann,
152 })
153 }
154}
155
156impl Every {
157 pub const WIRE_SIZE: usize = Dt::WIRE_SIZE + Dt::WIRE_SIZE;
159
160 pub fn to_wire_bytes(&self) -> [u8; Self::WIRE_SIZE] {
164 let mut buf = [0u8; Self::WIRE_SIZE];
165 let start = self.start.to_wire_bytes();
166 let step = self.step.to_wire_bytes();
167 buf[0..17].copy_from_slice(&start);
168 buf[17..33].copy_from_slice(&step);
169 buf
170 }
171
172 pub fn from_wire_bytes(bytes: &[u8]) -> Option<Self> {
179 if bytes.len() != Self::WIRE_SIZE {
180 return None;
181 }
182 let start = Dt::from_wire_bytes(&bytes[0..17])?;
183 let step = Dt::from_wire_bytes(&bytes[17..33])?;
184 Some(Self { start, step })
185 }
186}
187
188impl TimeRange {
189 pub const WIRE_VERSION: u8 = 1;
191
192 pub const WIRE_SIZE: usize = 1 + 2 * Dt::WIRE_SIZE + Dt::WIRE_SIZE + 1;
195
196 pub fn to_wire_bytes(&self) -> [u8; Self::WIRE_SIZE] {
203 let mut buf = [0u8; Self::WIRE_SIZE];
204 buf[0] = Self::WIRE_VERSION;
205
206 let start = self.start.to_wire_bytes();
207 let end = self.end.to_wire_bytes();
208 let step = self.step.to_wire_bytes();
209
210 let tp_size = Dt::WIRE_SIZE;
211 let span_size = Dt::WIRE_SIZE;
212
213 buf[1..1 + tp_size].copy_from_slice(&start);
214 buf[1 + tp_size..1 + 2 * tp_size].copy_from_slice(&end);
215 buf[1 + 2 * tp_size..1 + 2 * tp_size + span_size].copy_from_slice(&step);
216 buf[1 + 2 * tp_size + span_size] = if self.inclusive { 1 } else { 0 };
217
218 buf
219 }
220
221 pub fn from_wire_bytes(bytes: &[u8]) -> Option<Self> {
233 if bytes.len() != Self::WIRE_SIZE {
234 return None;
235 }
236
237 if bytes[0] != Self::WIRE_VERSION {
238 return None;
239 }
240
241 let tp_size = Dt::WIRE_SIZE;
242 let span_size = Dt::WIRE_SIZE;
243
244 let start = Dt::from_wire_bytes(&bytes[1..1 + tp_size])?;
245 let end = Dt::from_wire_bytes(&bytes[1 + tp_size..1 + 2 * tp_size])?;
246 let step = Dt::from_wire_bytes(&bytes[1 + 2 * tp_size..1 + 2 * tp_size + span_size])?;
247 let inclusive = bytes[1 + 2 * tp_size + span_size] != 0;
248
249 Some(Self::new(start, end, step, inclusive))
250 }
251}
252
253impl GregorianTime {
254 pub const WIRE_VERSION: u8 = 1;
256
257 pub const WIRE_SIZE: usize = 158;
259
260 pub fn to_wire_bytes(&self) -> [u8; Self::WIRE_SIZE] {
278 let mut buf = [0u8; Self::WIRE_SIZE];
279 buf[0] = Self::WIRE_VERSION;
280 let mut offset = 1usize;
281
282 buf[offset..offset + 16].copy_from_slice(&self.unix_attosec.to_le_bytes());
284 offset += 16;
285
286 buf[offset..offset + 8].copy_from_slice(&self.yr.to_le_bytes());
288 offset += 8;
289
290 buf[offset] = self.mo;
292 offset += 1;
293 buf[offset] = self.day;
294 offset += 1;
295 buf[offset] = self.hr;
296 offset += 1;
297 buf[offset] = self.min;
298 offset += 1;
299 buf[offset] = self.sec;
300 offset += 1;
301
302 buf[offset..offset + 8].copy_from_slice(&self.attos.to_le_bytes());
304 offset += 8;
305
306 buf[offset..offset + 8].copy_from_slice(&self.iso_yr.to_le_bytes());
308 offset += 8;
309
310 buf[offset] = self.iso_wk;
312 offset += 1;
313 buf[offset] = self.iso_wkday.to_wire_byte();
314 offset += 1;
315
316 buf[offset..offset + 2].copy_from_slice(&self.day_of_yr.to_le_bytes());
318 offset += 2;
319
320 buf[offset] = self.wkday;
322 offset += 1;
323
324 buf[offset] = self.wk_of_yr_sun;
326 offset += 1;
327 buf[offset] = self.wk_of_yr_mon;
328 offset += 1;
329
330 if let Some(val) = self.offset_sec {
332 buf[offset] = 1;
333 buf[offset + 1..offset + 5].copy_from_slice(&val.to_le_bytes());
334 } else {
335 buf[offset] = 0;
336 }
337 offset += 5;
338
339 if let Some(tz) = &self.tz {
341 buf[offset] = 1;
342 let tz_bytes = tz.to_wire_bytes();
343 buf[offset + 1..offset + 1 + AsciiStr::<49>::WIRE_SIZE].copy_from_slice(&tz_bytes);
344 } else {
345 buf[offset] = 0;
346 }
347 offset += 1 + AsciiStr::<49>::WIRE_SIZE;
348
349 if let Some(abbrev) = &self.tz_abbrev {
351 buf[offset] = 1;
352 let abbrev_bytes = abbrev.to_wire_bytes();
353 buf[offset + 1..offset + 1 + AsciiStr::<49>::WIRE_SIZE].copy_from_slice(&abbrev_bytes);
354 } else {
355 buf[offset] = 0;
356 }
357
358 buf
359 }
360
361 pub fn from_wire_bytes(bytes: &[u8]) -> Option<Self> {
370 if bytes.len() != Self::WIRE_SIZE {
371 return None;
372 }
373 if bytes[0] != Self::WIRE_VERSION {
374 return None;
375 }
376
377 let mut offset = 1usize;
378
379 let unix_attosec = i128::from_le_bytes(bytes[offset..offset + 16].try_into().ok()?);
381 offset += 16;
382
383 let yr = i64::from_le_bytes(bytes[offset..offset + 8].try_into().ok()?);
385 offset += 8;
386
387 let mo = bytes[offset];
389 offset += 1;
390 let day = bytes[offset];
391 offset += 1;
392 let hr = bytes[offset];
393 offset += 1;
394 let min = bytes[offset];
395 offset += 1;
396 let sec = bytes[offset];
397 offset += 1;
398
399 let attos = u64::from_le_bytes(bytes[offset..offset + 8].try_into().ok()?);
401 offset += 8;
402
403 let iso_yr = i64::from_le_bytes(bytes[offset..offset + 8].try_into().ok()?);
405 offset += 8;
406
407 let iso_wk = bytes[offset];
409 offset += 1;
410 let iso_wkday = Weekday::from_wire_byte(bytes[offset])?;
411 offset += 1;
412
413 let day_of_yr = u16::from_le_bytes(bytes[offset..offset + 2].try_into().ok()?);
415 offset += 2;
416
417 let wkday = bytes[offset];
419 offset += 1;
420
421 let wk_of_yr_sun = bytes[offset];
423 offset += 1;
424 let wk_of_yr_mon = bytes[offset];
425 offset += 1;
426
427 let offset_sec = if bytes[offset] == 1 {
429 Some(i32::from_le_bytes(
430 bytes[offset + 1..offset + 5].try_into().ok()?,
431 ))
432 } else {
433 None
434 };
435 offset += 5;
436
437 let tz = if bytes[offset] == 1 {
439 AsciiStr::<49>::from_wire_bytes(
440 &bytes[offset + 1..offset + 1 + AsciiStr::<49>::WIRE_SIZE],
441 )
442 } else {
443 None
444 };
445 offset += 1 + AsciiStr::<49>::WIRE_SIZE;
446
447 let tz_abbrev = if bytes[offset] == 1 {
449 AsciiStr::<49>::from_wire_bytes(
450 &bytes[offset + 1..offset + 1 + AsciiStr::<49>::WIRE_SIZE],
451 )
452 } else {
453 None
454 };
455
456 Some(Self {
457 unix_attosec,
458 yr,
459 mo,
460 day,
461 hr,
462 min,
463 sec,
464 attos,
465 iso_yr,
466 iso_wk,
467 iso_wkday,
468 day_of_yr,
469 wkday,
470 wk_of_yr_sun,
471 wk_of_yr_mon,
472 offset_sec,
473 tz,
474 tz_abbrev,
475 })
476 }
477}
478
479impl Meridiem {
480 pub const WIRE_SIZE: usize = 1;
481
482 #[inline]
483 pub const fn to_wire_byte(self) -> u8 {
484 match self {
485 Meridiem::AM => 0,
486 Meridiem::PM => 1,
487 }
488 }
489
490 #[inline]
491 pub const fn from_wire_byte(b: u8) -> Option<Self> {
492 match b {
493 0 => Some(Meridiem::AM),
494 1 => Some(Meridiem::PM),
495 _ => None,
496 }
497 }
498}
499
500impl Offset {
501 pub const WIRE_SIZE: usize = 5; pub fn to_wire_bytes(&self) -> [u8; Self::WIRE_SIZE] {
504 let mut buf = [0u8; Self::WIRE_SIZE];
505 match self {
506 Offset::Utc => buf[0] = 0,
507 Offset::None => buf[0] = 1,
508 Offset::Fixed(offset) => {
509 buf[0] = 2;
510 buf[1..5].copy_from_slice(&offset.to_le_bytes());
511 }
512 }
513 buf
514 }
515
516 pub fn from_wire_bytes(bytes: &[u8]) -> Option<Self> {
517 if bytes.len() != Self::WIRE_SIZE {
518 return None;
519 }
520 match bytes[0] {
521 0 => Some(Offset::Utc),
522 1 => Some(Offset::None),
523 2 => {
524 let offset = i32::from_le_bytes([bytes[1], bytes[2], bytes[3], bytes[4]]);
525 Some(Offset::Fixed(offset))
526 }
527 _ => None,
528 }
529 }
530}
531
532impl Weekday {
533 pub const WIRE_SIZE: usize = 1;
534
535 #[inline]
536 pub const fn to_wire_byte(self) -> u8 {
537 self.wk_sun()
538 }
539
540 #[inline]
541 pub const fn from_wire_byte(b: u8) -> Option<Self> {
542 Self::from_sunday_zero_offset(b)
543 }
544}
545
546impl TimeParts {
547 pub const WIRE_VERSION: u8 = 1;
549
550 pub const WIRE_SIZE: usize = 120;
552
553 pub fn to_wire_bytes(&self) -> [u8; Self::WIRE_SIZE] {
559 let mut buf = [0u8; Self::WIRE_SIZE];
560 buf[0] = Self::WIRE_VERSION;
561
562 let mut offset = 1usize;
563
564 let year = self.yr.unwrap_or(i64::MIN);
566 buf[offset..offset + 8].copy_from_slice(&year.to_le_bytes());
567 offset += 8;
568
569 buf[offset] = self.mo.unwrap_or(u8::MAX);
571 offset += 1;
572
573 buf[offset] = self.day.unwrap_or(u8::MAX);
575 offset += 1;
576
577 buf[offset] = self.hr.unwrap_or(u8::MAX);
579 offset += 1;
580
581 buf[offset] = self.min.unwrap_or(u8::MAX);
583 offset += 1;
584
585 buf[offset] = self.sec.unwrap_or(u8::MAX);
587 offset += 1;
588
589 let attos = self.attos.unwrap_or(u64::MAX);
591 buf[offset..offset + 8].copy_from_slice(&attos.to_le_bytes());
592 offset += 8;
593
594 let offset_bytes = self.offset.unwrap_or_default().to_wire_bytes();
596 buf[offset..offset + 5].copy_from_slice(&offset_bytes);
597 offset += 5;
598
599 if let Some(name) = &self.iana_name {
601 let name_bytes = name.to_wire_bytes();
602 buf[offset..offset + 49].copy_from_slice(&name_bytes);
603 }
604 offset += 49;
605
606 buf[offset] = if self.is_leap_sec { 1 } else { 0 };
608 offset += 1;
609
610 buf[offset] = self.scale as u8;
612 offset += 1;
613
614 buf[offset] = self.wkday.map_or(255, |w| w.to_wire_byte());
616 offset += 1;
617
618 let doy = self.day_of_yr.unwrap_or(u16::MAX);
620 buf[offset..offset + 2].copy_from_slice(&doy.to_le_bytes());
621 offset += 2;
622
623 let iso_y = self.iso_wk_yr.unwrap_or(i64::MIN);
625 buf[offset..offset + 8].copy_from_slice(&iso_y.to_le_bytes());
626 offset += 8;
627
628 buf[offset] = self.iso_wk.unwrap_or(u8::MAX);
630 offset += 1;
631
632 buf[offset] = self.wk_sun.unwrap_or(u8::MAX);
634 offset += 1;
635
636 buf[offset] = self.wk_mon.unwrap_or(u8::MAX);
638 offset += 1;
639
640 buf[offset] = self.meridiem.map_or(255, |m| m.to_wire_byte());
642 offset += 1;
643
644 let unix = self.unix_timestamp_seconds.unwrap_or(i64::MIN);
646 buf[offset..offset + 8].copy_from_slice(&unix.to_le_bytes());
647
648 buf
649 }
650
651 pub fn from_wire_bytes(bytes: &[u8]) -> Option<Self> {
655 if bytes.len() != Self::WIRE_SIZE {
656 return None;
657 }
658 if bytes[0] != Self::WIRE_VERSION {
659 return None;
660 }
661
662 let mut dc = TimeParts::default();
663 let mut offset = 1usize;
664
665 let year = i64::from_le_bytes(bytes[offset..offset + 8].try_into().ok()?);
667 if year != i64::MIN {
668 dc.yr = Some(year);
669 }
670 offset += 8;
671
672 let m = bytes[offset];
674 if m != u8::MAX {
675 dc.mo = Some(m);
676 }
677 offset += 1;
678
679 let d = bytes[offset];
681 if d != u8::MAX {
682 dc.day = Some(d);
683 }
684 offset += 1;
685
686 let h = bytes[offset];
688 if h != u8::MAX {
689 dc.hr = Some(h);
690 }
691 offset += 1;
692
693 let min = bytes[offset];
695 if min != u8::MAX {
696 dc.min = Some(min);
697 }
698 offset += 1;
699
700 let sec = bytes[offset];
702 if sec != u8::MAX {
703 dc.sec = Some(sec);
704 }
705 offset += 1;
706
707 let attos = u64::from_le_bytes(bytes[offset..offset + 8].try_into().ok()?);
709 if attos != u64::MAX {
710 dc.attos = Some(attos);
711 }
712 offset += 8;
713
714 if let Some(offset) = Offset::from_wire_bytes(&bytes[offset..offset + 5]) {
716 dc.offset = Some(offset);
717 }
718 offset += 5;
719
720 let iana_bytes = &bytes[offset..offset + 49];
722 if let Some(name) = AsciiStr::<49>::from_wire_bytes(iana_bytes)
723 && !name.is_empty()
724 {
725 dc.iana_name = Some(name);
726 }
727 offset += 49;
728
729 dc.is_leap_sec = bytes[offset] != 0;
731 offset += 1;
732
733 dc.scale = Scale::from_u8(bytes[offset]);
735 offset += 1;
736
737 let wd_byte = bytes[offset];
739 if wd_byte != 255
740 && let Some(wd) = Weekday::from_wire_byte(wd_byte)
741 {
742 dc.wkday = Some(wd);
743 }
744 offset += 1;
745
746 let doy = u16::from_le_bytes(bytes[offset..offset + 2].try_into().ok()?);
748 if doy != u16::MAX {
749 dc.day_of_yr = Some(doy);
750 }
751 offset += 2;
752
753 let iso_y = i64::from_le_bytes(bytes[offset..offset + 8].try_into().ok()?);
755 if iso_y != i64::MIN {
756 dc.iso_wk_yr = Some(iso_y);
757 }
758 offset += 8;
759
760 let iw = bytes[offset];
762 if iw != u8::MAX {
763 dc.iso_wk = Some(iw);
764 }
765 offset += 1;
766
767 let ws = bytes[offset];
769 if ws != u8::MAX {
770 dc.wk_sun = Some(ws);
771 }
772 offset += 1;
773
774 let wm = bytes[offset];
776 if wm != u8::MAX {
777 dc.wk_mon = Some(wm);
778 }
779 offset += 1;
780
781 let mer_byte = bytes[offset];
783 if mer_byte != 255
784 && let Some(m) = Meridiem::from_wire_byte(mer_byte)
785 {
786 dc.meridiem = Some(m);
787 }
788
789 offset += 1;
790
791 let unix = i64::from_le_bytes(bytes[offset..offset + 8].try_into().ok()?);
793 if unix != i64::MIN {
794 dc.unix_timestamp_seconds = Some(unix);
795 }
796
797 Some(dc)
798 }
799}