fory_core/serializer/
datetime.rs1use crate::context::{ReadContext, WriteContext};
19use crate::error::Error;
20use crate::serializer::util::read_basic_type_info;
21use crate::serializer::Serializer;
22use crate::type_id::TypeId;
23use crate::types::{Date, Duration, Timestamp};
24use std::sync::Arc;
25
26macro_rules! temporal_hooks {
27 ($ty:ty, $type_id:expr, $reserved:expr, $default:expr) => {
28 #[inline(always)]
29 fn default_value(_: &mut ReadContext) -> Result<Self, Error> {
30 Ok($default)
31 }
32
33 #[inline(always)]
34 fn read_arc_any(
35 context: &mut ReadContext,
36 ) -> Result<Arc<dyn std::any::Any + Send + Sync>, Error> {
37 Ok(Arc::new(Self::read_data(context)?))
38 }
39
40 #[inline(always)]
41 fn reserved_space() -> usize {
42 $reserved
43 }
44
45 #[inline(always)]
46 fn static_type_id() -> TypeId {
47 $type_id
48 }
49
50 #[inline(always)]
51 fn write_type_info(context: &mut WriteContext) -> Result<(), Error> {
52 context.writer.write_u8($type_id as u8);
53 Ok(())
54 }
55
56 #[inline(always)]
57 fn read_type_info(context: &mut ReadContext) -> Result<(), Error> {
58 read_basic_type_info::<$ty>(context)
59 }
60 };
61}
62
63impl Serializer for Timestamp {
64 type Target = Self;
65
66 #[inline(always)]
67 fn write_data(value: &Self, context: &mut WriteContext) -> Result<(), Error> {
68 context.writer.write_i64(value.seconds());
69 context.writer.write_u32(value.subsec_nanos());
70 Ok(())
71 }
72
73 #[inline(always)]
74 fn read_data(context: &mut ReadContext) -> Result<Self, Error> {
75 Timestamp::new(context.reader.read_i64()?, context.reader.read_u32()?)
76 }
77
78 temporal_hooks!(
79 Timestamp,
80 TypeId::TIMESTAMP,
81 std::mem::size_of::<i64>() + std::mem::size_of::<u32>(),
82 Timestamp::default()
83 );
84}
85
86impl Serializer for Date {
87 type Target = Self;
88
89 #[inline(always)]
90 fn write_data(value: &Self, context: &mut WriteContext) -> Result<(), Error> {
91 let days = value.epoch_days();
92 if context.is_xlang() {
93 context.writer.write_var_i64(days);
94 } else {
95 let native_days = i32::try_from(days).map_err(|_| {
96 Error::invalid_data(format!("date day count {} exceeds native i32 range", days))
97 })?;
98 context.writer.write_i32(native_days);
99 }
100 Ok(())
101 }
102
103 #[inline(always)]
104 fn read_data(context: &mut ReadContext) -> Result<Self, Error> {
105 let days = if context.is_xlang() {
106 context.reader.read_var_i64()?
107 } else {
108 i64::from(context.reader.read_i32()?)
109 };
110 Ok(Date::from_epoch_days(days))
111 }
112
113 temporal_hooks!(Date, TypeId::DATE, 9, Date::default());
114}
115
116impl Serializer for Duration {
117 type Target = Self;
118
119 #[inline(always)]
120 fn write_data(value: &Self, context: &mut WriteContext) -> Result<(), Error> {
121 context.writer.write_var_i64(value.seconds());
122 context.writer.write_i32(value.subsec_nanos() as i32);
123 Ok(())
124 }
125
126 #[inline(always)]
127 fn read_data(context: &mut ReadContext) -> Result<Self, Error> {
128 Duration::new(context.reader.read_var_i64()?, context.reader.read_i32()?)
129 }
130
131 temporal_hooks!(
132 Duration,
133 TypeId::DURATION,
134 9 + std::mem::size_of::<i32>(),
135 Duration::default()
136 );
137}
138
139#[cfg(feature = "chrono")]
140mod chrono_support {
141 use super::*;
142 use chrono::{Duration as ChronoDuration, NaiveDate, NaiveDateTime};
143
144 impl Serializer for NaiveDateTime {
145 type Target = Self;
146
147 #[inline(always)]
148 fn write_data(value: &Self, context: &mut WriteContext) -> Result<(), Error> {
149 Timestamp::write_data(&Timestamp::from(*value), context)
150 }
151
152 #[inline(always)]
153 fn read_data(context: &mut ReadContext) -> Result<Self, Error> {
154 Timestamp::read_data(context)?.try_into()
155 }
156
157 temporal_hooks!(
158 NaiveDateTime,
159 TypeId::TIMESTAMP,
160 Timestamp::reserved_space(),
161 NaiveDateTime::default()
162 );
163 }
164
165 impl Serializer for NaiveDate {
166 type Target = Self;
167
168 #[inline(always)]
169 fn write_data(value: &Self, context: &mut WriteContext) -> Result<(), Error> {
170 Date::write_data(&Date::from(*value), context)
171 }
172
173 #[inline(always)]
174 fn read_data(context: &mut ReadContext) -> Result<Self, Error> {
175 Date::read_data(context)?.try_into()
176 }
177
178 temporal_hooks!(
179 NaiveDate,
180 TypeId::DATE,
181 Date::reserved_space(),
182 NaiveDate::default()
183 );
184 }
185
186 impl Serializer for ChronoDuration {
187 type Target = Self;
188
189 #[inline(always)]
190 fn write_data(value: &Self, context: &mut WriteContext) -> Result<(), Error> {
191 Duration::write_data(&Duration::try_from(*value)?, context)
192 }
193
194 #[inline(always)]
195 fn read_data(context: &mut ReadContext) -> Result<Self, Error> {
196 Duration::read_data(context)?.try_into()
197 }
198
199 temporal_hooks!(
200 ChronoDuration,
201 TypeId::DURATION,
202 Duration::reserved_space(),
203 ChronoDuration::zero()
204 );
205 }
206}
207
208#[cfg(test)]
209mod tests {
210 use super::*;
211 use crate::fory::Fory;
212
213 #[test]
214 fn test_temporal_carrier_serialization() {
215 let fory = Fory::builder().xlang(false).compatible(false).build();
216
217 let timestamps = [
218 Timestamp::UNIX_EPOCH,
219 Timestamp::new(1, 0).unwrap(),
220 Timestamp::new(-1, 999_999_999).unwrap(),
221 ];
222 for timestamp in timestamps {
223 let bytes = fory.serialize(×tamp).unwrap();
224 let deserialized: Timestamp = fory.deserialize(&bytes).unwrap();
225 assert_eq!(timestamp, deserialized);
226 }
227
228 let dates = [
229 Date::UNIX_EPOCH,
230 Date::from_epoch_days(-1),
231 Date::from_epoch_days(18_628),
232 ];
233 for date in dates {
234 let bytes = fory.serialize(&date).unwrap();
235 let deserialized: Date = fory.deserialize(&bytes).unwrap();
236 assert_eq!(date, deserialized);
237 }
238
239 let durations = [
240 Duration::ZERO,
241 Duration::new(1, 0).unwrap(),
242 Duration::new(0, -1).unwrap(),
243 Duration::new(-123, 456_789).unwrap(),
244 ];
245 for duration in durations {
246 let bytes = fory.serialize(&duration).unwrap();
247 let deserialized: Duration = fory.deserialize(&bytes).unwrap();
248 assert_eq!(duration, deserialized);
249 }
250 }
251
252 #[test]
253 fn duration_negative_nanoseconds() {
254 assert_eq!(
255 Duration::new(0, -1).unwrap(),
256 Duration::from_normalized(-1, 999_999_999).unwrap()
257 );
258 }
259
260 #[cfg(feature = "chrono")]
261 #[test]
262 fn chrono_temporal_serialization() {
263 use chrono::{DateTime, Duration as ChronoDuration, NaiveDate, NaiveDateTime};
264
265 let fory = Fory::builder().xlang(false).compatible(false).build();
266 let date = NaiveDate::from_ymd_opt(2024, 2, 3).unwrap();
267 let timestamp = DateTime::from_timestamp(100, 1).unwrap().naive_utc();
268 let duration = ChronoDuration::nanoseconds(-1);
269
270 let bytes = fory.serialize(&date).unwrap();
271 let deserialized: NaiveDate = fory.deserialize(&bytes).unwrap();
272 assert_eq!(date, deserialized);
273
274 let bytes = fory.serialize(×tamp).unwrap();
275 let deserialized: NaiveDateTime = fory.deserialize(&bytes).unwrap();
276 assert_eq!(timestamp, deserialized);
277
278 let bytes = fory.serialize(&duration).unwrap();
279 let deserialized: ChronoDuration = fory.deserialize(&bytes).unwrap();
280 assert_eq!(duration, deserialized);
281 }
282}