fory_core/serializer/util.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, WriteContext};
19use crate::ensure;
20use crate::error::Error;
21use crate::serializer::Serializer;
22use crate::type_id::TypeId;
23use crate::type_id::{is_user_type, ENUM, NAMED_ENUM, NAMED_UNION, TYPED_UNION, UNION, UNKNOWN};
24
25#[inline(always)]
26pub(crate) fn read_basic_type_info<T: Serializer>(context: &mut ReadContext) -> Result<(), Error> {
27 let local_type_id = T::fory_get_type_id(context.get_type_resolver())?;
28 let local_type_id_u32 = local_type_id as u32;
29 let remote_type_id = context.reader.read_u8()? as u32;
30 ensure!(
31 local_type_id_u32 == remote_type_id,
32 Error::type_mismatch(local_type_id_u32, remote_type_id)
33 );
34 Ok(())
35}
36
37/// Returns whether a schema-known struct field value carries inline type information.
38///
39/// Compatible/xlang struct field metadata describes the schema kind, but dynamic fields and
40/// struct/ext user fields carry inline type information so readers can resolve the concrete
41/// TypeInfo. Enums and union-compatible fields are exceptions: their field payloads are
42/// ordinal/index based and do not start with a type-info header.
43#[inline(always)]
44pub const fn field_need_read_type_info(type_id: u32) -> bool {
45 if type_id == ENUM || type_id == NAMED_ENUM || type_id == UNION {
46 return false;
47 }
48 type_id == UNKNOWN || is_user_type(type_id)
49}
50
51/// Returns whether a schema-known struct field write must include inline type information.
52///
53/// This is the write-side counterpart of [`field_need_read_type_info`].
54#[inline(always)]
55pub const fn field_need_write_type_info(static_type_id: TypeId) -> bool {
56 let static_type_id = static_type_id as u32;
57 if static_type_id == ENUM
58 || static_type_id == NAMED_ENUM
59 || static_type_id == UNION
60 || static_type_id == TYPED_UNION
61 || static_type_id == NAMED_UNION
62 {
63 return false;
64 }
65 static_type_id == UNKNOWN || is_user_type(static_type_id)
66}
67
68/// Keep as const fn for compile time evaluation or constant folding
69///
70/// In xlang mode with nullable=false default:
71/// - If nullable=true: always need to write ref flag (to handle null values)
72/// - If nullable=false: no ref flag needed (value is always present, no null handling required)
73///
74/// This aligns with the xlang protocol where:
75/// - Non-optional types (nullable=false) skip the ref flag entirely
76/// - Optional types (nullable=true) write a ref flag to indicate null vs non-null
77#[inline]
78pub const fn field_need_write_ref_into(_type_id: u32, nullable: bool) -> bool {
79 // Only write ref flag when nullable is true (value can be null)
80 // When nullable=false, the value is always present, no ref flag needed
81 nullable
82}
83
84#[inline(always)]
85pub fn write_dyn_data_generic<T: Serializer>(
86 value: &T,
87 context: &mut WriteContext,
88 has_generics: bool,
89) -> Result<(), Error> {
90 let any_value = value.as_any();
91 let concrete_type_id = any_value.type_id();
92 let serializer_fn = context
93 .write_any_type_info(T::fory_static_type_id() as u32, concrete_type_id)?
94 .get_harness()
95 .get_write_data_fn();
96 serializer_fn(any_value, context, has_generics)
97}
98
99pub(crate) mod send_sync {
100 use std::any::Any;
101
102 #[inline(always)]
103 pub fn box_send_sync<T>(value: T) -> Box<dyn Any + Send + Sync>
104 where
105 T: Any + Send + Sync,
106 {
107 Box::new(value)
108 }
109}