embedded_msgpack/ext/
timestamp.rs

1use super::ExtType;
2use crate::{
3    decode::Error as DeError,
4    encode::{Error as SerError, SerializeIntoSlice},
5    Ext,
6};
7use byteorder::{BigEndian, ByteOrder};
8use core::convert::{TryFrom, TryInto};
9
10const EXT_TIMESTAMP: ExtType = ExtType(-1);
11
12pub(crate) const TYPE_NAME: &'static str = "$Timestamp";
13pub(crate) const FIELD_SECONDS_NAME: &'static str = "seconds";
14pub(crate) const FIELD_NANOSECONDS_NAME: &'static str = "nanoseconds";
15
16#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
17#[cfg_attr(any(test, feature = "derive-debug"), derive(core::fmt::Debug))]
18pub struct Timestamp {
19    seconds: i64,
20    nanoseconds: u32,
21}
22
23impl Timestamp {
24    pub const fn new(seconds: i64, nanoseconds: u32) -> Result<Timestamp, DeError> {
25        let mut seconds = seconds;
26        let mut nanoseconds = nanoseconds;
27        while nanoseconds >= 1_000_000_000 {
28            // This will be at most 4 times, so it can't become a performance problem
29            seconds += 1;
30            nanoseconds -= 1_000_000_000;
31        }
32        Ok(Timestamp { seconds, nanoseconds })
33    }
34
35    pub const fn seconds(&self) -> i64 { self.seconds }
36    pub const fn nanoseconds(&self) -> u32 { self.nanoseconds }
37
38    #[allow(clippy::cast_sign_loss)]
39    #[allow(clippy::cast_possible_truncation)]
40    pub fn to_ext<'a>(&self, data: &'a mut [u8]) -> Result<Ext<'a>, SerError> {
41        if self.seconds >> 34 == 0 {
42            let x = (u64::from(self.nanoseconds) << 34) | self.seconds as u64;
43            if x & 0xffff_ffff_0000_0000_u64 == 0 {
44                // timestamp 32
45                if data.len() < 4 {
46                    return Err(SerError::EndOfBuffer);
47                }
48                BigEndian::write_u32(data, x as u32);
49                Ok(Ext::new(-1, &data[0..4]))
50            } else {
51                // timestamp 64
52                if data.len() < 8 {
53                    return Err(SerError::EndOfBuffer);
54                }
55                BigEndian::write_u64(data, x);
56                Ok(Ext::new(-1, &data[0..8]))
57            }
58        } else {
59            // timestamp 96
60            #[cfg(feature = "timestamp96")]
61            {
62                if data.len() < 12 {
63                    return Err(SerError::EndOfBuffer);
64                }
65                BigEndian::write_u32(data, self.nanoseconds);
66                BigEndian::write_i64(&mut data[4..], self.seconds);
67                return Ok(Ext::new(-1, &data[0..12]));
68            }
69            #[cfg(not(feature = "timestamp96"))]
70            return Err(SerError::InvalidType);
71        }
72    }
73}
74
75impl SerializeIntoSlice for Timestamp {
76    fn write_into_slice(&self, buf: &mut [u8]) -> Result<usize, SerError> {
77        let mut tmp = [0; 12];
78        let ext = self.to_ext(&mut tmp)?;
79        crate::ext::serialize_ext(&ext, buf)
80    }
81}
82
83pub fn try_deserialize(buf: &[u8]) -> Result<Timestamp, DeError> { crate::ext::try_deserialize_ext(&buf)?.try_into() }
84
85impl<'a> TryFrom<Ext<'a>> for Timestamp {
86    type Error = DeError;
87
88    #[allow(clippy::cast_possible_truncation)]
89    fn try_from(ext: Ext<'a>) -> Result<Self, Self::Error> {
90        if ext.typ == EXT_TIMESTAMP {
91            match ext.data.len() {
92                4 => {
93                    // timestamp 32 stores the number of seconds that have elapsed since 1970-01-01 00:00:00 UTC
94                    // in an 32-bit unsigned integer:
95                    // +--------+--------+--------+--------+--------+--------+
96                    // |  0xd6  |   -1   |   seconds in 32-bit unsigned int  |
97                    // +--------+--------+--------+--------+--------+--------+
98                    Timestamp::new(i64::from(BigEndian::read_u32(&ext.data)), 0)
99                }
100                #[allow(clippy::cast_possible_wrap)]
101                8 => {
102                    // timestamp 64 stores the number of seconds and nanoseconds that have elapsed since 1970-01-01 00:00:00 UTC
103                    // in 32-bit unsigned integers:
104                    // +--------+--------+--------+--------+--------+------|-+--------+--------+--------+--------+
105                    // |  0xd7  |   -1   | nanosec. in 30-bit unsigned int |   seconds in 34-bit unsigned int    |
106                    // +--------+--------+--------+--------+--------+------^-+--------+--------+--------+--------+
107                    let value = BigEndian::read_u64(&ext.data);
108                    Timestamp::new((value & 0x0000_0003_ffff_ffff_u64) as i64, (value >> 34) as u32)
109                }
110                #[cfg(feature = "timestamp96")]
111                12 => {
112                    // timestamp 96 stores the number of seconds and nanoseconds that have elapsed since 1970-01-01 00:00:00 UTC
113                    // in 64-bit signed integer and 32-bit unsigned integer:
114                    // +--------+--------+--------+--------+--------+--------+--------+
115                    // |  0xc7  |   12   |   -1   |nanoseconds in 32-bit unsigned int |
116                    // +--------+--------+--------+--------+--------+--------+--------+
117                    // +--------+--------+--------+--------+--------+--------+--------+--------+
118                    // |                   seconds in 64-bit signed int                        |
119                    // +--------+--------+--------+--------+--------+--------+--------+--------+
120                    let nanos = BigEndian::read_u32(&ext.data[0..4]);
121                    let s = BigEndian::read_i64(&ext.data[4..12]);
122                    Timestamp::new(s, nanos)
123                }
124                _ => Err(DeError::InvalidType),
125            }
126        } else {
127            Err(DeError::InvalidType)
128        }
129    }
130}
131
132#[cfg(feature = "serde")]
133impl ::serde::ser::Serialize for Timestamp {
134    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
135    where S: serde::Serializer {
136        use serde::ser::SerializeStruct;
137        let mut s = serializer.serialize_struct(TYPE_NAME, 2)?;
138        s.serialize_field(FIELD_SECONDS_NAME, &self.seconds)?;
139        s.serialize_field(FIELD_NANOSECONDS_NAME, &self.nanoseconds)?;
140        s.end()
141    }
142}
143
144#[cfg(feature = "serde")]
145impl<'de> ::serde::de::Deserialize<'de> for Timestamp {
146    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
147    where D: ::serde::de::Deserializer<'de> {
148        use crate::encode::Binary;
149        struct TimestampVisitor<'a>(core::marker::PhantomData<&'a ()>);
150
151        impl<'de: 'a, 'a> ::serde::de::Visitor<'de> for TimestampVisitor<'a> {
152            type Value = Timestamp;
153            fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { formatter.write_str("a MsgPack ext data") }
154            fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
155            where A: serde::de::SeqAccess<'de> {
156                // This will be called from the MsgPack deserializer
157                // if it detects an ext tag or an array tag
158                let typ: Option<ExtType> = seq.next_element()?;
159                let data: Option<Binary> = seq.next_element()?;
160                match (typ, data) {
161                    (Some(typ), Some(data)) => Ok(Ext::new(typ.0, &data).try_into().map_err(::serde::de::Error::custom)?),
162                    (Some(_), None) => Err(::serde::de::Error::custom("ext data not found")),
163                    _ => Err(::serde::de::Error::custom("ext type field not found")),
164                }
165            }
166            fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
167            where V: ::serde::de::MapAccess<'de> {
168                // This will probably be called from other deserializers
169                // or if the MsgPack deserializer sees a map tag
170
171                enum Field {
172                    Seconds,
173                    Nanoseconds,
174                    Type,
175                    Data,
176                }
177
178                impl<'de> ::serde::de::Deserialize<'de> for Field {
179                    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
180                    where D: serde::Deserializer<'de> {
181                        struct FieldVisitor;
182                        impl<'de> ::serde::de::Visitor<'de> for FieldVisitor {
183                            type Value = Field;
184                            fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
185                                formatter.write_str("`seconds`, `secs`, `s`, `nanoseconds`, `nanos`, `ns`, `type` or `data`")
186                            }
187                            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
188                            where E: serde::de::Error {
189                                match v {
190                                    "seconds" | "secs" | "s" => Ok(Field::Seconds),
191                                    "nanoseconds" | "nanos" | "ns" => Ok(Field::Nanoseconds),
192                                    "type" => Ok(Field::Type),
193                                    "data" => Ok(Field::Data),
194                                    _ => Err(::serde::de::Error::unknown_field(
195                                        v,
196                                        &["seconds", "secs", "s", "nanoseconds", "nanos", "ns", "type", "data"],
197                                    )),
198                                }
199                            }
200                        }
201
202                        deserializer.deserialize_identifier(FieldVisitor)
203                    }
204                }
205
206                let mut typ = None;
207                let mut data = None;
208                let mut seconds = None;
209                let mut nanoseconds = None;
210
211                loop {
212                    match map.next_key::<Field>() {
213                        Ok(Some(Field::Type)) => typ = Some(map.next_value::<ExtType>()?),
214                        Ok(Some(Field::Data)) => data = Some(map.next_value::<Binary>()?),
215                        Ok(Some(Field::Seconds)) => seconds = Some(map.next_value::<i64>()?),
216                        Ok(Some(Field::Nanoseconds)) => nanoseconds = Some(map.next_value::<u32>()?),
217                        Ok(None) => break, // no more fields
218                        Err(_e) => {
219                            // Error, could be an unknown field name
220                            // println!("{:?}", e);
221                            map.next_value()?;
222                        }
223                    }
224                }
225
226                match (typ, data, seconds, nanoseconds) {
227                    (Some(typ), Some(data), None, None) => Ok(Ext::new(typ.0, &data).try_into().map_err(::serde::de::Error::custom)?),
228                    (None, None, Some(seconds), Some(nanoseconds)) => {
229                        Ok(Timestamp::new(seconds, nanoseconds).map_err(::serde::de::Error::custom)?)
230                    }
231                    (None, None, Some(seconds), None) => Ok(Timestamp::new(seconds, 0).map_err(::serde::de::Error::custom)?),
232                    (None, None, None, Some(nanoseconds)) => Ok(Timestamp::new(0, nanoseconds).map_err(::serde::de::Error::custom)?),
233                    (Some(_), None, _, _) => Err(::serde::de::Error::custom("ext data not found")),
234                    _ => Err(::serde::de::Error::custom("ext type field not found")),
235                }
236                // }
237            }
238        }
239
240        static FIELDS: [&str; 2] = [FIELD_SECONDS_NAME, FIELD_NANOSECONDS_NAME];
241        deserializer.deserialize_struct(TYPE_NAME, &FIELDS, TimestampVisitor(core::marker::PhantomData))
242    }
243}