1use crate::{
2 Drift, Dt, Every, LiteStr, Meridiem, Offset, Scale, Spacetime, TimeParts, TimeRange, Weekday,
3 YmdHmsRich,
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 YmdHmsRich {
254 pub const WIRE_VERSION: u8 = 1;
256
257 pub const WIRE_SIZE: usize = 159;
259
260 pub fn to_wire_bytes(&self) -> [u8; Self::WIRE_SIZE] {
279 let mut buf = [0u8; Self::WIRE_SIZE];
280 buf[0] = Self::WIRE_VERSION;
281 let mut offset = 1usize;
282
283 buf[offset..offset + 16].copy_from_slice(&self.unix_attosec.to_le_bytes());
285 offset += 16;
286
287 buf[offset..offset + 8].copy_from_slice(&self.yr.to_le_bytes());
289 offset += 8;
290
291 buf[offset] = self.mo;
293 offset += 1;
294 buf[offset] = self.day;
295 offset += 1;
296 buf[offset] = self.hr;
297 offset += 1;
298 buf[offset] = self.min;
299 offset += 1;
300 buf[offset] = self.sec;
301 offset += 1;
302
303 buf[offset..offset + 8].copy_from_slice(&self.attos.to_le_bytes());
305 offset += 8;
306
307 buf[offset..offset + 8].copy_from_slice(&self.iso_yr.to_le_bytes());
309 offset += 8;
310
311 buf[offset] = self.iso_wk;
313 offset += 1;
314 buf[offset] = self.iso_wkday.to_wire_byte();
315 offset += 1;
316
317 buf[offset..offset + 2].copy_from_slice(&self.day_of_yr.to_le_bytes());
319 offset += 2;
320
321 buf[offset] = self.wkday;
323 offset += 1;
324
325 buf[offset] = self.wk_of_yr_sun;
327 offset += 1;
328 buf[offset] = self.wk_of_yr_mon;
329 offset += 1;
330
331 if let Some(val) = self.offset_sec {
333 buf[offset] = 1;
334 buf[offset + 1..offset + 5].copy_from_slice(&val.to_le_bytes());
335 } else {
336 buf[offset] = 0;
337 }
338 offset += 5;
339
340 if let Some(tz) = &self.tz {
342 buf[offset] = 1;
343 let tz_bytes = tz.to_bytes();
344 buf[offset + 1..offset + 1 + LiteStr::<49>::SIZE].copy_from_slice(&tz_bytes);
345 } else {
346 buf[offset] = 0;
347 }
348 offset += 1 + LiteStr::<49>::SIZE;
349
350 if let Some(abbrev) = &self.tz_abbrev {
352 buf[offset] = 1;
353 let abbrev_bytes = abbrev.to_bytes();
354 buf[offset + 1..offset + 1 + LiteStr::<49>::SIZE].copy_from_slice(&abbrev_bytes);
355 } else {
356 buf[offset] = 0;
357 }
358 offset += 1 + LiteStr::<49>::SIZE;
359
360 buf[offset] = self.scale.to_u8();
362
363 buf
364 }
365
366 pub fn from_wire_bytes(bytes: &[u8]) -> Option<Self> {
375 if bytes.len() != Self::WIRE_SIZE {
376 return None;
377 }
378 if bytes[0] != Self::WIRE_VERSION {
379 return None;
380 }
381
382 let mut offset = 1usize;
383
384 let unix_attosec = i128::from_le_bytes(bytes[offset..offset + 16].try_into().ok()?);
386 offset += 16;
387
388 let yr = i64::from_le_bytes(bytes[offset..offset + 8].try_into().ok()?);
390 offset += 8;
391
392 let mo = bytes[offset];
394 offset += 1;
395 let day = bytes[offset];
396 offset += 1;
397 let hr = bytes[offset];
398 offset += 1;
399 let min = bytes[offset];
400 offset += 1;
401 let sec = bytes[offset];
402 offset += 1;
403
404 let attos = u64::from_le_bytes(bytes[offset..offset + 8].try_into().ok()?);
406 offset += 8;
407
408 let iso_yr = i64::from_le_bytes(bytes[offset..offset + 8].try_into().ok()?);
410 offset += 8;
411
412 let iso_wk = bytes[offset];
414 offset += 1;
415 let iso_wkday = Weekday::from_wire_byte(bytes[offset])?;
416 offset += 1;
417
418 let day_of_yr = u16::from_le_bytes(bytes[offset..offset + 2].try_into().ok()?);
420 offset += 2;
421
422 let wkday = bytes[offset];
424 offset += 1;
425
426 let wk_of_yr_sun = bytes[offset];
428 offset += 1;
429 let wk_of_yr_mon = bytes[offset];
430 offset += 1;
431
432 let offset_sec = if bytes[offset] == 1 {
434 Some(i32::from_le_bytes(
435 bytes[offset + 1..offset + 5].try_into().ok()?,
436 ))
437 } else {
438 None
439 };
440 offset += 5;
441
442 let tz = if bytes[offset] == 1 {
444 LiteStr::<49>::from_bytes(&bytes[offset + 1..offset + 1 + LiteStr::<49>::SIZE]).ok()
445 } else {
446 None
447 };
448 offset += 1 + LiteStr::<49>::SIZE;
449
450 let tz_abbrev = if bytes[offset] == 1 {
452 LiteStr::<49>::from_bytes(&bytes[offset + 1..offset + 1 + LiteStr::<49>::SIZE]).ok()
453 } else {
454 None
455 };
456 offset += 1 + LiteStr::<49>::SIZE;
457
458 let scale = Scale::from_u8(bytes[offset]);
460
461 Some(Self {
462 unix_attosec,
463 yr,
464 mo,
465 day,
466 hr,
467 min,
468 sec,
469 attos,
470 iso_yr,
471 iso_wk,
472 iso_wkday,
473 day_of_yr,
474 wkday,
475 wk_of_yr_sun,
476 wk_of_yr_mon,
477 offset_sec,
478 tz,
479 tz_abbrev,
480 scale,
481 })
482 }
483}
484
485impl Meridiem {
486 pub const WIRE_SIZE: usize = 1;
487
488 #[inline]
489 pub const fn to_wire_byte(self) -> u8 {
490 match self {
491 Meridiem::AM => 0,
492 Meridiem::PM => 1,
493 }
494 }
495
496 #[inline]
497 pub const fn from_wire_byte(b: u8) -> Option<Self> {
498 match b {
499 0 => Some(Meridiem::AM),
500 1 => Some(Meridiem::PM),
501 _ => None,
502 }
503 }
504}
505
506impl Offset {
507 pub const WIRE_SIZE: usize = 5; pub fn to_wire_bytes(&self) -> [u8; Self::WIRE_SIZE] {
510 let mut buf = [0u8; Self::WIRE_SIZE];
511 match self {
512 Offset::Utc => buf[0] = 0,
513 Offset::None => buf[0] = 1,
514 Offset::Fixed(offset) => {
515 buf[0] = 2;
516 buf[1..5].copy_from_slice(&offset.to_le_bytes());
517 }
518 }
519 buf
520 }
521
522 pub fn from_wire_bytes(bytes: &[u8]) -> Option<Self> {
523 if bytes.len() != Self::WIRE_SIZE {
524 return None;
525 }
526 match bytes[0] {
527 0 => Some(Offset::Utc),
528 1 => Some(Offset::None),
529 2 => {
530 let offset = i32::from_le_bytes([bytes[1], bytes[2], bytes[3], bytes[4]]);
531 Some(Offset::Fixed(offset))
532 }
533 _ => None,
534 }
535 }
536}
537
538impl Weekday {
539 pub const WIRE_SIZE: usize = 1;
540
541 #[inline]
542 pub const fn to_wire_byte(self) -> u8 {
543 self.wk_sun()
544 }
545
546 #[inline]
547 pub const fn from_wire_byte(b: u8) -> Option<Self> {
548 Self::from_sunday_zero_offset(b)
549 }
550}
551
552impl TimeParts {
553 pub const WIRE_VERSION: u8 = 1;
555
556 pub const WIRE_SIZE: usize = 120;
558
559 pub fn to_wire_bytes(&self) -> [u8; Self::WIRE_SIZE] {
565 let mut buf = [0u8; Self::WIRE_SIZE];
566 buf[0] = Self::WIRE_VERSION;
567
568 let mut offset = 1usize;
569
570 let year = self.yr.unwrap_or(i64::MIN);
572 buf[offset..offset + 8].copy_from_slice(&year.to_le_bytes());
573 offset += 8;
574
575 buf[offset] = self.mo.unwrap_or(u8::MAX);
577 offset += 1;
578
579 buf[offset] = self.day.unwrap_or(u8::MAX);
581 offset += 1;
582
583 buf[offset] = self.hr.unwrap_or(u8::MAX);
585 offset += 1;
586
587 buf[offset] = self.min.unwrap_or(u8::MAX);
589 offset += 1;
590
591 buf[offset] = self.sec.unwrap_or(u8::MAX);
593 offset += 1;
594
595 let attos = self.attos.unwrap_or(u64::MAX);
597 buf[offset..offset + 8].copy_from_slice(&attos.to_le_bytes());
598 offset += 8;
599
600 let offset_bytes = self.offset.unwrap_or_default().to_wire_bytes();
602 buf[offset..offset + 5].copy_from_slice(&offset_bytes);
603 offset += 5;
604
605 if let Some(name) = &self.iana_name {
607 let name_bytes = name.to_bytes();
608 buf[offset..offset + 49].copy_from_slice(&name_bytes);
609 }
610 offset += 49;
611
612 buf[offset] = if self.is_leap_sec { 1 } else { 0 };
614 offset += 1;
615
616 buf[offset] = self.scale as u8;
618 offset += 1;
619
620 buf[offset] = self.wkday.map_or(255, |w| w.to_wire_byte());
622 offset += 1;
623
624 let doy = self.day_of_yr.unwrap_or(u16::MAX);
626 buf[offset..offset + 2].copy_from_slice(&doy.to_le_bytes());
627 offset += 2;
628
629 let iso_y = self.iso_wk_yr.unwrap_or(i64::MIN);
631 buf[offset..offset + 8].copy_from_slice(&iso_y.to_le_bytes());
632 offset += 8;
633
634 buf[offset] = self.iso_wk.unwrap_or(u8::MAX);
636 offset += 1;
637
638 buf[offset] = self.wk_sun.unwrap_or(u8::MAX);
640 offset += 1;
641
642 buf[offset] = self.wk_mon.unwrap_or(u8::MAX);
644 offset += 1;
645
646 buf[offset] = self.meridiem.map_or(255, |m| m.to_wire_byte());
648 offset += 1;
649
650 let unix = self.unix_timestamp_seconds.unwrap_or(i64::MIN);
652 buf[offset..offset + 8].copy_from_slice(&unix.to_le_bytes());
653
654 buf
655 }
656
657 pub fn from_wire_bytes(bytes: &[u8]) -> Option<Self> {
661 if bytes.len() != Self::WIRE_SIZE {
662 return None;
663 }
664 if bytes[0] != Self::WIRE_VERSION {
665 return None;
666 }
667
668 let mut dc = TimeParts::default();
669 let mut offset = 1usize;
670
671 let year = i64::from_le_bytes(bytes[offset..offset + 8].try_into().ok()?);
673 if year != i64::MIN {
674 dc.yr = Some(year);
675 }
676 offset += 8;
677
678 let m = bytes[offset];
680 if m != u8::MAX {
681 dc.mo = Some(m);
682 }
683 offset += 1;
684
685 let d = bytes[offset];
687 if d != u8::MAX {
688 dc.day = Some(d);
689 }
690 offset += 1;
691
692 let h = bytes[offset];
694 if h != u8::MAX {
695 dc.hr = Some(h);
696 }
697 offset += 1;
698
699 let min = bytes[offset];
701 if min != u8::MAX {
702 dc.min = Some(min);
703 }
704 offset += 1;
705
706 let sec = bytes[offset];
708 if sec != u8::MAX {
709 dc.sec = Some(sec);
710 }
711 offset += 1;
712
713 let attos = u64::from_le_bytes(bytes[offset..offset + 8].try_into().ok()?);
715 if attos != u64::MAX {
716 dc.attos = Some(attos);
717 }
718 offset += 8;
719
720 if let Some(offset) = Offset::from_wire_bytes(&bytes[offset..offset + 5]) {
722 dc.offset = Some(offset);
723 }
724 offset += 5;
725
726 let iana_bytes = &bytes[offset..offset + 49];
728 if let Some(name) = LiteStr::<49>::from_bytes(iana_bytes).ok()
729 && !name.len() == 0
730 {
731 dc.iana_name = Some(name);
732 }
733 offset += 49;
734
735 dc.is_leap_sec = bytes[offset] != 0;
737 offset += 1;
738
739 dc.scale = Scale::from_u8(bytes[offset]);
741 offset += 1;
742
743 let wd_byte = bytes[offset];
745 if wd_byte != 255
746 && let Some(wd) = Weekday::from_wire_byte(wd_byte)
747 {
748 dc.wkday = Some(wd);
749 }
750 offset += 1;
751
752 let doy = u16::from_le_bytes(bytes[offset..offset + 2].try_into().ok()?);
754 if doy != u16::MAX {
755 dc.day_of_yr = Some(doy);
756 }
757 offset += 2;
758
759 let iso_y = i64::from_le_bytes(bytes[offset..offset + 8].try_into().ok()?);
761 if iso_y != i64::MIN {
762 dc.iso_wk_yr = Some(iso_y);
763 }
764 offset += 8;
765
766 let iw = bytes[offset];
768 if iw != u8::MAX {
769 dc.iso_wk = Some(iw);
770 }
771 offset += 1;
772
773 let ws = bytes[offset];
775 if ws != u8::MAX {
776 dc.wk_sun = Some(ws);
777 }
778 offset += 1;
779
780 let wm = bytes[offset];
782 if wm != u8::MAX {
783 dc.wk_mon = Some(wm);
784 }
785 offset += 1;
786
787 let mer_byte = bytes[offset];
789 if mer_byte != 255
790 && let Some(m) = Meridiem::from_wire_byte(mer_byte)
791 {
792 dc.meridiem = Some(m);
793 }
794
795 offset += 1;
796
797 let unix = i64::from_le_bytes(bytes[offset..offset + 8].try_into().ok()?);
799 if unix != i64::MIN {
800 dc.unix_timestamp_seconds = Some(unix);
801 }
802
803 Some(dc)
804 }
805}