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::ensure;
19use crate::error::Error;
20use crate::resolver::context::{ReadContext, WriteContext};
21use crate::serializer::Serializer;
22use crate::types::TypeId;
23use crate::types::{is_user_type, ENUM, NAMED_ENUM, UNION};
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/// Check at runtime whether type info should be skipped for a given type id.
38///
39/// According to xlang_serialization_spec.md:
40/// - For enums (ENUM/NAMED_ENUM), we should skip writing type info
41/// - For structs and ext types, we should write type info
42///
43/// Keep as const fn for compile time evaluation or constant folding
44#[inline]
45pub const fn field_need_read_type_info(type_id: u32) -> bool {
46 if type_id == ENUM || type_id == NAMED_ENUM || type_id == UNION {
47 return false;
48 }
49 is_user_type(type_id)
50}
51
52/// Keep as const fn for compile time evaluation or constant folding
53pub const fn field_need_write_type_info(static_type_id: TypeId) -> bool {
54 let static_type_id = static_type_id as u32;
55 if static_type_id == ENUM || static_type_id == NAMED_ENUM || static_type_id == UNION {
56 return false;
57 }
58 is_user_type(static_type_id)
59}
60
61/// Keep as const fn for compile time evaluation or constant folding
62///
63/// In xlang mode with nullable=false default:
64/// - If nullable=true: always need to write ref flag (to handle null values)
65/// - If nullable=false: no ref flag needed (value is always present, no null handling required)
66///
67/// This aligns with the xlang protocol where:
68/// - Non-optional types (nullable=false) skip the ref flag entirely
69/// - Optional types (nullable=true) write a ref flag to indicate null vs non-null
70#[inline]
71pub const fn field_need_write_ref_into(_type_id: u32, nullable: bool) -> bool {
72 // Only write ref flag when nullable is true (value can be null)
73 // When nullable=false, the value is always present, no ref flag needed
74 nullable
75}
76
77#[inline(always)]
78pub fn write_dyn_data_generic<T: Serializer>(
79 value: &T,
80 context: &mut WriteContext,
81 has_generics: bool,
82) -> Result<(), Error> {
83 let any_value = value.as_any();
84 let concrete_type_id = any_value.type_id();
85 let serializer_fn = context
86 .write_any_type_info(T::fory_static_type_id() as u32, concrete_type_id)?
87 .get_harness()
88 .get_write_data_fn();
89 serializer_fn(any_value, context, has_generics)
90}