1use crate::{
2 Drift, Dt, Every, LiteStr, Meridiem, Offset, Scale, Spacetime, TimeParts, TimeRange, Weekday,
3};
4
5impl Dt {
6 pub const WIRE_VERSION: u8 = 1;
8
9 pub const WIRE_SIZE: usize = 19;
11
12 pub fn to_wire_bytes(&self) -> [u8; Self::WIRE_SIZE] {
22 let mut buf = [0u8; Self::WIRE_SIZE];
23 buf[0] = Self::WIRE_VERSION;
24 buf[1..17].copy_from_slice(&self.attos.to_le_bytes());
25 buf[17] = self.target as u8;
26 buf
27 }
28
29 pub fn from_wire_bytes(bytes: &[u8]) -> Option<Self> {
46 if bytes.len() != Self::WIRE_SIZE {
47 return None;
48 }
49
50 if bytes[0] != Self::WIRE_VERSION {
51 return None;
52 }
53
54 let attos = i128::from_le_bytes([
55 bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], bytes[8],
56 bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15], bytes[16],
57 ]);
58
59 let scale = Scale::from_u8(bytes[17]);
60 let target = Scale::from_u8(bytes[18]);
61
62 Some(Dt::new(attos, scale, target))
63 }
64}
65
66impl Drift {
67 pub const WIRE_VERSION: u8 = 1;
69
70 pub const WIRE_SIZE: usize = 3 * Dt::WIRE_SIZE; pub fn to_wire_bytes(&self) -> [u8; Self::WIRE_SIZE] {
77 let mut buf = [0u8; Self::WIRE_SIZE];
78 let c = self.constant.to_wire_bytes();
79 let r = self.rate.to_wire_bytes();
80 let a = self.accel.to_wire_bytes();
81
82 buf[0..Dt::WIRE_SIZE].copy_from_slice(&c);
83 buf[Dt::WIRE_SIZE..2 * Dt::WIRE_SIZE].copy_from_slice(&r);
84 buf[2 * Dt::WIRE_SIZE..].copy_from_slice(&a);
85 buf
86 }
87
88 pub fn from_wire_bytes(bytes: &[u8]) -> Option<Self> {
100 if bytes.len() != Self::WIRE_SIZE {
101 return None;
102 }
103
104 if bytes[0] != Self::WIRE_VERSION {
105 return None;
106 }
107
108 let constant = Dt::from_wire_bytes(&bytes[0..Dt::WIRE_SIZE])?;
109 let rate = Dt::from_wire_bytes(&bytes[Dt::WIRE_SIZE..2 * Dt::WIRE_SIZE])?;
110 let accel = Dt::from_wire_bytes(&bytes[2 * Dt::WIRE_SIZE..])?;
111
112 Some(Self::new(constant, rate, accel))
113 }
114}
115
116impl Spacetime {
117 pub const WIRE_SIZE: usize = 24;
119
120 pub fn to_wire_bytes(&self) -> [u8; Self::WIRE_SIZE] {
124 let mut buf = [0u8; Self::WIRE_SIZE];
125 buf[0..8].copy_from_slice(&self.alpha.to_le_bytes());
126 buf[8..16].copy_from_slice(&self.beta.to_le_bytes());
127 buf[16..24].copy_from_slice(&self.kretschmann.to_le_bytes());
128 buf
129 }
130
131 pub fn from_wire_bytes(bytes: &[u8]) -> Option<Self> {
139 if bytes.len() != Self::WIRE_SIZE {
140 return None;
141 }
142 let alpha = f64::from_le_bytes([
143 bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
144 ]);
145 let beta = f64::from_le_bytes([
146 bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15],
147 ]);
148 let kretschmann = f64::from_le_bytes([
149 bytes[16], bytes[17], bytes[18], bytes[19], bytes[20], bytes[21], bytes[22], bytes[23],
150 ]);
151 Some(Self {
152 alpha,
153 beta,
154 kretschmann,
155 })
156 }
157}
158
159impl Every {
160 pub const WIRE_SIZE: usize = Dt::WIRE_SIZE + Dt::WIRE_SIZE;
162
163 pub fn to_wire_bytes(&self) -> [u8; Self::WIRE_SIZE] {
167 let mut buf = [0u8; Self::WIRE_SIZE];
168 let start = self.start.to_wire_bytes();
169 let step = self.step.to_wire_bytes();
170 buf[0..17].copy_from_slice(&start);
171 buf[17..33].copy_from_slice(&step);
172 buf
173 }
174
175 pub fn from_wire_bytes(bytes: &[u8]) -> Option<Self> {
182 if bytes.len() != Self::WIRE_SIZE {
183 return None;
184 }
185 let start = Dt::from_wire_bytes(&bytes[0..17])?;
186 let step = Dt::from_wire_bytes(&bytes[17..33])?;
187 Some(Self { start, step })
188 }
189}
190
191impl TimeRange {
192 pub const WIRE_VERSION: u8 = 1;
194
195 pub const WIRE_SIZE: usize = 1 + 2 * Dt::WIRE_SIZE + Dt::WIRE_SIZE + 1;
198
199 pub fn to_wire_bytes(&self) -> [u8; Self::WIRE_SIZE] {
206 let mut buf = [0u8; Self::WIRE_SIZE];
207 buf[0] = Self::WIRE_VERSION;
208
209 let start = self.start.to_wire_bytes();
210 let end = self.end.to_wire_bytes();
211 let step = self.step.to_wire_bytes();
212
213 let tp_size = Dt::WIRE_SIZE;
214 let span_size = Dt::WIRE_SIZE;
215
216 buf[1..1 + tp_size].copy_from_slice(&start);
217 buf[1 + tp_size..1 + 2 * tp_size].copy_from_slice(&end);
218 buf[1 + 2 * tp_size..1 + 2 * tp_size + span_size].copy_from_slice(&step);
219 buf[1 + 2 * tp_size + span_size] = if self.inclusive { 1 } else { 0 };
220
221 buf
222 }
223
224 pub fn from_wire_bytes(bytes: &[u8]) -> Option<Self> {
236 if bytes.len() != Self::WIRE_SIZE {
237 return None;
238 }
239
240 if bytes[0] != Self::WIRE_VERSION {
241 return None;
242 }
243
244 let tp_size = Dt::WIRE_SIZE;
245 let span_size = Dt::WIRE_SIZE;
246
247 let start = Dt::from_wire_bytes(&bytes[1..1 + tp_size])?;
248 let end = Dt::from_wire_bytes(&bytes[1 + tp_size..1 + 2 * tp_size])?;
249 let step = Dt::from_wire_bytes(&bytes[1 + 2 * tp_size..1 + 2 * tp_size + span_size])?;
250 let inclusive = bytes[1 + 2 * tp_size + span_size] != 0;
251
252 Some(Self::new(start, end, step, inclusive))
253 }
254}
255
256impl Meridiem {
257 pub const WIRE_SIZE: usize = 1;
258
259 #[inline]
260 pub const fn to_wire_byte(self) -> u8 {
261 match self {
262 Meridiem::AM => 0,
263 Meridiem::PM => 1,
264 }
265 }
266
267 #[inline]
268 pub const fn from_wire_byte(b: u8) -> Option<Self> {
269 match b {
270 0 => Some(Meridiem::AM),
271 1 => Some(Meridiem::PM),
272 _ => None,
273 }
274 }
275}
276
277impl Offset {
278 pub const WIRE_SIZE: usize = 5; pub fn to_wire_bytes(&self) -> [u8; Self::WIRE_SIZE] {
281 let mut buf = [0u8; Self::WIRE_SIZE];
282 match self {
283 Offset::Utc => buf[0] = 0,
284 Offset::None => buf[0] = 1,
285 Offset::Fixed(offset) => {
286 buf[0] = 2;
287 buf[1..5].copy_from_slice(&offset.to_le_bytes());
288 }
289 }
290 buf
291 }
292
293 pub fn from_wire_bytes(bytes: &[u8]) -> Option<Self> {
294 if bytes.len() != Self::WIRE_SIZE {
295 return None;
296 }
297 match bytes[0] {
298 0 => Some(Offset::Utc),
299 1 => Some(Offset::None),
300 2 => {
301 let offset = i32::from_le_bytes([bytes[1], bytes[2], bytes[3], bytes[4]]);
302 Some(Offset::Fixed(offset))
303 }
304 _ => None,
305 }
306 }
307}
308
309impl Weekday {
310 pub const WIRE_SIZE: usize = 1;
311
312 #[inline]
313 pub const fn to_wire_byte(self) -> u8 {
314 self.wkday_sun_0_based()
315 }
316
317 #[inline]
318 pub const fn from_wire_byte(b: u8) -> Option<Self> {
319 Self::from_sunday_0_based(b)
320 }
321}
322
323impl TimeParts {
324 pub const WIRE_VERSION: u8 = 1;
326
327 pub const WIRE_SIZE: usize = 120;
329
330 pub fn to_wire_bytes(&self) -> [u8; Self::WIRE_SIZE] {
336 let mut buf = [0u8; Self::WIRE_SIZE];
337 buf[0] = Self::WIRE_VERSION;
338
339 let mut offset = 1usize;
340
341 let year = self.yr.unwrap_or(i64::MIN);
343 buf[offset..offset + 8].copy_from_slice(&year.to_le_bytes());
344 offset += 8;
345
346 buf[offset] = self.mo.unwrap_or(u8::MAX);
348 offset += 1;
349
350 buf[offset] = self.day.unwrap_or(u8::MAX);
352 offset += 1;
353
354 buf[offset] = self.hr.unwrap_or(u8::MAX);
356 offset += 1;
357
358 buf[offset] = self.min.unwrap_or(u8::MAX);
360 offset += 1;
361
362 buf[offset] = self.sec.unwrap_or(u8::MAX);
364 offset += 1;
365
366 let attos = self.attos.unwrap_or(u64::MAX);
368 buf[offset..offset + 8].copy_from_slice(&attos.to_le_bytes());
369 offset += 8;
370
371 let offset_bytes = self.offset.unwrap_or_default().to_wire_bytes();
373 buf[offset..offset + 5].copy_from_slice(&offset_bytes);
374 offset += 5;
375
376 if let Some(name) = &self.iana_name {
378 let name_bytes = name.bytes;
379 buf[offset..offset + 49].copy_from_slice(&name_bytes);
380 }
381 offset += 49;
382
383 buf[offset] = if self.is_leap_sec { 1 } else { 0 };
385 offset += 1;
386
387 buf[offset] = self.scale as u8;
389 offset += 1;
390
391 buf[offset] = self.wkday.map_or(255, |w| w.to_wire_byte());
393 offset += 1;
394
395 let doy = self.day_of_yr.unwrap_or(u16::MAX);
397 buf[offset..offset + 2].copy_from_slice(&doy.to_le_bytes());
398 offset += 2;
399
400 let iso_y = self.iso_wk_yr.unwrap_or(i64::MIN);
402 buf[offset..offset + 8].copy_from_slice(&iso_y.to_le_bytes());
403 offset += 8;
404
405 buf[offset] = self.iso_wk.unwrap_or(u8::MAX);
407 offset += 1;
408
409 buf[offset] = self.wk_sun.unwrap_or(u8::MAX);
411 offset += 1;
412
413 buf[offset] = self.wk_mon.unwrap_or(u8::MAX);
415 offset += 1;
416
417 buf[offset] = self.meridiem.map_or(255, |m| m.to_wire_byte());
419 offset += 1;
420
421 let unix = self.unix_timestamp_seconds.unwrap_or(i64::MIN);
423 buf[offset..offset + 8].copy_from_slice(&unix.to_le_bytes());
424
425 buf
426 }
427
428 pub fn from_wire_bytes(bytes: &[u8]) -> Option<Self> {
432 if bytes.len() != Self::WIRE_SIZE {
433 return None;
434 }
435 if bytes[0] != Self::WIRE_VERSION {
436 return None;
437 }
438
439 let mut dc = TimeParts::default();
440 let mut offset = 1usize;
441
442 let year = i64::from_le_bytes(bytes[offset..offset + 8].try_into().ok()?);
444 if year != i64::MIN {
445 dc.yr = Some(year);
446 }
447 offset += 8;
448
449 let m = bytes[offset];
451 if m != u8::MAX {
452 dc.mo = Some(m);
453 }
454 offset += 1;
455
456 let d = bytes[offset];
458 if d != u8::MAX {
459 dc.day = Some(d);
460 }
461 offset += 1;
462
463 let h = bytes[offset];
465 if h != u8::MAX {
466 dc.hr = Some(h);
467 }
468 offset += 1;
469
470 let min = bytes[offset];
472 if min != u8::MAX {
473 dc.min = Some(min);
474 }
475 offset += 1;
476
477 let sec = bytes[offset];
479 if sec != u8::MAX {
480 dc.sec = Some(sec);
481 }
482 offset += 1;
483
484 let attos = u64::from_le_bytes(bytes[offset..offset + 8].try_into().ok()?);
486 if attos != u64::MAX {
487 dc.attos = Some(attos);
488 }
489 offset += 8;
490
491 if let Some(offset) = Offset::from_wire_bytes(&bytes[offset..offset + 5]) {
493 dc.offset = Some(offset);
494 }
495 offset += 5;
496
497 let iana_bytes = &bytes[offset..offset + 49];
499 let name = LiteStr::<49>::from_bytes(iana_bytes);
500 if !name.as_bytes().len() == 0 {
501 dc.iana_name = Some(name);
502 }
503 offset += 49;
504
505 dc.is_leap_sec = bytes[offset] != 0;
507 offset += 1;
508
509 dc.scale = Scale::from_u8(bytes[offset]);
511 offset += 1;
512
513 let wd_byte = bytes[offset];
515 if wd_byte != 255
516 && let Some(wd) = Weekday::from_wire_byte(wd_byte)
517 {
518 dc.wkday = Some(wd);
519 }
520 offset += 1;
521
522 let doy = u16::from_le_bytes(bytes[offset..offset + 2].try_into().ok()?);
524 if doy != u16::MAX {
525 dc.day_of_yr = Some(doy);
526 }
527 offset += 2;
528
529 let iso_y = i64::from_le_bytes(bytes[offset..offset + 8].try_into().ok()?);
531 if iso_y != i64::MIN {
532 dc.iso_wk_yr = Some(iso_y);
533 }
534 offset += 8;
535
536 let iw = bytes[offset];
538 if iw != u8::MAX {
539 dc.iso_wk = Some(iw);
540 }
541 offset += 1;
542
543 let ws = bytes[offset];
545 if ws != u8::MAX {
546 dc.wk_sun = Some(ws);
547 }
548 offset += 1;
549
550 let wm = bytes[offset];
552 if wm != u8::MAX {
553 dc.wk_mon = Some(wm);
554 }
555 offset += 1;
556
557 let mer_byte = bytes[offset];
559 if mer_byte != 255
560 && let Some(m) = Meridiem::from_wire_byte(mer_byte)
561 {
562 dc.meridiem = Some(m);
563 }
564
565 offset += 1;
566
567 let unix = i64::from_le_bytes(bytes[offset..offset + 8].try_into().ok()?);
569 if unix != i64::MIN {
570 dc.unix_timestamp_seconds = Some(unix);
571 }
572
573 Some(dc)
574 }
575}