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::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}