blob: 97cf78b20e6582a7d756e12c35aeceee430fc380 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
use crate::error::Error;
use crate::resolver::context::{ReadContext, WriteContext};
use crate::resolver::type_resolver::TypeResolver;
use crate::serializer::collection::{read_collection_type_info, write_collection_type_info};
use crate::serializer::skip::skip_any_value;
use crate::serializer::{ForyDefault, Serializer};
use crate::types::{RefMode, TypeId};
use std::mem;
// Unit type () implementation - represents an empty/unit value with no data
impl Serializer for () {
#[inline(always)]
fn fory_write_data(&self, _context: &mut WriteContext) -> Result<(), Error> {
// Unit type has no data to write
Ok(())
}
#[inline(always)]
fn fory_read_data(_context: &mut ReadContext) -> Result<Self, Error> {
// Unit type has no data to read
Ok(())
}
#[inline(always)]
fn fory_reserved_space() -> usize {
0
}
#[inline(always)]
fn fory_get_type_id(_: &TypeResolver) -> Result<TypeId, Error> {
// Use NONE - unit type has no runtime data, skip can return early
Ok(TypeId::NONE)
}
#[inline(always)]
fn fory_type_id_dyn(&self, _: &TypeResolver) -> Result<TypeId, Error> {
// Use NONE - unit type has no runtime data, skip can return early
Ok(TypeId::NONE)
}
#[inline(always)]
fn fory_static_type_id() -> TypeId {
// Use NONE - unit type has no runtime data, skip can return early
TypeId::NONE
}
#[inline(always)]
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
impl ForyDefault for () {
#[inline(always)]
fn fory_default() -> Self {}
}
/// Helper function to write a tuple element based on its type characteristics.
/// This handles the different serialization strategies for various element types.
#[inline(always)]
fn write_tuple_element<T: Serializer>(elem: &T, context: &mut WriteContext) -> Result<(), Error> {
if T::fory_is_option() || T::fory_is_shared_ref() || T::fory_static_type_id() == TypeId::UNKNOWN
{
// For Option, shared references, or unknown static types, use full write with ref tracking
let ref_mode = if T::fory_is_shared_ref() {
RefMode::Tracking
} else {
RefMode::NullOnly
};
elem.fory_write(context, ref_mode, false, false)
} else {
// For concrete types with known static type IDs, directly write data
elem.fory_write_data(context)
}
}
/// Helper function to read a tuple element based on its type characteristics.
#[inline(always)]
fn read_tuple_element<T: Serializer + ForyDefault>(
context: &mut ReadContext,
_has_generics: bool,
) -> Result<T, Error> {
if T::fory_is_option() || T::fory_is_shared_ref() || T::fory_static_type_id() == TypeId::UNKNOWN
{
// For Option, shared references, or unknown static types, use full read with ref tracking
let ref_mode = if T::fory_is_shared_ref() {
RefMode::Tracking
} else {
RefMode::NullOnly
};
T::fory_read(context, ref_mode, false)
} else {
// For concrete types with known static type IDs, directly read data
T::fory_read_data(context)
}
}
impl<T0: Serializer + ForyDefault> Serializer for (T0,) {
#[inline(always)]
fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> {
if !context.is_compatible() && !context.is_xlang() {
// Non-compatible mode: write elements directly
write_tuple_element(&self.0, context)?;
} else {
// Compatible mode: use collection protocol (heterogeneous)
context.writer.write_var_uint32(1);
let header = 0u8; // No IS_SAME_TYPE flag
context.writer.write_u8(header);
self.0.fory_write(context, RefMode::NullOnly, true, false)?;
}
Ok(())
}
#[inline(always)]
fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
write_collection_type_info(context, TypeId::LIST as u32)
}
#[inline(always)]
fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
if !context.is_compatible() && !context.is_xlang() {
// Non-compatible mode: read elements directly
let elem0 = read_tuple_element::<T0>(context, false)?;
Ok((elem0,))
} else {
// Compatible mode: read collection protocol (heterogeneous)
let len = context.reader.read_varuint32()?;
let _header = context.reader.read_u8()?;
let elem0 = if len > 0 {
T0::fory_read(context, RefMode::NullOnly, true)?
} else {
T0::fory_default()
};
// Skip any extra elements beyond the first
for _ in 1..len {
skip_any_value(context, true)?;
}
Ok((elem0,))
}
}
#[inline(always)]
fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
read_collection_type_info(context, TypeId::LIST as u32)
}
#[inline(always)]
fn fory_reserved_space() -> usize {
mem::size_of::<u32>()
}
#[inline(always)]
fn fory_get_type_id(_: &TypeResolver) -> Result<TypeId, Error> {
Ok(TypeId::LIST)
}
#[inline(always)]
fn fory_type_id_dyn(&self, _: &TypeResolver) -> Result<TypeId, Error> {
Ok(TypeId::LIST)
}
#[inline(always)]
fn fory_static_type_id() -> TypeId {
TypeId::LIST
}
#[inline(always)]
fn fory_is_wrapper_type() -> bool
where
Self: Sized,
{
true
}
#[inline(always)]
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
impl<T0: ForyDefault> ForyDefault for (T0,) {
#[inline(always)]
fn fory_default() -> Self {
(T0::fory_default(),)
}
}
macro_rules! fory_tuple_field {
($tuple:expr, T0) => {
$tuple.0
};
($tuple:expr, T1) => {
$tuple.1
};
($tuple:expr, T2) => {
$tuple.2
};
($tuple:expr, T3) => {
$tuple.3
};
($tuple:expr, T4) => {
$tuple.4
};
($tuple:expr, T5) => {
$tuple.5
};
($tuple:expr, T6) => {
$tuple.6
};
($tuple:expr, T7) => {
$tuple.7
};
($tuple:expr, T8) => {
$tuple.8
};
($tuple:expr, T9) => {
$tuple.9
};
($tuple:expr, T10) => {
$tuple.10
};
($tuple:expr, T11) => {
$tuple.11
};
($tuple:expr, T12) => {
$tuple.12
};
($tuple:expr, T13) => {
$tuple.13
};
($tuple:expr, T14) => {
$tuple.14
};
($tuple:expr, T15) => {
$tuple.15
};
($tuple:expr, T16) => {
$tuple.16
};
($tuple:expr, T17) => {
$tuple.17
};
($tuple:expr, T18) => {
$tuple.18
};
($tuple:expr, T19) => {
$tuple.19
};
($tuple:expr, T20) => {
$tuple.20
};
($tuple:expr, T21) => {
$tuple.21
};
($tuple:expr, T22) => {
$tuple.22
};
($tuple:expr, T23) => {
$tuple.23
};
($tuple:expr, T24) => {
$tuple.24
};
($tuple:expr, T25) => {
$tuple.25
};
($tuple:expr, T26) => {
$tuple.26
};
($tuple:expr, T27) => {
$tuple.27
};
($tuple:expr, T28) => {
$tuple.28
};
($tuple:expr, T29) => {
$tuple.29
};
($tuple:expr, T30) => {
$tuple.30
};
($tuple:expr, T31) => {
$tuple.31
};
($tuple:expr, T32) => {
$tuple.32
};
($tuple:expr, T33) => {
$tuple.33
};
($tuple:expr, T34) => {
$tuple.34
};
($tuple:expr, T35) => {
$tuple.35
};
($tuple:expr, T36) => {
$tuple.36
};
($tuple:expr, T37) => {
$tuple.37
};
($tuple:expr, T38) => {
$tuple.38
};
($tuple:expr, T39) => {
$tuple.39
};
($tuple:expr, T40) => {
$tuple.40
};
}
macro_rules! fory_tuple_count {
($($name:ident),+ $(,)?) => {
0usize $(+ fory_tuple_count!(@one $name))*
};
(@one $name:ident) => { 1usize };
}
/// Macro to implement Serializer for tuples of various sizes.
/// Fory supports tuples up to 22 elements, longer tuples are not allowed.
///
/// This handles two serialization modes:
/// 1. Non-compatible mode: Write elements one by one without collection headers and type metadata
/// 2. Compatible mode: Use full collection protocol with headers and type info (always heterogeneous)
#[macro_export]
macro_rules! impl_tuple_serializer {
// Multiple element tuples (2+)
($T0:ident $(, $T:ident)+ $(,)?) => {
impl<$T0: Serializer + ForyDefault, $($T: Serializer + ForyDefault),*> Serializer for ($T0, $($T),*) {
#[inline(always)]
fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> {
if !context.is_compatible() && !context.is_xlang() {
// Non-compatible mode: write elements directly one by one
write_tuple_element(&self.0, context)?;
$(
write_tuple_element(&fory_tuple_field!(self, $T), context)?;
)*
} else {
// Compatible mode: use collection protocol (always heterogeneous)
let len = fory_tuple_count!($T0, $($T),*);
context.writer.write_var_uint32(len as u32);
// Write header without IS_SAME_TYPE flag
let header = 0u8;
context.writer.write_u8(header);
// Write each element with its type info
self.0.fory_write(context, RefMode::NullOnly, true, false)?;
$(
fory_tuple_field!(self, $T).fory_write(context, RefMode::NullOnly, true, false)?;
)*
}
Ok(())
}
#[inline(always)]
fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
write_collection_type_info(context, TypeId::LIST as u32)
}
#[inline(always)]
fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
if !context.is_compatible() && !context.is_xlang() {
// Non-compatible mode: read elements directly
let elem0 = read_tuple_element::<$T0>(context, false)?;
$(
#[allow(non_snake_case)]
let $T = read_tuple_element::<$T>(context, false)?;
)*
Ok((elem0, $($T),*))
} else {
// Compatible mode: read collection protocol (always heterogeneous)
// Handle flexible length: use defaults for missing elements, skip extras
let len = context.reader.read_varuint32()?;
let _header = context.reader.read_u8()?;
// Track how many elements we've read
let mut index = 0u32;
// Read first element or use default
let elem0 = if index < len {
index += 1;
$T0::fory_read(context, RefMode::NullOnly, true)?
} else {
$T0::fory_default()
};
// Read remaining elements or use defaults
$(
#[allow(non_snake_case)]
let $T = if index < len {
index += 1;
$T::fory_read(context, RefMode::NullOnly, true)?
} else {
$T::fory_default()
};
)*
// Skip any extra elements beyond what we expect
for _ in index..len {
skip_any_value(context, true)?;
}
Ok((elem0, $($T),*))
}
}
#[inline(always)]
fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
read_collection_type_info(context, TypeId::LIST as u32)
}
#[inline(always)]
fn fory_reserved_space() -> usize {
mem::size_of::<u32>() // Size for length
}
#[inline(always)]
fn fory_get_type_id(_: &TypeResolver) -> Result<TypeId, Error> {
Ok(TypeId::LIST)
}
#[inline(always)]
fn fory_type_id_dyn(&self, _: &TypeResolver) -> Result<TypeId, Error> {
Ok(TypeId::LIST)
}
#[inline(always)]
fn fory_static_type_id() -> TypeId {
TypeId::LIST
}
#[inline(always)]
fn fory_is_wrapper_type() -> bool
where
Self: Sized, {
true
}
#[inline(always)]
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
impl<$T0: ForyDefault, $($T: ForyDefault),*> ForyDefault for ($T0, $($T),*) {
#[inline(always)]
fn fory_default() -> Self {
($T0::fory_default(), $($T::fory_default()),*)
}
}
};
}
// Implement Serializer for tuples of size 2-22
impl_tuple_serializer!(T0, T1);
impl_tuple_serializer!(T0, T1, T2);
impl_tuple_serializer!(T0, T1, T2, T3);
impl_tuple_serializer!(T0, T1, T2, T3, T4);
impl_tuple_serializer!(T0, T1, T2, T3, T4, T5);
impl_tuple_serializer!(T0, T1, T2, T3, T4, T5, T6);
impl_tuple_serializer!(T0, T1, T2, T3, T4, T5, T6, T7);
impl_tuple_serializer!(T0, T1, T2, T3, T4, T5, T6, T7, T8);
impl_tuple_serializer!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9);
impl_tuple_serializer!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
impl_tuple_serializer!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);
impl_tuple_serializer!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12);
impl_tuple_serializer!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13);
impl_tuple_serializer!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14);
impl_tuple_serializer!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15);
impl_tuple_serializer!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16);
impl_tuple_serializer!(
T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17
);
impl_tuple_serializer!(
T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18
);
impl_tuple_serializer!(
T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19
);
impl_tuple_serializer!(
T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20
);
impl_tuple_serializer!(
T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20,
T21
);