diff --git a/src/encoding.rs b/src/encoding.rs index f796a3a..0a90789 100644 --- a/src/encoding.rs +++ b/src/encoding.rs @@ -70,7 +70,7 @@ mod try_from_u8 { } #[derive(Deserialize, Serialize, Debug, Clone)] -pub struct Trade { +pub struct Serde32BytesTrade { pub time: u64, #[serde(with = "try_from_u8")] pub exch: Exchange, @@ -183,6 +183,11 @@ impl<'a> PackedTradeData<'a> { lexical::parse(&self.0[Self::AMOUNT_OFFSET..(Self::AMOUNT_OFFSET + 8)]) } + /// `server_time` is stored in milliseconds, while `time` is nanoseconds. + /// this is what you need to multiply the stored `server_time` data by to + /// get it back to nanoseconds. + const SERVER_TIME_DOWNSCALE_FACTOR: u64 = 1_000_000; + #[inline] pub fn server_time(&self) -> Result, ParseError> { let st: i32 = @@ -192,12 +197,21 @@ impl<'a> PackedTradeData<'a> { std::str::from_utf8(&self.0[Self::SERVER_TIME_OFFSET..(Self::SERVER_TIME_OFFSET + 4)]).unwrap_or("uft8 error") ))) })?; + + // while the `server_time` delta is stored as a signed integer, to be able to express a + // delta in both directions relative to `time`, we can't just add a negative `i64` to a + // `u64`, it doesn't work like that. this match either subtracts the absolute value of a + // negative delta, or adds a positive delta, to get around this conundrum. + // + // `SERVER_TIME_DOWNSCALE_FACTOR` is used to rescale the delta to nanoseconds prior to its + // being applied to `time`. + match st { 0 => Ok(None), - x @ std::i32::MIN .. 0 => Ok(Some(self.time()? - x.abs() as u64)), + x @ std::i32::MIN .. 0 => Ok(Some(self.time()? - (x.abs() as u64 * Self::SERVER_TIME_DOWNSCALE_FACTOR))), - x @ 1 ..= std::i32::MAX => Ok(Some(self.time()? + x as u64)), + x @ 1 ..= std::i32::MAX => Ok(Some(self.time()? + (x as u64 * Self::SERVER_TIME_DOWNSCALE_FACTOR))), } } } @@ -216,37 +230,17 @@ mod tests { #[test] fn check_bincode_serialized_size() { - let trade = Trade { + let trade = Serde32BytesTrade { time: 1586996977191449698, exch: e!(bmex), ticker: t!(btc-usd), price: 1.234, amount: 4.567, side: None, - //server_time: NonZeroU64::new(1586996977191449698 + 1_000_000), server_time: NonZeroI32::new(1_000_000), - //server_time: Some(1586996977191449698 + 1_000_000), }; - /* - let packed = PackedTrade { - time: trade.time, - exch: u8::from(trade.exch), - base: u8::from(trade.ticker.base), - quote: u8::from(trade.ticker.quote), - amount: trade.amount, - price: trade.price, - //side: trade.side.and_then(|s| NonZeroU8::new(u8::from(s))), - //server_time: NonZeroI32::new(1_000_000), - side: trade.side.map(|s| u8::from(s)).unwrap_or(0), - server_time: 1_000_000, - - }; - */ - - assert_eq!(size_of::(), 32); - - //assert_eq!(serde_json::to_string(&trade).unwrap().len(), 32); + assert_eq!(size_of::(), 32); assert_eq!(bincode::serialized_size(&trade).unwrap(), 32); }