Skip to main content

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}