1use crate::{
2 Drift, Dt, Every, LiteStr, Meridiem, Offset, Parts, Scale, Spacetime, TimeRange, Weekday,
3 civil_parts::{Epoch, Timestamp},
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 Meridiem {
258 pub const WIRE_SIZE: usize = 1;
259
260 #[inline]
261 pub const fn to_wire_byte(self) -> u8 {
262 match self {
263 Meridiem::AM => 0,
264 Meridiem::PM => 1,
265 }
266 }
267
268 #[inline]
269 pub const fn from_wire_byte(b: u8) -> Option<Self> {
270 match b {
271 0 => Some(Meridiem::AM),
272 1 => Some(Meridiem::PM),
273 _ => None,
274 }
275 }
276}
277
278impl Offset {
279 pub const WIRE_SIZE: usize = 5; pub fn to_wire_bytes(&self) -> [u8; Self::WIRE_SIZE] {
282 let mut buf = [0u8; Self::WIRE_SIZE];
283 match self {
284 Offset::None => buf[0] = 0,
285 Offset::Fixed(offset) => {
286 buf[0] = 1;
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::None),
299 1 => {
300 let offset = i32::from_le_bytes([bytes[1], bytes[2], bytes[3], bytes[4]]);
301 Some(Offset::Fixed(offset))
302 }
303 _ => None,
304 }
305 }
306}
307
308impl Weekday {
309 pub const WIRE_SIZE: usize = 1;
310
311 #[inline]
312 pub const fn to_wire_byte(self) -> u8 {
313 self.wkday_sun_0_based()
314 }
315
316 #[inline]
317 pub const fn from_wire_byte(b: u8) -> Option<Self> {
318 Self::from_sunday_0_based(b)
319 }
320}
321
322impl Parts {
323 pub const WIRE_VERSION: u8 = 1;
325
326 pub const WIRE_SIZE: usize = 120;
329
330 pub fn to_wire_bytes(&self) -> [u8; Self::WIRE_SIZE] {
332 let mut buf = [0u8; Self::WIRE_SIZE];
333 buf[0] = Self::WIRE_VERSION;
334
335 let mut offset = 1usize;
336
337 let year = self.yr.unwrap_or(i64::MIN);
339 buf[offset..offset + 8].copy_from_slice(&year.to_le_bytes());
340 offset += 8;
341
342 buf[offset] = self.mo.unwrap_or(u8::MAX);
344 offset += 1;
345
346 buf[offset] = self.day.unwrap_or(u8::MAX);
348 offset += 1;
349
350 buf[offset] = self.hr;
352 offset += 1;
353
354 buf[offset] = self.min;
356 offset += 1;
357
358 buf[offset] = self.sec;
360 offset += 1;
361
362 let attos = self.attos;
364 buf[offset..offset + 8].copy_from_slice(&attos.to_le_bytes());
365 offset += 8;
366
367 let offset_bytes = self.offset.unwrap_or_default().to_wire_bytes();
369 buf[offset..offset + 5].copy_from_slice(&offset_bytes);
370 offset += 5;
371
372 if let Some(name) = &self.iana_name {
374 let name_bytes = name.bytes;
375 buf[offset..offset + 49].copy_from_slice(&name_bytes);
376 }
377 offset += 49;
378
379 buf[offset] = self.scale as u8;
381 offset += 1;
382
383 buf[offset] = self.wkday.map_or(255, |w| w.to_wire_byte());
385 offset += 1;
386
387 let doy = self.day_of_yr.unwrap_or(u16::MAX);
389 buf[offset..offset + 2].copy_from_slice(&doy.to_le_bytes());
390 offset += 2;
391
392 let iso_y = self.iso_wk_yr.unwrap_or(i64::MIN);
394 buf[offset..offset + 8].copy_from_slice(&iso_y.to_le_bytes());
395 offset += 8;
396
397 buf[offset] = self.iso_wk.unwrap_or(u8::MAX);
399 offset += 1;
400
401 buf[offset] = self.wk_sun.unwrap_or(u8::MAX);
403 offset += 1;
404
405 buf[offset] = self.wk_mon.unwrap_or(u8::MAX);
407 offset += 1;
408
409 buf[offset] = self.meridiem.map_or(255, |m| m.to_wire_byte());
411 offset += 1;
412
413 let (tag, attos) = match self.timestamp {
416 None => (0u8, 0i128),
417 Some(ts) => {
418 let t = match ts.epoch {
419 Epoch::Unix => 1u8,
420 Epoch::Noon2000 => 2u8,
421 };
422 (t, ts.attos)
423 }
424 };
425 buf[offset] = tag;
426 offset += 1;
427 buf[offset..offset + 16].copy_from_slice(&attos.to_le_bytes());
428 buf
431 }
432
433 pub fn from_wire_bytes(bytes: &[u8]) -> Option<Self> {
435 if bytes.len() != Self::WIRE_SIZE {
436 return None;
437 }
438 if bytes[0] != Self::WIRE_VERSION {
439 return None;
440 }
441
442 let mut dc = Parts::default();
443 let mut offset = 1usize;
444
445 let year = i64::from_le_bytes(bytes[offset..offset + 8].try_into().ok()?);
447 if year != i64::MIN {
448 dc.yr = Some(year);
449 }
450 offset += 8;
451
452 let m = bytes[offset];
454 if m != u8::MAX {
455 dc.mo = Some(m);
456 }
457 offset += 1;
458
459 let d = bytes[offset];
461 if d != u8::MAX {
462 dc.day = Some(d);
463 }
464 offset += 1;
465
466 dc.hr = bytes[offset];
468 offset += 1;
469
470 dc.min = bytes[offset];
472 offset += 1;
473
474 dc.sec = bytes[offset];
476 offset += 1;
477
478 let attos = u64::from_le_bytes(bytes[offset..offset + 8].try_into().ok()?);
480 dc.attos = attos;
481 offset += 8;
482
483 if let Some(off) = Offset::from_wire_bytes(&bytes[offset..offset + 5]) {
485 dc.offset = Some(off);
486 }
487 offset += 5;
488
489 let iana_bytes = &bytes[offset..offset + 49];
491 let name = LiteStr::<49>::from_bytes(iana_bytes);
492 if !name.as_bytes().is_empty() {
493 dc.iana_name = Some(name);
494 }
495 offset += 49;
496
497 dc.scale = Scale::from_u8(bytes[offset]);
499 offset += 1;
500
501 let wd_byte = bytes[offset];
503 if wd_byte != 255
504 && let Some(wd) = Weekday::from_wire_byte(wd_byte)
505 {
506 dc.wkday = Some(wd);
507 }
508 offset += 1;
509
510 let doy = u16::from_le_bytes(bytes[offset..offset + 2].try_into().ok()?);
512 if doy != u16::MAX {
513 dc.day_of_yr = Some(doy);
514 }
515 offset += 2;
516
517 let iso_y = i64::from_le_bytes(bytes[offset..offset + 8].try_into().ok()?);
519 if iso_y != i64::MIN {
520 dc.iso_wk_yr = Some(iso_y);
521 }
522 offset += 8;
523
524 let iw = bytes[offset];
526 if iw != u8::MAX {
527 dc.iso_wk = Some(iw);
528 }
529 offset += 1;
530
531 let ws = bytes[offset];
533 if ws != u8::MAX {
534 dc.wk_sun = Some(ws);
535 }
536 offset += 1;
537
538 let wm = bytes[offset];
540 if wm != u8::MAX {
541 dc.wk_mon = Some(wm);
542 }
543 offset += 1;
544
545 let mer_byte = bytes[offset];
547 if mer_byte != 255
548 && let Some(m) = Meridiem::from_wire_byte(mer_byte)
549 {
550 dc.meridiem = Some(m);
551 }
552 offset += 1;
553
554 let tag = bytes[offset];
557 offset += 1;
558
559 if tag != 0 {
560 let attos_arr: [u8; 16] = bytes[offset..offset + 16].try_into().ok()?;
561 let attos = i128::from_le_bytes(attos_arr);
562 let epoch = match tag {
565 1 => Epoch::Unix,
566 2 => Epoch::Noon2000,
567 _ => return None,
568 };
569 dc.timestamp = Some(Timestamp { attos, epoch });
570 } else {
571 }
573
574 Some(dc)
575 }
576}