fory_core/serializer/
datetime.rs1use crate::error::Error;
19use crate::resolver::context::ReadContext;
20use crate::resolver::context::WriteContext;
21use crate::resolver::type_resolver::TypeResolver;
22use crate::serializer::util::read_basic_type_info;
23use crate::serializer::ForyDefault;
24use crate::serializer::Serializer;
25use crate::types::TypeId;
26use crate::util::EPOCH;
27use chrono::{Duration as ChronoDuration, NaiveDate, NaiveDateTime};
28use std::mem;
29use std::time::Duration;
30
31impl Serializer for NaiveDateTime {
32 #[inline(always)]
33 fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> {
34 let dt = self.and_utc();
35 let seconds = dt.timestamp();
36 let nanos = dt.timestamp_subsec_nanos();
37 context.writer.write_i64(seconds);
38 context.writer.write_u32(nanos);
39 Ok(())
40 }
41
42 #[inline(always)]
43 fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
44 let seconds = context.reader.read_i64()?;
45 let nanos = context.reader.read_u32()?;
46 #[allow(deprecated)]
47 let result = NaiveDateTime::from_timestamp(seconds, nanos);
48 Ok(result)
49 }
50
51 #[inline(always)]
52 fn fory_reserved_space() -> usize {
53 mem::size_of::<i64>() + mem::size_of::<u32>()
54 }
55
56 #[inline(always)]
57 fn fory_get_type_id(_: &TypeResolver) -> Result<TypeId, Error> {
58 Ok(TypeId::TIMESTAMP)
59 }
60
61 #[inline(always)]
62 fn fory_type_id_dyn(&self, _: &TypeResolver) -> Result<TypeId, Error> {
63 Ok(TypeId::TIMESTAMP)
64 }
65
66 #[inline(always)]
67 fn fory_static_type_id() -> TypeId {
68 TypeId::TIMESTAMP
69 }
70
71 #[inline(always)]
72 fn as_any(&self) -> &dyn std::any::Any {
73 self
74 }
75
76 #[inline(always)]
77 fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
78 context.writer.write_u8(TypeId::TIMESTAMP as u8);
79 Ok(())
80 }
81
82 #[inline(always)]
83 fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
84 read_basic_type_info::<Self>(context)
85 }
86}
87
88impl Serializer for NaiveDate {
89 #[inline(always)]
90 fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> {
91 let days_since_epoch = self.signed_duration_since(EPOCH).num_days();
92 context.writer.write_i32(days_since_epoch as i32);
93 Ok(())
94 }
95
96 #[inline(always)]
97 fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
98 let days = context.reader.read_i32()?;
99 use chrono::TimeDelta;
100 let duration = TimeDelta::days(days as i64);
101 let result = EPOCH + duration;
102 Ok(result)
103 }
104
105 #[inline(always)]
106 fn fory_reserved_space() -> usize {
107 mem::size_of::<i32>()
108 }
109
110 #[inline(always)]
111 fn fory_get_type_id(_: &TypeResolver) -> Result<TypeId, Error> {
112 Ok(TypeId::DATE)
113 }
114
115 #[inline(always)]
116 fn fory_type_id_dyn(&self, _: &TypeResolver) -> Result<TypeId, Error> {
117 Ok(TypeId::DATE)
118 }
119
120 #[inline(always)]
121 fn fory_static_type_id() -> TypeId {
122 TypeId::DATE
123 }
124
125 #[inline(always)]
126 fn as_any(&self) -> &dyn std::any::Any {
127 self
128 }
129
130 #[inline(always)]
131 fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
132 context.writer.write_u8(TypeId::DATE as u8);
133 Ok(())
134 }
135
136 #[inline(always)]
137 fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
138 read_basic_type_info::<Self>(context)
139 }
140}
141
142impl ForyDefault for NaiveDateTime {
143 #[inline(always)]
144 fn fory_default() -> Self {
145 NaiveDateTime::default()
146 }
147}
148
149impl ForyDefault for NaiveDate {
150 #[inline(always)]
151 fn fory_default() -> Self {
152 NaiveDate::default()
153 }
154}
155
156impl Serializer for Duration {
157 #[inline(always)]
158 fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> {
159 let raw = self.as_secs();
160 if raw > i64::MAX as u64 {
161 return Err(Error::invalid_data(format!(
162 "std::time::Duration seconds {} exceeds i64::MAX and cannot be encoded as varint64",
163 raw
164 )));
165 }
166 let secs = raw as i64;
167 let nanos = self.subsec_nanos() as i32;
168 context.writer.write_varint64(secs);
169 context.writer.write_i32(nanos);
170 Ok(())
171 }
172
173 #[inline(always)]
174 fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
175 let secs = context.reader.read_varint64()?;
176 if secs < 0 {
177 return Err(Error::invalid_data(format!(
178 "negative duration seconds {} cannot be represented as std::time::Duration; use chrono::Duration instead",
179 secs
180 )));
181 }
182 let nanos = context.reader.read_i32()?;
183 if !(0..=999_999_999).contains(&nanos) {
184 return Err(Error::invalid_data(format!(
188 "duration nanoseconds {} out of valid range [0, 999_999_999] for std::time::Duration",
189 nanos
190 )));
191 }
192 Ok(Duration::new(secs as u64, nanos as u32))
193 }
194
195 #[inline(always)]
196 fn fory_reserved_space() -> usize {
197 9 + mem::size_of::<i32>() }
199
200 #[inline(always)]
201 fn fory_get_type_id(_: &TypeResolver) -> Result<TypeId, Error> {
202 Ok(TypeId::DURATION)
203 }
204
205 #[inline(always)]
206 fn fory_type_id_dyn(&self, _: &TypeResolver) -> Result<TypeId, Error> {
207 Ok(TypeId::DURATION)
208 }
209
210 #[inline(always)]
211 fn fory_static_type_id() -> TypeId {
212 TypeId::DURATION
213 }
214
215 #[inline(always)]
216 fn as_any(&self) -> &dyn std::any::Any {
217 self
218 }
219
220 #[inline(always)]
221 fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
222 context.writer.write_u8(TypeId::DURATION as u8);
223 Ok(())
224 }
225
226 #[inline(always)]
227 fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
228 read_basic_type_info::<Self>(context)
229 }
230}
231
232impl ForyDefault for Duration {
233 #[inline(always)]
234 fn fory_default() -> Self {
235 Duration::ZERO
236 }
237}
238
239impl Serializer for ChronoDuration {
240 #[inline(always)]
241 fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> {
242 let secs = self.num_seconds();
243 let nanos = self.subsec_nanos();
244 context.writer.write_varint64(secs);
245 context.writer.write_i32(nanos);
246 Ok(())
247 }
248
249 #[inline(always)]
250 fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
251 let secs = context.reader.read_varint64()?;
252 let nanos = context.reader.read_i32()?;
253 if !(-999_999_999..=999_999_999).contains(&nanos) {
254 return Err(Error::invalid_data(format!(
256 "duration nanoseconds {} out of valid range [-999_999_999, 999_999_999]",
257 nanos
258 )));
259 }
260 ChronoDuration::try_seconds(secs) .and_then(|d| d.checked_add(&ChronoDuration::nanoseconds(nanos as i64)))
262 .ok_or_else(|| {
263 Error::invalid_data(format!(
264 "duration seconds {} out of chrono::Duration valid range",
265 secs
266 ))
267 })
268 }
269
270 #[inline(always)]
271 fn fory_reserved_space() -> usize {
272 9 + mem::size_of::<i32>() }
274
275 #[inline(always)]
276 fn fory_get_type_id(_: &TypeResolver) -> Result<TypeId, Error> {
277 Ok(TypeId::DURATION)
278 }
279
280 #[inline(always)]
281 fn fory_type_id_dyn(&self, _: &TypeResolver) -> Result<TypeId, Error> {
282 Ok(TypeId::DURATION)
283 }
284
285 #[inline(always)]
286 fn fory_static_type_id() -> TypeId {
287 TypeId::DURATION
288 }
289
290 #[inline(always)]
291 fn as_any(&self) -> &dyn std::any::Any {
292 self
293 }
294
295 #[inline(always)]
296 fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
297 context.writer.write_u8(TypeId::DURATION as u8);
298 Ok(())
299 }
300
301 #[inline(always)]
302 fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
303 read_basic_type_info::<Self>(context)
304 }
305}
306
307impl ForyDefault for ChronoDuration {
308 #[inline(always)]
309 fn fory_default() -> Self {
310 ChronoDuration::zero()
311 }
312}
313
314#[cfg(test)]
315mod tests {
316 use super::*;
317 use crate::fory::Fory;
318
319 #[test]
320 fn test_std_duration_serialization() {
321 let fory = Fory::default();
322
323 let test_cases = vec![
325 Duration::ZERO,
326 Duration::new(0, 0),
327 Duration::new(1, 0),
328 Duration::new(0, 1),
329 Duration::new(123, 456789),
330 Duration::new(i64::MAX as u64, 999_999_999),
331 ];
332
333 for duration in test_cases {
334 let bytes = fory.serialize(&duration).unwrap();
335 let deserialized: Duration = fory.deserialize(&bytes).unwrap();
336 assert_eq!(
337 duration, deserialized,
338 "Failed for duration: {:?}",
339 duration
340 );
341 }
342 }
343
344 #[test]
345 fn test_chrono_duration_serialization() {
346 let fory = Fory::default();
347
348 let test_cases = vec![
350 ChronoDuration::zero(),
351 ChronoDuration::new(0, 0).unwrap(),
352 ChronoDuration::new(1, 0).unwrap(),
353 ChronoDuration::new(0, 1).unwrap(),
354 ChronoDuration::new(123, 456789).unwrap(),
355 ChronoDuration::seconds(-1),
356 ChronoDuration::nanoseconds(-1),
357 ChronoDuration::microseconds(-456789),
358 ChronoDuration::MAX,
359 ChronoDuration::MIN,
360 ];
361
362 for duration in test_cases {
363 let bytes = fory.serialize(&duration).unwrap();
364 let deserialized: ChronoDuration = fory.deserialize(&bytes).unwrap();
365 assert_eq!(
366 duration, deserialized,
367 "Failed for duration: {:?}",
368 duration
369 );
370 }
371 }
372
373 #[test]
374 fn test_chrono_duration_out_of_range_is_error() {
375 let fory = Fory::default();
376 let too_large = Duration::new(i64::MAX as u64, 0);
377 let bytes = fory.serialize(&too_large).unwrap();
378 let result: Result<ChronoDuration, _> = fory.deserialize(&bytes);
379 assert!(
380 result.is_err(),
381 "out-of-range seconds should not be deserialized into chrono::Duration!"
382 );
383 }
384
385 #[test]
386 fn test_negative_std_duration_read_is_error() {
387 let fory = Fory::default();
388 let negative_duration = ChronoDuration::seconds(-1);
389 let bytes = fory.serialize(&negative_duration).unwrap();
390 let result: Result<Duration, _> = fory.deserialize(&bytes);
391 assert!(
392 result.is_err(),
393 "negative duration should not be deserialized into std::time::Duration!"
394 );
395 }
396}