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