use crate::error::Error;
use crate::resolver::context::ReadContext;
use crate::resolver::context::WriteContext;
use crate::resolver::type_resolver::TypeResolver;
use crate::serializer::util::read_basic_type_info;
use crate::serializer::ForyDefault;
use crate::serializer::Serializer;
use crate::types::TypeId;
use crate::util::EPOCH;
use chrono::{Duration as ChronoDuration, NaiveDate, NaiveDateTime};
use std::mem;
use std::time::Duration;
impl Serializer for NaiveDateTime {
#[inline(always)]
fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> {
let dt = self.and_utc();
let seconds = dt.timestamp();
let nanos = dt.timestamp_subsec_nanos();
context.writer.write_i64(seconds);
context.writer.write_u32(nanos);
Ok(())
}
#[inline(always)]
fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
let seconds = context.reader.read_i64()?;
let nanos = context.reader.read_u32()?;
#[allow(deprecated)]
let result = NaiveDateTime::from_timestamp(seconds, nanos);
Ok(result)
}
#[inline(always)]
fn fory_reserved_space() -> usize {
mem::size_of::<i64>() + mem::size_of::<u32>()
}
#[inline(always)]
fn fory_get_type_id(_: &TypeResolver) -> Result<TypeId, Error> {
Ok(TypeId::TIMESTAMP)
}
#[inline(always)]
fn fory_type_id_dyn(&self, _: &TypeResolver) -> Result<TypeId, Error> {
Ok(TypeId::TIMESTAMP)
}
#[inline(always)]
fn fory_static_type_id() -> TypeId {
TypeId::TIMESTAMP
}
#[inline(always)]
fn as_any(&self) -> &dyn std::any::Any {
self
}
#[inline(always)]
fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
context.writer.write_u8(TypeId::TIMESTAMP as u8);
Ok(())
}
#[inline(always)]
fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
read_basic_type_info::<Self>(context)
}
}
impl Serializer for NaiveDate {
#[inline(always)]
fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> {
let days_since_epoch = self.signed_duration_since(EPOCH).num_days();
context.writer.write_i32(days_since_epoch as i32);
Ok(())
}
#[inline(always)]
fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
let days = context.reader.read_i32()?;
use chrono::TimeDelta;
let duration = TimeDelta::days(days as i64);
let result = EPOCH + duration;
Ok(result)
}
#[inline(always)]
fn fory_reserved_space() -> usize {
mem::size_of::<i32>()
}
#[inline(always)]
fn fory_get_type_id(_: &TypeResolver) -> Result<TypeId, Error> {
Ok(TypeId::DATE)
}
#[inline(always)]
fn fory_type_id_dyn(&self, _: &TypeResolver) -> Result<TypeId, Error> {
Ok(TypeId::DATE)
}
#[inline(always)]
fn fory_static_type_id() -> TypeId {
TypeId::DATE
}
#[inline(always)]
fn as_any(&self) -> &dyn std::any::Any {
self
}
#[inline(always)]
fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
context.writer.write_u8(TypeId::DATE as u8);
Ok(())
}
#[inline(always)]
fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
read_basic_type_info::<Self>(context)
}
}
impl ForyDefault for NaiveDateTime {
#[inline(always)]
fn fory_default() -> Self {
NaiveDateTime::default()
}
}
impl ForyDefault for NaiveDate {
#[inline(always)]
fn fory_default() -> Self {
NaiveDate::default()
}
}
impl Serializer for Duration {
#[inline(always)]
fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> {
let raw = self.as_secs();
if raw > i64::MAX as u64 {
return Err(Error::invalid_data(format!(
"std::time::Duration seconds {} exceeds i64::MAX and cannot be encoded as varint64",
raw
)));
}
let secs = raw as i64;
let nanos = self.subsec_nanos() as i32;
context.writer.write_varint64(secs);
context.writer.write_i32(nanos);
Ok(())
}
#[inline(always)]
fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
let secs = context.reader.read_varint64()?;
if secs < 0 {
return Err(Error::invalid_data(format!(
"negative duration seconds {} cannot be represented as std::time::Duration; use chrono::Duration instead",
secs
)));
}
let nanos = context.reader.read_i32()?;
if !(0..=999_999_999).contains(&nanos) {
return Err(Error::invalid_data(format!(
"duration nanoseconds {} out of valid range [0, 999_999_999] for std::time::Duration",
nanos
)));
}
Ok(Duration::new(secs as u64, nanos as u32))
}
#[inline(always)]
fn fory_reserved_space() -> usize {
9 + mem::size_of::<i32>() }
#[inline(always)]
fn fory_get_type_id(_: &TypeResolver) -> Result<TypeId, Error> {
Ok(TypeId::DURATION)
}
#[inline(always)]
fn fory_type_id_dyn(&self, _: &TypeResolver) -> Result<TypeId, Error> {
Ok(TypeId::DURATION)
}
#[inline(always)]
fn fory_static_type_id() -> TypeId {
TypeId::DURATION
}
#[inline(always)]
fn as_any(&self) -> &dyn std::any::Any {
self
}
#[inline(always)]
fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
context.writer.write_u8(TypeId::DURATION as u8);
Ok(())
}
#[inline(always)]
fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
read_basic_type_info::<Self>(context)
}
}
impl ForyDefault for Duration {
#[inline(always)]
fn fory_default() -> Self {
Duration::ZERO
}
}
impl Serializer for ChronoDuration {
#[inline(always)]
fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> {
let secs = self.num_seconds();
let nanos = self.subsec_nanos();
context.writer.write_varint64(secs);
context.writer.write_i32(nanos);
Ok(())
}
#[inline(always)]
fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
let secs = context.reader.read_varint64()?;
let nanos = context.reader.read_i32()?;
if !(-999_999_999..=999_999_999).contains(&nanos) {
return Err(Error::invalid_data(format!(
"duration nanoseconds {} out of valid range [-999_999_999, 999_999_999]",
nanos
)));
}
ChronoDuration::try_seconds(secs) .and_then(|d| d.checked_add(&ChronoDuration::nanoseconds(nanos as i64)))
.ok_or_else(|| {
Error::invalid_data(format!(
"duration seconds {} out of chrono::Duration valid range",
secs
))
})
}
#[inline(always)]
fn fory_reserved_space() -> usize {
9 + mem::size_of::<i32>() }
#[inline(always)]
fn fory_get_type_id(_: &TypeResolver) -> Result<TypeId, Error> {
Ok(TypeId::DURATION)
}
#[inline(always)]
fn fory_type_id_dyn(&self, _: &TypeResolver) -> Result<TypeId, Error> {
Ok(TypeId::DURATION)
}
#[inline(always)]
fn fory_static_type_id() -> TypeId {
TypeId::DURATION
}
#[inline(always)]
fn as_any(&self) -> &dyn std::any::Any {
self
}
#[inline(always)]
fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
context.writer.write_u8(TypeId::DURATION as u8);
Ok(())
}
#[inline(always)]
fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
read_basic_type_info::<Self>(context)
}
}
impl ForyDefault for ChronoDuration {
#[inline(always)]
fn fory_default() -> Self {
ChronoDuration::zero()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::fory::Fory;
#[test]
fn test_std_duration_serialization() {
let fory = Fory::default();
let test_cases = vec![
Duration::ZERO,
Duration::new(0, 0),
Duration::new(1, 0),
Duration::new(0, 1),
Duration::new(123, 456789),
Duration::new(i64::MAX as u64, 999_999_999),
];
for duration in test_cases {
let bytes = fory.serialize(&duration).unwrap();
let deserialized: Duration = fory.deserialize(&bytes).unwrap();
assert_eq!(
duration, deserialized,
"Failed for duration: {:?}",
duration
);
}
}
#[test]
fn test_chrono_duration_serialization() {
let fory = Fory::default();
let test_cases = vec![
ChronoDuration::zero(),
ChronoDuration::new(0, 0).unwrap(),
ChronoDuration::new(1, 0).unwrap(),
ChronoDuration::new(0, 1).unwrap(),
ChronoDuration::new(123, 456789).unwrap(),
ChronoDuration::seconds(-1),
ChronoDuration::nanoseconds(-1),
ChronoDuration::microseconds(-456789),
ChronoDuration::MAX,
ChronoDuration::MIN,
];
for duration in test_cases {
let bytes = fory.serialize(&duration).unwrap();
let deserialized: ChronoDuration = fory.deserialize(&bytes).unwrap();
assert_eq!(
duration, deserialized,
"Failed for duration: {:?}",
duration
);
}
}
#[test]
fn test_chrono_duration_out_of_range_is_error() {
let fory = Fory::default();
let too_large = Duration::new(i64::MAX as u64, 0);
let bytes = fory.serialize(&too_large).unwrap();
let result: Result<ChronoDuration, _> = fory.deserialize(&bytes);
assert!(
result.is_err(),
"out-of-range seconds should not be deserialized into chrono::Duration!"
);
}
#[test]
fn test_negative_std_duration_read_is_error() {
let fory = Fory::default();
let negative_duration = ChronoDuration::seconds(-1);
let bytes = fory.serialize(&negative_duration).unwrap();
let result: Result<Duration, _> = fory.deserialize(&bytes);
assert!(
result.is_err(),
"negative duration should not be deserialized into std::time::Duration!"
);
}
}