1use alloc::borrow::Cow;
2use alloc::vec::Vec;
3
4use deser_core::State;
5use deser_core::de::{Deserialize, Sink, SinkHandle};
6use deser_core::ext::{ExtValue, Extension, Timestamp};
7use deser_core::ser::{Chunk, 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(&self, _state: &mut State) -> Result<Chunk<'_>, Error> {
63 Ok(Chunk::Atom(Atom::Ext(ExtValue::borrowed(self))))
64 }
65}
66
67impl<'de> Deserialize<'de> for Ext {
68 fn deserialize_into<'out>(
69 out: &'out mut Option<Self>,
70 state: &mut State,
71 ) -> SinkHandle<'out, 'de> {
72 SinkHandle::arena(ExtSink(out), state)
73 }
74}
75
76struct ExtSink<'a>(&'a mut Option<Ext>);
77
78impl<'a, 'de> Sink<'de> for ExtSink<'a> {
79 fn expecting(&self) -> Cow<'_, str> {
80 Cow::Borrowed("msgpack extension")
81 }
82
83 fn atom(&mut self, atom: Atom, state: &mut State) -> Result<(), Error> {
84 let value = match atom {
85 Atom::Ext(ref ext) => {
86 if let Some(value) = ext.downcast_ref::<Ext>() {
87 value.clone()
88 } else if let Some(value) = ext.downcast_ref::<Timestamp>() {
89 let mut buf = [0; 12];
90 Ext::new(TIMESTAMP, encode_timestamp(value, &mut buf))
91 } else {
92 return self.unexpected_atom(atom, state);
93 }
94 }
95 other => return self.unexpected_atom(other, state),
96 };
97 *self.0 = Some(value);
98 Ok(())
99 }
100}
101
102pub(crate) fn decode_timestamp(data: &[u8]) -> Option<Timestamp> {
106 let (seconds, nanosecond) = match data.len() {
107 4 => (i64::from(u32::from_be_bytes(data.try_into().unwrap())), 0),
109 8 => {
111 let value = u64::from_be_bytes(data.try_into().unwrap());
112 ((value & 0x3_ffff_ffff) as i64, (value >> 34) as u32)
113 }
114 12 => (
116 i64::from_be_bytes(data[4..].try_into().unwrap()),
117 u32::from_be_bytes(data[..4].try_into().unwrap()),
118 ),
119 _ => return None,
120 };
121 (nanosecond < 1_000_000_000).then_some(Timestamp {
122 seconds,
123 nanosecond,
124 })
125}
126
127pub(crate) fn encode_timestamp<'b>(value: &Timestamp, buf: &'b mut [u8; 12]) -> &'b [u8] {
129 if value.seconds >> 34 == 0 {
130 if value.nanosecond == 0 && value.seconds <= i64::from(u32::MAX) {
131 buf[..4].copy_from_slice(&(value.seconds as u32).to_be_bytes());
132 &buf[..4]
133 } else {
134 let packed = (u64::from(value.nanosecond) << 34) | value.seconds as u64;
135 buf[..8].copy_from_slice(&packed.to_be_bytes());
136 &buf[..8]
137 }
138 } else {
139 buf[..4].copy_from_slice(&value.nanosecond.to_be_bytes());
140 buf[4..].copy_from_slice(&value.seconds.to_be_bytes());
141 &buf[..]
142 }
143}
144
145#[test]
146fn test_timestamp_codec() {
147 for (seconds, nanosecond, len) in [
148 (0, 0, 4),
149 (u32::MAX as i64, 0, 4),
150 (u32::MAX as i64 + 1, 0, 8),
151 (0, 1, 8),
152 ((1 << 34) - 1, 999_999_999, 8),
153 (1 << 34, 0, 12),
154 (-1, 0, 12),
155 (i64::MIN, 999_999_999, 12),
156 (i64::MAX, 0, 12),
157 ] {
158 let value = Timestamp {
159 seconds,
160 nanosecond,
161 };
162 let mut buf = [0; 12];
163 let data = encode_timestamp(&value, &mut buf);
164 assert_eq!(data.len(), len, "{:?}", value);
165 assert_eq!(decode_timestamp(data), Some(value));
166 }
167 assert_eq!(decode_timestamp(&[0xee, 0x6b, 0x28, 0, 0, 0, 0, 0]), None);
169 assert_eq!(
170 decode_timestamp(&[0x3b, 0x9a, 0xca, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
171 None
172 );
173 assert_eq!(decode_timestamp(&[0, 0, 0]), None);
174}