1use alloc::borrow::Cow;
2use alloc::vec::Vec;
3
4use deser_core::State;
5use deser_core::de::{Deserialize, Slot, default_atom};
6use deser_core::ext::{ExtValue, Extension, Timestamp};
7use deser_core::ser::{Emit, Serialize};
8use deser_core::{Atom, Bytes, Error};
9
10pub(crate) const TIMESTAMP: i8 = -1;
12
13#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
33pub struct Ext {
34 pub kind: i8,
37 pub data: Vec<u8>,
39}
40
41impl Ext {
42 pub fn new(kind: i8, data: impl Into<Vec<u8>>) -> Ext {
44 Ext {
45 kind,
46 data: data.into(),
47 }
48 }
49}
50
51impl Extension for Ext {
52 fn name(&self) -> &str {
53 "msgpack extension"
54 }
55
56 fn fallback(&self) -> Atom<'_> {
57 Atom::Bytes(Bytes::borrowed(&self.data))
58 }
59}
60
61impl Serialize for Ext {
62 fn serialize<'a>(value: &'a Self, _state: &mut State) -> Result<Emit<'a>, Error> {
63 Ok(Emit::Atom(Atom::Ext(ExtValue::borrowed(value))))
64 }
65}
66
67impl<'de> Deserialize<'de> for Ext {
68 fn deserialize_atom(slot: &mut Slot<Self>, atom: Atom, state: &mut State) -> Result<(), Error> {
69 let value = match atom {
70 Atom::Ext(ref ext) => {
71 if let Some(value) = ext.downcast_ref::<Ext>() {
72 value.clone()
73 } else if let Some(value) = ext.downcast_ref::<Timestamp>() {
74 let mut buf = [0; 12];
75 Ext::new(TIMESTAMP, encode_timestamp(value, &mut buf))
76 } else {
77 return default_atom(slot, atom, state);
78 }
79 }
80 other => return default_atom(slot, other, state),
81 };
82 slot.set(value);
83 Ok(())
84 }
85
86 fn expecting() -> Cow<'static, str> {
87 Cow::Borrowed("msgpack extension")
88 }
89}
90
91pub(crate) fn decode_timestamp(data: &[u8]) -> Option<Timestamp> {
95 let (seconds, nanosecond) = match data.len() {
96 4 => (i64::from(u32::from_be_bytes(data.try_into().unwrap())), 0),
98 8 => {
100 let value = u64::from_be_bytes(data.try_into().unwrap());
101 ((value & 0x3_ffff_ffff) as i64, (value >> 34) as u32)
102 }
103 12 => (
105 i64::from_be_bytes(data[4..].try_into().unwrap()),
106 u32::from_be_bytes(data[..4].try_into().unwrap()),
107 ),
108 _ => return None,
109 };
110 (nanosecond < 1_000_000_000).then_some(Timestamp {
111 seconds,
112 nanosecond,
113 })
114}
115
116pub(crate) fn encode_timestamp<'b>(value: &Timestamp, buf: &'b mut [u8; 12]) -> &'b [u8] {
118 if value.seconds >> 34 == 0 {
119 if value.nanosecond == 0 && value.seconds <= i64::from(u32::MAX) {
120 buf[..4].copy_from_slice(&(value.seconds as u32).to_be_bytes());
121 &buf[..4]
122 } else {
123 let packed = (u64::from(value.nanosecond) << 34) | value.seconds as u64;
124 buf[..8].copy_from_slice(&packed.to_be_bytes());
125 &buf[..8]
126 }
127 } else {
128 buf[..4].copy_from_slice(&value.nanosecond.to_be_bytes());
129 buf[4..].copy_from_slice(&value.seconds.to_be_bytes());
130 &buf[..]
131 }
132}
133
134#[test]
135fn test_timestamp_codec() {
136 for (seconds, nanosecond, len) in [
137 (0, 0, 4),
138 (u32::MAX as i64, 0, 4),
139 (u32::MAX as i64 + 1, 0, 8),
140 (0, 1, 8),
141 ((1 << 34) - 1, 999_999_999, 8),
142 (1 << 34, 0, 12),
143 (-1, 0, 12),
144 (i64::MIN, 999_999_999, 12),
145 (i64::MAX, 0, 12),
146 ] {
147 let value = Timestamp {
148 seconds,
149 nanosecond,
150 };
151 let mut buf = [0; 12];
152 let data = encode_timestamp(&value, &mut buf);
153 assert_eq!(data.len(), len, "{:?}", value);
154 assert_eq!(decode_timestamp(data), Some(value));
155 }
156 assert_eq!(decode_timestamp(&[0xee, 0x6b, 0x28, 0, 0, 0, 0, 0]), None);
158 assert_eq!(
159 decode_timestamp(&[0x3b, 0x9a, 0xca, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
160 None
161 );
162 assert_eq!(decode_timestamp(&[0, 0, 0]), None);
163}