Skip to main content

fory_core/serializer/
datetime.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18use crate::context::ReadContext;
19use crate::context::WriteContext;
20use crate::error::Error;
21use crate::resolver::TypeResolver;
22use crate::serializer::util::read_basic_type_info;
23use crate::serializer::ForyDefault;
24use crate::serializer::Serializer;
25use crate::type_id::TypeId;
26use crate::types::{Date, Duration, Timestamp};
27use std::mem;
28
29impl Serializer for Timestamp {
30    #[inline(always)]
31    fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> {
32        context.writer.write_i64(self.seconds());
33        context.writer.write_u32(self.subsec_nanos());
34        Ok(())
35    }
36
37    #[inline(always)]
38    fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
39        let seconds = context.reader.read_i64()?;
40        let nanos = context.reader.read_u32()?;
41        Timestamp::new(seconds, nanos)
42    }
43    #[inline]
44    fn fory_read_data_as_send_sync_any(
45        context: &mut ReadContext,
46    ) -> Result<Box<dyn std::any::Any + Send + Sync>, Error>
47    where
48        Self: Sized + ForyDefault,
49    {
50        Ok(crate::serializer::box_send_sync(Self::fory_read_data(
51            context,
52        )?))
53    }
54
55    #[inline(always)]
56    fn fory_reserved_space() -> usize {
57        mem::size_of::<i64>() + mem::size_of::<u32>()
58    }
59
60    #[inline(always)]
61    fn fory_get_type_id(_: &TypeResolver) -> Result<TypeId, Error> {
62        Ok(TypeId::TIMESTAMP)
63    }
64
65    #[inline(always)]
66    fn fory_type_id_dyn(&self, _: &TypeResolver) -> Result<TypeId, Error> {
67        Ok(TypeId::TIMESTAMP)
68    }
69
70    #[inline(always)]
71    fn fory_static_type_id() -> TypeId {
72        TypeId::TIMESTAMP
73    }
74
75    #[inline(always)]
76    fn as_any(&self) -> &dyn std::any::Any {
77        self
78    }
79
80    #[inline(always)]
81    fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
82        context.writer.write_u8(TypeId::TIMESTAMP as u8);
83        Ok(())
84    }
85
86    #[inline(always)]
87    fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
88        read_basic_type_info::<Self>(context)
89    }
90}
91
92impl ForyDefault for Timestamp {
93    #[inline(always)]
94    fn fory_default() -> Self {
95        Timestamp::default()
96    }
97}
98
99impl Serializer for Date {
100    #[inline(always)]
101    fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> {
102        let days = self.epoch_days();
103        if context.is_xlang() {
104            context.writer.write_var_i64(days);
105        } else {
106            let native_days = i32::try_from(days).map_err(|_| {
107                Error::invalid_data(format!("date day count {} exceeds native i32 range", days))
108            })?;
109            context.writer.write_i32(native_days);
110        }
111        Ok(())
112    }
113
114    #[inline(always)]
115    fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
116        let days = if context.is_xlang() {
117            context.reader.read_var_i64()?
118        } else {
119            i64::from(context.reader.read_i32()?)
120        };
121        Ok(Date::from_epoch_days(days))
122    }
123    #[inline]
124    fn fory_read_data_as_send_sync_any(
125        context: &mut ReadContext,
126    ) -> Result<Box<dyn std::any::Any + Send + Sync>, Error>
127    where
128        Self: Sized + ForyDefault,
129    {
130        Ok(crate::serializer::box_send_sync(Self::fory_read_data(
131            context,
132        )?))
133    }
134
135    #[inline(always)]
136    fn fory_reserved_space() -> usize {
137        9
138    }
139
140    #[inline(always)]
141    fn fory_get_type_id(_: &TypeResolver) -> Result<TypeId, Error> {
142        Ok(TypeId::DATE)
143    }
144
145    #[inline(always)]
146    fn fory_type_id_dyn(&self, _: &TypeResolver) -> Result<TypeId, Error> {
147        Ok(TypeId::DATE)
148    }
149
150    #[inline(always)]
151    fn fory_static_type_id() -> TypeId {
152        TypeId::DATE
153    }
154
155    #[inline(always)]
156    fn as_any(&self) -> &dyn std::any::Any {
157        self
158    }
159
160    #[inline(always)]
161    fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
162        context.writer.write_u8(TypeId::DATE as u8);
163        Ok(())
164    }
165
166    #[inline(always)]
167    fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
168        read_basic_type_info::<Self>(context)
169    }
170}
171
172impl ForyDefault for Date {
173    #[inline(always)]
174    fn fory_default() -> Self {
175        Date::default()
176    }
177}
178
179impl Serializer for Duration {
180    #[inline(always)]
181    fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> {
182        context.writer.write_var_i64(self.seconds());
183        context.writer.write_i32(self.subsec_nanos() as i32);
184        Ok(())
185    }
186
187    #[inline(always)]
188    fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
189        let seconds = context.reader.read_var_i64()?;
190        let nanos = context.reader.read_i32()?;
191        Duration::new(seconds, nanos)
192    }
193    #[inline]
194    fn fory_read_data_as_send_sync_any(
195        context: &mut ReadContext,
196    ) -> Result<Box<dyn std::any::Any + Send + Sync>, Error>
197    where
198        Self: Sized + ForyDefault,
199    {
200        Ok(crate::serializer::box_send_sync(Self::fory_read_data(
201            context,
202        )?))
203    }
204
205    #[inline(always)]
206    fn fory_reserved_space() -> usize {
207        9 + mem::size_of::<i32>()
208    }
209
210    #[inline(always)]
211    fn fory_get_type_id(_: &TypeResolver) -> Result<TypeId, Error> {
212        Ok(TypeId::DURATION)
213    }
214
215    #[inline(always)]
216    fn fory_type_id_dyn(&self, _: &TypeResolver) -> Result<TypeId, Error> {
217        Ok(TypeId::DURATION)
218    }
219
220    #[inline(always)]
221    fn fory_static_type_id() -> TypeId {
222        TypeId::DURATION
223    }
224
225    #[inline(always)]
226    fn as_any(&self) -> &dyn std::any::Any {
227        self
228    }
229
230    #[inline(always)]
231    fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
232        context.writer.write_u8(TypeId::DURATION as u8);
233        Ok(())
234    }
235
236    #[inline(always)]
237    fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
238        read_basic_type_info::<Self>(context)
239    }
240}
241
242impl ForyDefault for Duration {
243    #[inline(always)]
244    fn fory_default() -> Self {
245        Duration::default()
246    }
247}
248
249#[cfg(feature = "chrono")]
250mod chrono_support {
251    use super::*;
252    use chrono::{Duration as ChronoDuration, NaiveDate, NaiveDateTime};
253
254    impl Serializer for NaiveDateTime {
255        #[inline(always)]
256        fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> {
257            Timestamp::from(*self).fory_write_data(context)
258        }
259
260        #[inline(always)]
261        fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
262            Timestamp::fory_read_data(context)?.try_into()
263        }
264        #[inline]
265        fn fory_read_data_as_send_sync_any(
266            context: &mut ReadContext,
267        ) -> Result<Box<dyn std::any::Any + Send + Sync>, Error>
268        where
269            Self: Sized + ForyDefault,
270        {
271            Ok(crate::serializer::box_send_sync(Self::fory_read_data(
272                context,
273            )?))
274        }
275
276        #[inline(always)]
277        fn fory_reserved_space() -> usize {
278            Timestamp::fory_reserved_space()
279        }
280
281        #[inline(always)]
282        fn fory_get_type_id(_: &TypeResolver) -> Result<TypeId, Error> {
283            Ok(TypeId::TIMESTAMP)
284        }
285
286        #[inline(always)]
287        fn fory_type_id_dyn(&self, _: &TypeResolver) -> Result<TypeId, Error> {
288            Ok(TypeId::TIMESTAMP)
289        }
290
291        #[inline(always)]
292        fn fory_static_type_id() -> TypeId {
293            TypeId::TIMESTAMP
294        }
295
296        #[inline(always)]
297        fn as_any(&self) -> &dyn std::any::Any {
298            self
299        }
300
301        #[inline(always)]
302        fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
303            Timestamp::fory_write_type_info(context)
304        }
305
306        #[inline(always)]
307        fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
308            read_basic_type_info::<Self>(context)
309        }
310    }
311
312    impl ForyDefault for NaiveDateTime {
313        #[inline(always)]
314        fn fory_default() -> Self {
315            NaiveDateTime::default()
316        }
317    }
318
319    impl Serializer for NaiveDate {
320        #[inline(always)]
321        fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> {
322            Date::from(*self).fory_write_data(context)
323        }
324
325        #[inline(always)]
326        fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
327            Date::fory_read_data(context)?.try_into()
328        }
329        #[inline]
330        fn fory_read_data_as_send_sync_any(
331            context: &mut ReadContext,
332        ) -> Result<Box<dyn std::any::Any + Send + Sync>, Error>
333        where
334            Self: Sized + ForyDefault,
335        {
336            Ok(crate::serializer::box_send_sync(Self::fory_read_data(
337                context,
338            )?))
339        }
340
341        #[inline(always)]
342        fn fory_reserved_space() -> usize {
343            Date::fory_reserved_space()
344        }
345
346        #[inline(always)]
347        fn fory_get_type_id(_: &TypeResolver) -> Result<TypeId, Error> {
348            Ok(TypeId::DATE)
349        }
350
351        #[inline(always)]
352        fn fory_type_id_dyn(&self, _: &TypeResolver) -> Result<TypeId, Error> {
353            Ok(TypeId::DATE)
354        }
355
356        #[inline(always)]
357        fn fory_static_type_id() -> TypeId {
358            TypeId::DATE
359        }
360
361        #[inline(always)]
362        fn as_any(&self) -> &dyn std::any::Any {
363            self
364        }
365
366        #[inline(always)]
367        fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
368            Date::fory_write_type_info(context)
369        }
370
371        #[inline(always)]
372        fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
373            read_basic_type_info::<Self>(context)
374        }
375    }
376
377    impl ForyDefault for NaiveDate {
378        #[inline(always)]
379        fn fory_default() -> Self {
380            NaiveDate::default()
381        }
382    }
383
384    impl Serializer for ChronoDuration {
385        #[inline(always)]
386        fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> {
387            Duration::try_from(*self)?.fory_write_data(context)
388        }
389
390        #[inline(always)]
391        fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
392            Duration::fory_read_data(context)?.try_into()
393        }
394        #[inline]
395        fn fory_read_data_as_send_sync_any(
396            context: &mut ReadContext,
397        ) -> Result<Box<dyn std::any::Any + Send + Sync>, Error>
398        where
399            Self: Sized + ForyDefault,
400        {
401            Ok(crate::serializer::box_send_sync(Self::fory_read_data(
402                context,
403            )?))
404        }
405
406        #[inline(always)]
407        fn fory_reserved_space() -> usize {
408            Duration::fory_reserved_space()
409        }
410
411        #[inline(always)]
412        fn fory_get_type_id(_: &TypeResolver) -> Result<TypeId, Error> {
413            Ok(TypeId::DURATION)
414        }
415
416        #[inline(always)]
417        fn fory_type_id_dyn(&self, _: &TypeResolver) -> Result<TypeId, Error> {
418            Ok(TypeId::DURATION)
419        }
420
421        #[inline(always)]
422        fn fory_static_type_id() -> TypeId {
423            TypeId::DURATION
424        }
425
426        #[inline(always)]
427        fn as_any(&self) -> &dyn std::any::Any {
428            self
429        }
430
431        #[inline(always)]
432        fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
433            Duration::fory_write_type_info(context)
434        }
435
436        #[inline(always)]
437        fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
438            read_basic_type_info::<Self>(context)
439        }
440    }
441
442    impl ForyDefault for ChronoDuration {
443        #[inline(always)]
444        fn fory_default() -> Self {
445            ChronoDuration::zero()
446        }
447    }
448}
449
450#[cfg(test)]
451mod tests {
452    use super::*;
453    use crate::fory::Fory;
454
455    #[test]
456    fn test_temporal_carrier_serialization() {
457        let fory = Fory::builder().xlang(false).compatible(false).build();
458
459        let timestamps = [
460            Timestamp::UNIX_EPOCH,
461            Timestamp::new(1, 0).unwrap(),
462            Timestamp::new(-1, 999_999_999).unwrap(),
463        ];
464        for timestamp in timestamps {
465            let bytes = fory.serialize(&timestamp).unwrap();
466            let deserialized: Timestamp = fory.deserialize(&bytes).unwrap();
467            assert_eq!(timestamp, deserialized);
468        }
469
470        let dates = [
471            Date::UNIX_EPOCH,
472            Date::from_epoch_days(-1),
473            Date::from_epoch_days(18_628),
474        ];
475        for date in dates {
476            let bytes = fory.serialize(&date).unwrap();
477            let deserialized: Date = fory.deserialize(&bytes).unwrap();
478            assert_eq!(date, deserialized);
479        }
480
481        let durations = [
482            Duration::ZERO,
483            Duration::new(1, 0).unwrap(),
484            Duration::new(0, -1).unwrap(),
485            Duration::new(-123, 456_789).unwrap(),
486        ];
487        for duration in durations {
488            let bytes = fory.serialize(&duration).unwrap();
489            let deserialized: Duration = fory.deserialize(&bytes).unwrap();
490            assert_eq!(duration, deserialized);
491        }
492    }
493
494    #[test]
495    fn test_duration_normalizes_negative_nanoseconds() {
496        assert_eq!(
497            Duration::new(0, -1).unwrap(),
498            Duration::from_normalized(-1, 999_999_999).unwrap()
499        );
500    }
501
502    #[cfg(feature = "chrono")]
503    #[test]
504    fn test_chrono_temporal_feature_serialization() {
505        use chrono::{DateTime, Duration as ChronoDuration, NaiveDate, NaiveDateTime};
506
507        let fory = Fory::builder().xlang(false).compatible(false).build();
508        let date = NaiveDate::from_ymd_opt(2024, 2, 3).unwrap();
509        let timestamp = DateTime::from_timestamp(100, 1).unwrap().naive_utc();
510        let duration = ChronoDuration::nanoseconds(-1);
511
512        let bytes = fory.serialize(&date).unwrap();
513        let deserialized: NaiveDate = fory.deserialize(&bytes).unwrap();
514        assert_eq!(date, deserialized);
515
516        let bytes = fory.serialize(&timestamp).unwrap();
517        let deserialized: NaiveDateTime = fory.deserialize(&bytes).unwrap();
518        assert_eq!(timestamp, deserialized);
519
520        let bytes = fory.serialize(&duration).unwrap();
521        let deserialized: ChronoDuration = fory.deserialize(&bytes).unwrap();
522        assert_eq!(duration, deserialized);
523    }
524}