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::None => buf[0] = 0,
284 Offset::Fixed(offset) => {
285 buf[0] = 1;
286 buf[1..5].copy_from_slice(&offset.to_le_bytes());
287 }
288 }
289 buf
290 }
291
292 pub fn from_wire_bytes(bytes: &[u8]) -> Option<Self> {
293 if bytes.len() != Self::WIRE_SIZE {
294 return None;
295 }
296 match bytes[0] {
297 0 => Some(Offset::None),
298 1 => {
299 let offset = i32::from_le_bytes([bytes[1], bytes[2], bytes[3], bytes[4]]);
300 Some(Offset::Fixed(offset))
301 }
302 _ => None,
303 }
304 }
305}
306
307impl Weekday {
308 pub const WIRE_SIZE: usize = 1;
309
310 #[inline]
311 pub const fn to_wire_byte(self) -> u8 {
312 self.wkday_sun_0_based()
313 }
314
315 #[inline]
316 pub const fn from_wire_byte(b: u8) -> Option<Self> {
317 Self::from_sunday_0_based(b)
318 }
319}
320
321impl TimeParts {
322 pub const WIRE_VERSION: u8 = 1;
324
325 pub const WIRE_SIZE: usize = 119;
327
328 pub fn to_wire_bytes(&self) -> [u8; Self::WIRE_SIZE] {
330 let mut buf = [0u8; Self::WIRE_SIZE];
331 buf[0] = Self::WIRE_VERSION;
332
333 let mut offset = 1usize;
334
335 let year = self.yr.unwrap_or(i64::MIN);
337 buf[offset..offset + 8].copy_from_slice(&year.to_le_bytes());
338 offset += 8;
339
340 buf[offset] = self.mo.unwrap_or(u8::MAX);
342 offset += 1;
343
344 buf[offset] = self.day.unwrap_or(u8::MAX);
346 offset += 1;
347
348 buf[offset] = self.hr;
350 offset += 1;
351
352 buf[offset] = self.min;
354 offset += 1;
355
356 buf[offset] = self.sec;
358 offset += 1;
359
360 let attos = self.attos;
362 buf[offset..offset + 8].copy_from_slice(&attos.to_le_bytes());
363 offset += 8;
364
365 let offset_bytes = self.offset.unwrap_or_default().to_wire_bytes();
367 buf[offset..offset + 5].copy_from_slice(&offset_bytes);
368 offset += 5;
369
370 if let Some(name) = &self.iana_name {
372 let name_bytes = name.bytes;
373 buf[offset..offset + 49].copy_from_slice(&name_bytes);
374 }
375 offset += 49;
376
377 buf[offset] = self.scale as u8;
379 offset += 1;
380
381 buf[offset] = self.wkday.map_or(255, |w| w.to_wire_byte());
383 offset += 1;
384
385 let doy = self.day_of_yr.unwrap_or(u16::MAX);
387 buf[offset..offset + 2].copy_from_slice(&doy.to_le_bytes());
388 offset += 2;
389
390 let iso_y = self.iso_wk_yr.unwrap_or(i64::MIN);
392 buf[offset..offset + 8].copy_from_slice(&iso_y.to_le_bytes());
393 offset += 8;
394
395 buf[offset] = self.iso_wk.unwrap_or(u8::MAX);
397 offset += 1;
398
399 buf[offset] = self.wk_sun.unwrap_or(u8::MAX);
401 offset += 1;
402
403 buf[offset] = self.wk_mon.unwrap_or(u8::MAX);
405 offset += 1;
406
407 buf[offset] = self.meridiem.map_or(255, |m| m.to_wire_byte());
409 offset += 1;
410
411 let unix = self.unix_timestamp_seconds.unwrap_or(i64::MIN);
413 buf[offset..offset + 8].copy_from_slice(&unix.to_le_bytes());
414
415 buf
416 }
417
418 pub fn from_wire_bytes(bytes: &[u8]) -> Option<Self> {
420 if bytes.len() != Self::WIRE_SIZE {
421 return None;
422 }
423 if bytes[0] != Self::WIRE_VERSION {
424 return None;
425 }
426
427 let mut dc = TimeParts::default();
428 let mut offset = 1usize;
429
430 let year = i64::from_le_bytes(bytes[offset..offset + 8].try_into().ok()?);
432 if year != i64::MIN {
433 dc.yr = Some(year);
434 }
435 offset += 8;
436
437 let m = bytes[offset];
439 if m != u8::MAX {
440 dc.mo = Some(m);
441 }
442 offset += 1;
443
444 let d = bytes[offset];
446 if d != u8::MAX {
447 dc.day = Some(d);
448 }
449 offset += 1;
450
451 dc.hr = bytes[offset];
453 offset += 1;
454
455 dc.min = bytes[offset];
457 offset += 1;
458
459 dc.sec = bytes[offset];
461 offset += 1;
462
463 let attos = u64::from_le_bytes(bytes[offset..offset + 8].try_into().ok()?);
465 dc.attos = attos;
466 offset += 8;
467
468 if let Some(off) = Offset::from_wire_bytes(&bytes[offset..offset + 5]) {
470 dc.offset = Some(off);
471 }
472 offset += 5;
473
474 let iana_bytes = &bytes[offset..offset + 49];
476 let name = LiteStr::<49>::from_bytes(iana_bytes);
477 if !name.as_bytes().is_empty() {
478 dc.iana_name = Some(name);
479 }
480 offset += 49;
481
482 dc.scale = Scale::from_u8(bytes[offset]);
484 offset += 1;
485
486 let wd_byte = bytes[offset];
488 if wd_byte != 255
489 && let Some(wd) = Weekday::from_wire_byte(wd_byte)
490 {
491 dc.wkday = Some(wd);
492 }
493 offset += 1;
494
495 let doy = u16::from_le_bytes(bytes[offset..offset + 2].try_into().ok()?);
497 if doy != u16::MAX {
498 dc.day_of_yr = Some(doy);
499 }
500 offset += 2;
501
502 let iso_y = i64::from_le_bytes(bytes[offset..offset + 8].try_into().ok()?);
504 if iso_y != i64::MIN {
505 dc.iso_wk_yr = Some(iso_y);
506 }
507 offset += 8;
508
509 let iw = bytes[offset];
511 if iw != u8::MAX {
512 dc.iso_wk = Some(iw);
513 }
514 offset += 1;
515
516 let ws = bytes[offset];
518 if ws != u8::MAX {
519 dc.wk_sun = Some(ws);
520 }
521 offset += 1;
522
523 let wm = bytes[offset];
525 if wm != u8::MAX {
526 dc.wk_mon = Some(wm);
527 }
528 offset += 1;
529
530 let mer_byte = bytes[offset];
532 if mer_byte != 255
533 && let Some(m) = Meridiem::from_wire_byte(mer_byte)
534 {
535 dc.meridiem = Some(m);
536 }
537 offset += 1;
538
539 let unix = i64::from_le_bytes(bytes[offset..offset + 8].try_into().ok()?);
541 if unix != i64::MIN {
542 dc.unix_timestamp_seconds = Some(unix);
543 }
544
545 Some(dc)
546 }
547}