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 = 19;
12
13 pub fn to_wire_bytes(&self) -> [u8; Self::WIRE_SIZE] {
23 let mut buf = [0u8; Self::WIRE_SIZE];
24 buf[0] = Self::WIRE_VERSION;
25 buf[1..17].copy_from_slice(&self.attos.to_le_bytes());
26 buf[17] = self.target as u8;
27 buf
28 }
29
30 pub fn from_wire_bytes(bytes: &[u8]) -> Option<Self> {
47 if bytes.len() != Self::WIRE_SIZE {
48 return None;
49 }
50
51 if bytes[0] != Self::WIRE_VERSION {
52 return None;
53 }
54
55 let attos = i128::from_le_bytes([
56 bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], bytes[8],
57 bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15], bytes[16],
58 ]);
59
60 let scale = Scale::from_u8(bytes[17]);
61 let target = Scale::from_u8(bytes[18]);
62
63 Some(Dt::new(attos, scale, target))
64 }
65}
66
67impl Drift {
68 pub const WIRE_VERSION: u8 = 1;
70
71 pub const WIRE_SIZE: usize = 3 * Dt::WIRE_SIZE; pub fn to_wire_bytes(&self) -> [u8; Self::WIRE_SIZE] {
78 let mut buf = [0u8; Self::WIRE_SIZE];
79 let c = self.constant.to_wire_bytes();
80 let r = self.rate.to_wire_bytes();
81 let a = self.accel.to_wire_bytes();
82
83 buf[0..Dt::WIRE_SIZE].copy_from_slice(&c);
84 buf[Dt::WIRE_SIZE..2 * Dt::WIRE_SIZE].copy_from_slice(&r);
85 buf[2 * Dt::WIRE_SIZE..].copy_from_slice(&a);
86 buf
87 }
88
89 pub fn from_wire_bytes(bytes: &[u8]) -> Option<Self> {
101 if bytes.len() != Self::WIRE_SIZE {
102 return None;
103 }
104
105 if bytes[0] != Self::WIRE_VERSION {
106 return None;
107 }
108
109 let constant = Dt::from_wire_bytes(&bytes[0..Dt::WIRE_SIZE])?;
110 let rate = Dt::from_wire_bytes(&bytes[Dt::WIRE_SIZE..2 * Dt::WIRE_SIZE])?;
111 let accel = Dt::from_wire_bytes(&bytes[2 * Dt::WIRE_SIZE..])?;
112
113 Some(Self::new(constant, rate, accel))
114 }
115}
116
117impl Spacetime {
118 pub const WIRE_SIZE: usize = 24;
120
121 pub fn to_wire_bytes(&self) -> [u8; Self::WIRE_SIZE] {
125 let mut buf = [0u8; Self::WIRE_SIZE];
126 buf[0..8].copy_from_slice(&self.alpha.to_le_bytes());
127 buf[8..16].copy_from_slice(&self.beta.to_le_bytes());
128 buf[16..24].copy_from_slice(&self.kretschmann.to_le_bytes());
129 buf
130 }
131
132 pub fn from_wire_bytes(bytes: &[u8]) -> Option<Self> {
140 if bytes.len() != Self::WIRE_SIZE {
141 return None;
142 }
143 let alpha = f64::from_le_bytes([
144 bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
145 ]);
146 let beta = f64::from_le_bytes([
147 bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15],
148 ]);
149 let kretschmann = f64::from_le_bytes([
150 bytes[16], bytes[17], bytes[18], bytes[19], bytes[20], bytes[21], bytes[22], bytes[23],
151 ]);
152 Some(Self {
153 alpha,
154 beta,
155 kretschmann,
156 })
157 }
158}
159
160impl Every {
161 pub const WIRE_SIZE: usize = Dt::WIRE_SIZE + Dt::WIRE_SIZE;
163
164 pub fn to_wire_bytes(&self) -> [u8; Self::WIRE_SIZE] {
168 let mut buf = [0u8; Self::WIRE_SIZE];
169 let start = self.start.to_wire_bytes();
170 let step = self.step.to_wire_bytes();
171 buf[0..17].copy_from_slice(&start);
172 buf[17..33].copy_from_slice(&step);
173 buf
174 }
175
176 pub fn from_wire_bytes(bytes: &[u8]) -> Option<Self> {
183 if bytes.len() != Self::WIRE_SIZE {
184 return None;
185 }
186 let start = Dt::from_wire_bytes(&bytes[0..17])?;
187 let step = Dt::from_wire_bytes(&bytes[17..33])?;
188 Some(Self { start, step })
189 }
190}
191
192impl TimeRange {
193 pub const WIRE_VERSION: u8 = 1;
195
196 pub const WIRE_SIZE: usize = 1 + 2 * Dt::WIRE_SIZE + Dt::WIRE_SIZE + 1;
199
200 pub fn to_wire_bytes(&self) -> [u8; Self::WIRE_SIZE] {
207 let mut buf = [0u8; Self::WIRE_SIZE];
208 buf[0] = Self::WIRE_VERSION;
209
210 let start = self.start.to_wire_bytes();
211 let end = self.end.to_wire_bytes();
212 let step = self.step.to_wire_bytes();
213
214 let tp_size = Dt::WIRE_SIZE;
215 let span_size = Dt::WIRE_SIZE;
216
217 buf[1..1 + tp_size].copy_from_slice(&start);
218 buf[1 + tp_size..1 + 2 * tp_size].copy_from_slice(&end);
219 buf[1 + 2 * tp_size..1 + 2 * tp_size + span_size].copy_from_slice(&step);
220 buf[1 + 2 * tp_size + span_size] = if self.inclusive { 1 } else { 0 };
221
222 buf
223 }
224
225 pub fn from_wire_bytes(bytes: &[u8]) -> Option<Self> {
237 if bytes.len() != Self::WIRE_SIZE {
238 return None;
239 }
240
241 if bytes[0] != Self::WIRE_VERSION {
242 return None;
243 }
244
245 let tp_size = Dt::WIRE_SIZE;
246 let span_size = Dt::WIRE_SIZE;
247
248 let start = Dt::from_wire_bytes(&bytes[1..1 + tp_size])?;
249 let end = Dt::from_wire_bytes(&bytes[1 + tp_size..1 + 2 * tp_size])?;
250 let step = Dt::from_wire_bytes(&bytes[1 + 2 * tp_size..1 + 2 * tp_size + span_size])?;
251 let inclusive = bytes[1 + 2 * tp_size + span_size] != 0;
252
253 Some(Self::new(start, end, step, inclusive))
254 }
255}
256
257impl YmdHmsRich {
258 pub const WIRE_VERSION: u8 = 1;
260
261 pub const WIRE_SIZE: usize = 159;
263
264 pub fn to_wire_bytes(&self) -> [u8; Self::WIRE_SIZE] {
283 let mut buf = [0u8; Self::WIRE_SIZE];
284 buf[0] = Self::WIRE_VERSION;
285 let mut offset = 1usize;
286
287 buf[offset..offset + 16].copy_from_slice(&self.unix_attosec.to_le_bytes());
289 offset += 16;
290
291 buf[offset..offset + 8].copy_from_slice(&self.yr.to_le_bytes());
293 offset += 8;
294
295 buf[offset] = self.mo;
297 offset += 1;
298 buf[offset] = self.day;
299 offset += 1;
300 buf[offset] = self.hr;
301 offset += 1;
302 buf[offset] = self.min;
303 offset += 1;
304 buf[offset] = self.sec;
305 offset += 1;
306
307 buf[offset..offset + 8].copy_from_slice(&self.attos.to_le_bytes());
309 offset += 8;
310
311 buf[offset..offset + 8].copy_from_slice(&self.iso_yr.to_le_bytes());
313 offset += 8;
314
315 buf[offset] = self.iso_wk;
317 offset += 1;
318 buf[offset] = self.iso_wkday.to_wire_byte();
319 offset += 1;
320
321 buf[offset..offset + 2].copy_from_slice(&self.day_of_yr.to_le_bytes());
323 offset += 2;
324
325 buf[offset] = self.wkday;
327 offset += 1;
328
329 buf[offset] = self.wk_of_yr_sun;
331 offset += 1;
332 buf[offset] = self.wk_of_yr_mon;
333 offset += 1;
334
335 if let Some(val) = self.offset_sec {
337 buf[offset] = 1;
338 buf[offset + 1..offset + 5].copy_from_slice(&val.to_le_bytes());
339 } else {
340 buf[offset] = 0;
341 }
342 offset += 5;
343
344 if let Some(tz) = &self.tz {
346 buf[offset] = 1;
347 let tz_bytes = tz.to_bytes();
348 buf[offset + 1..offset + 1 + LiteStr::<49>::SIZE].copy_from_slice(&tz_bytes);
349 } else {
350 buf[offset] = 0;
351 }
352 offset += 1 + LiteStr::<49>::SIZE;
353
354 if let Some(abbrev) = &self.tz_abbrev {
356 buf[offset] = 1;
357 let abbrev_bytes = abbrev.to_bytes();
358 buf[offset + 1..offset + 1 + LiteStr::<49>::SIZE].copy_from_slice(&abbrev_bytes);
359 } else {
360 buf[offset] = 0;
361 }
362 offset += 1 + LiteStr::<49>::SIZE;
363
364 buf[offset] = self.scale.to_u8();
366
367 buf
368 }
369
370 pub fn from_wire_bytes(bytes: &[u8]) -> Option<Self> {
379 if bytes.len() != Self::WIRE_SIZE {
380 return None;
381 }
382 if bytes[0] != Self::WIRE_VERSION {
383 return None;
384 }
385
386 let mut offset = 1usize;
387
388 let unix_attosec = i128::from_le_bytes(bytes[offset..offset + 16].try_into().ok()?);
390 offset += 16;
391
392 let yr = i64::from_le_bytes(bytes[offset..offset + 8].try_into().ok()?);
394 offset += 8;
395
396 let mo = bytes[offset];
398 offset += 1;
399 let day = bytes[offset];
400 offset += 1;
401 let hr = bytes[offset];
402 offset += 1;
403 let min = bytes[offset];
404 offset += 1;
405 let sec = bytes[offset];
406 offset += 1;
407
408 let attos = u64::from_le_bytes(bytes[offset..offset + 8].try_into().ok()?);
410 offset += 8;
411
412 let iso_yr = i64::from_le_bytes(bytes[offset..offset + 8].try_into().ok()?);
414 offset += 8;
415
416 let iso_wk = bytes[offset];
418 offset += 1;
419 let iso_wkday = Weekday::from_wire_byte(bytes[offset])?;
420 offset += 1;
421
422 let day_of_yr = u16::from_le_bytes(bytes[offset..offset + 2].try_into().ok()?);
424 offset += 2;
425
426 let wkday = bytes[offset];
428 offset += 1;
429
430 let wk_of_yr_sun = bytes[offset];
432 offset += 1;
433 let wk_of_yr_mon = bytes[offset];
434 offset += 1;
435
436 let offset_sec = if bytes[offset] == 1 {
438 Some(i32::from_le_bytes(
439 bytes[offset + 1..offset + 5].try_into().ok()?,
440 ))
441 } else {
442 None
443 };
444 offset += 5;
445
446 let tz = if bytes[offset] == 1 {
448 LiteStr::<49>::from_bytes(&bytes[offset + 1..offset + 1 + LiteStr::<49>::SIZE]).ok()
449 } else {
450 None
451 };
452 offset += 1 + LiteStr::<49>::SIZE;
453
454 let tz_abbrev = if bytes[offset] == 1 {
456 LiteStr::<49>::from_bytes(&bytes[offset + 1..offset + 1 + LiteStr::<49>::SIZE]).ok()
457 } else {
458 None
459 };
460 offset += 1 + LiteStr::<49>::SIZE;
461
462 let scale = Scale::from_u8(bytes[offset]);
464
465 Some(Self {
466 unix_attosec,
467 yr,
468 mo,
469 day,
470 hr,
471 min,
472 sec,
473 attos,
474 iso_yr,
475 iso_wk,
476 iso_wkday,
477 day_of_yr,
478 wkday,
479 wk_of_yr_sun,
480 wk_of_yr_mon,
481 offset_sec,
482 tz,
483 tz_abbrev,
484 scale,
485 })
486 }
487}
488
489impl Meridiem {
490 pub const WIRE_SIZE: usize = 1;
491
492 #[inline]
493 pub const fn to_wire_byte(self) -> u8 {
494 match self {
495 Meridiem::AM => 0,
496 Meridiem::PM => 1,
497 }
498 }
499
500 #[inline]
501 pub const fn from_wire_byte(b: u8) -> Option<Self> {
502 match b {
503 0 => Some(Meridiem::AM),
504 1 => Some(Meridiem::PM),
505 _ => None,
506 }
507 }
508}
509
510impl Offset {
511 pub const WIRE_SIZE: usize = 5; pub fn to_wire_bytes(&self) -> [u8; Self::WIRE_SIZE] {
514 let mut buf = [0u8; Self::WIRE_SIZE];
515 match self {
516 Offset::Utc => buf[0] = 0,
517 Offset::None => buf[0] = 1,
518 Offset::Fixed(offset) => {
519 buf[0] = 2;
520 buf[1..5].copy_from_slice(&offset.to_le_bytes());
521 }
522 }
523 buf
524 }
525
526 pub fn from_wire_bytes(bytes: &[u8]) -> Option<Self> {
527 if bytes.len() != Self::WIRE_SIZE {
528 return None;
529 }
530 match bytes[0] {
531 0 => Some(Offset::Utc),
532 1 => Some(Offset::None),
533 2 => {
534 let offset = i32::from_le_bytes([bytes[1], bytes[2], bytes[3], bytes[4]]);
535 Some(Offset::Fixed(offset))
536 }
537 _ => None,
538 }
539 }
540}
541
542impl Weekday {
543 pub const WIRE_SIZE: usize = 1;
544
545 #[inline]
546 pub const fn to_wire_byte(self) -> u8 {
547 self.wk_sun()
548 }
549
550 #[inline]
551 pub const fn from_wire_byte(b: u8) -> Option<Self> {
552 Self::from_sunday_zero_offset(b)
553 }
554}
555
556impl TimeParts {
557 pub const WIRE_VERSION: u8 = 1;
559
560 pub const WIRE_SIZE: usize = 120;
562
563 pub fn to_wire_bytes(&self) -> [u8; Self::WIRE_SIZE] {
569 let mut buf = [0u8; Self::WIRE_SIZE];
570 buf[0] = Self::WIRE_VERSION;
571
572 let mut offset = 1usize;
573
574 let year = self.yr.unwrap_or(i64::MIN);
576 buf[offset..offset + 8].copy_from_slice(&year.to_le_bytes());
577 offset += 8;
578
579 buf[offset] = self.mo.unwrap_or(u8::MAX);
581 offset += 1;
582
583 buf[offset] = self.day.unwrap_or(u8::MAX);
585 offset += 1;
586
587 buf[offset] = self.hr.unwrap_or(u8::MAX);
589 offset += 1;
590
591 buf[offset] = self.min.unwrap_or(u8::MAX);
593 offset += 1;
594
595 buf[offset] = self.sec.unwrap_or(u8::MAX);
597 offset += 1;
598
599 let attos = self.attos.unwrap_or(u64::MAX);
601 buf[offset..offset + 8].copy_from_slice(&attos.to_le_bytes());
602 offset += 8;
603
604 let offset_bytes = self.offset.unwrap_or_default().to_wire_bytes();
606 buf[offset..offset + 5].copy_from_slice(&offset_bytes);
607 offset += 5;
608
609 if let Some(name) = &self.iana_name {
611 let name_bytes = name.to_bytes();
612 buf[offset..offset + 49].copy_from_slice(&name_bytes);
613 }
614 offset += 49;
615
616 buf[offset] = if self.is_leap_sec { 1 } else { 0 };
618 offset += 1;
619
620 buf[offset] = self.scale as u8;
622 offset += 1;
623
624 buf[offset] = self.wkday.map_or(255, |w| w.to_wire_byte());
626 offset += 1;
627
628 let doy = self.day_of_yr.unwrap_or(u16::MAX);
630 buf[offset..offset + 2].copy_from_slice(&doy.to_le_bytes());
631 offset += 2;
632
633 let iso_y = self.iso_wk_yr.unwrap_or(i64::MIN);
635 buf[offset..offset + 8].copy_from_slice(&iso_y.to_le_bytes());
636 offset += 8;
637
638 buf[offset] = self.iso_wk.unwrap_or(u8::MAX);
640 offset += 1;
641
642 buf[offset] = self.wk_sun.unwrap_or(u8::MAX);
644 offset += 1;
645
646 buf[offset] = self.wk_mon.unwrap_or(u8::MAX);
648 offset += 1;
649
650 buf[offset] = self.meridiem.map_or(255, |m| m.to_wire_byte());
652 offset += 1;
653
654 let unix = self.unix_timestamp_seconds.unwrap_or(i64::MIN);
656 buf[offset..offset + 8].copy_from_slice(&unix.to_le_bytes());
657
658 buf
659 }
660
661 pub fn from_wire_bytes(bytes: &[u8]) -> Option<Self> {
665 if bytes.len() != Self::WIRE_SIZE {
666 return None;
667 }
668 if bytes[0] != Self::WIRE_VERSION {
669 return None;
670 }
671
672 let mut dc = TimeParts::default();
673 let mut offset = 1usize;
674
675 let year = i64::from_le_bytes(bytes[offset..offset + 8].try_into().ok()?);
677 if year != i64::MIN {
678 dc.yr = Some(year);
679 }
680 offset += 8;
681
682 let m = bytes[offset];
684 if m != u8::MAX {
685 dc.mo = Some(m);
686 }
687 offset += 1;
688
689 let d = bytes[offset];
691 if d != u8::MAX {
692 dc.day = Some(d);
693 }
694 offset += 1;
695
696 let h = bytes[offset];
698 if h != u8::MAX {
699 dc.hr = Some(h);
700 }
701 offset += 1;
702
703 let min = bytes[offset];
705 if min != u8::MAX {
706 dc.min = Some(min);
707 }
708 offset += 1;
709
710 let sec = bytes[offset];
712 if sec != u8::MAX {
713 dc.sec = Some(sec);
714 }
715 offset += 1;
716
717 let attos = u64::from_le_bytes(bytes[offset..offset + 8].try_into().ok()?);
719 if attos != u64::MAX {
720 dc.attos = Some(attos);
721 }
722 offset += 8;
723
724 if let Some(offset) = Offset::from_wire_bytes(&bytes[offset..offset + 5]) {
726 dc.offset = Some(offset);
727 }
728 offset += 5;
729
730 let iana_bytes = &bytes[offset..offset + 49];
732 if let Some(name) = LiteStr::<49>::from_bytes(iana_bytes).ok()
733 && !name.len() == 0
734 {
735 dc.iana_name = Some(name);
736 }
737 offset += 49;
738
739 dc.is_leap_sec = bytes[offset] != 0;
741 offset += 1;
742
743 dc.scale = Scale::from_u8(bytes[offset]);
745 offset += 1;
746
747 let wd_byte = bytes[offset];
749 if wd_byte != 255
750 && let Some(wd) = Weekday::from_wire_byte(wd_byte)
751 {
752 dc.wkday = Some(wd);
753 }
754 offset += 1;
755
756 let doy = u16::from_le_bytes(bytes[offset..offset + 2].try_into().ok()?);
758 if doy != u16::MAX {
759 dc.day_of_yr = Some(doy);
760 }
761 offset += 2;
762
763 let iso_y = i64::from_le_bytes(bytes[offset..offset + 8].try_into().ok()?);
765 if iso_y != i64::MIN {
766 dc.iso_wk_yr = Some(iso_y);
767 }
768 offset += 8;
769
770 let iw = bytes[offset];
772 if iw != u8::MAX {
773 dc.iso_wk = Some(iw);
774 }
775 offset += 1;
776
777 let ws = bytes[offset];
779 if ws != u8::MAX {
780 dc.wk_sun = Some(ws);
781 }
782 offset += 1;
783
784 let wm = bytes[offset];
786 if wm != u8::MAX {
787 dc.wk_mon = Some(wm);
788 }
789 offset += 1;
790
791 let mer_byte = bytes[offset];
793 if mer_byte != 255
794 && let Some(m) = Meridiem::from_wire_byte(mer_byte)
795 {
796 dc.meridiem = Some(m);
797 }
798
799 offset += 1;
800
801 let unix = i64::from_le_bytes(bytes[offset..offset + 8].try_into().ok()?);
803 if unix != i64::MIN {
804 dc.unix_timestamp_seconds = Some(unix);
805 }
806
807 Some(dc)
808 }
809}