Skip to main content

fory_core/serializer/
struct_.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, StructSerializer};
22use crate::types::{RefFlag, RefMode, TypeId};
23use crate::util::ENABLE_FORY_DEBUG_OUTPUT;
24use std::any::Any;
25
26#[inline(always)]
27pub fn actual_type_id(_type_id: u32, register_by_name: bool, compatible: bool) -> u32 {
28    if compatible {
29        if register_by_name {
30            TypeId::NAMED_COMPATIBLE_STRUCT as u32
31        } else {
32            TypeId::COMPATIBLE_STRUCT as u32
33        }
34    } else if register_by_name {
35        TypeId::NAMED_STRUCT as u32
36    } else {
37        TypeId::STRUCT as u32
38    }
39}
40
41#[inline(always)]
42pub fn write_type_info<T: Serializer>(context: &mut WriteContext) -> Result<(), Error> {
43    let rs_type_id = std::any::TypeId::of::<T>();
44    let type_id = T::fory_get_type_id(context.get_type_resolver())?;
45    context.write_any_type_info(type_id as u32, rs_type_id)?;
46    Ok(())
47}
48
49#[inline(always)]
50pub fn read_type_info<T: Serializer>(context: &mut ReadContext) -> Result<(), Error> {
51    context.read_any_type_info()?;
52    Ok(())
53}
54
55#[inline(always)]
56pub fn read_type_info_fast<T: StructSerializer>(context: &mut ReadContext) -> Result<(), Error> {
57    if context.is_compatible() || context.is_xlang() {
58        return read_type_info::<T>(context);
59    }
60    let local_type_id = context
61        .get_type_resolver()
62        .get_type_id_by_index(T::fory_type_index())?;
63    let local_type_id_u32 = local_type_id as u32;
64    if !crate::types::needs_user_type_id(local_type_id_u32) {
65        return read_type_info::<T>(context);
66    }
67    let remote_type_id = context.reader.read_u8()? as u32;
68    ensure!(
69        local_type_id_u32 == remote_type_id,
70        Error::type_mismatch(local_type_id_u32, remote_type_id)
71    );
72    let remote_user_type_id = context.reader.read_varuint32()?;
73    let local_user_type_id = context
74        .get_type_resolver()
75        .get_user_type_id_by_index(&std::any::TypeId::of::<T>(), T::fory_type_index())?;
76    if remote_user_type_id != local_user_type_id {
77        return Err(Error::type_error(format!(
78            "User type id mismatch: local {} vs remote {}",
79            local_user_type_id, remote_user_type_id
80        )));
81    }
82    Ok(())
83}
84
85#[inline(always)]
86pub fn write<T: Serializer>(
87    this: &T,
88    context: &mut WriteContext,
89    ref_mode: RefMode,
90    write_type_info: bool,
91) -> Result<(), Error> {
92    match ref_mode {
93        RefMode::None => {}
94        RefMode::NullOnly => {
95            context.writer.write_i8(RefFlag::NotNullValue as i8);
96        }
97        RefMode::Tracking => {
98            // For ref tracking mode, write RefValue flag and reserve a ref_id
99            // so this struct participates in reference tracking.
100            context.writer.write_i8(RefFlag::RefValue as i8);
101            context.ref_writer.reserve_ref_id();
102        }
103    }
104    if write_type_info {
105        T::fory_write_type_info(context)?;
106    }
107    this.fory_write_data(context)
108}
109
110pub type BeforeWriteFieldFunc =
111    fn(struct_name: &str, field_name: &str, field_value: &dyn Any, context: &mut WriteContext);
112pub type AfterWriteFieldFunc =
113    fn(struct_name: &str, field_name: &str, field_value: &dyn Any, context: &mut WriteContext);
114pub type BeforeReadFieldFunc = fn(struct_name: &str, field_name: &str, context: &mut ReadContext);
115pub type AfterReadFieldFunc =
116    fn(struct_name: &str, field_name: &str, field_value: &dyn Any, context: &mut ReadContext);
117
118fn default_before_write_field(
119    struct_name: &str,
120    field_name: &str,
121    _field_value: &dyn Any,
122    context: &mut WriteContext,
123) {
124    if ENABLE_FORY_DEBUG_OUTPUT {
125        println!(
126            "before_write_field:\tstruct={struct_name},\tfield={field_name},\twriter_len={}",
127            context.writer.len()
128        );
129    }
130}
131
132fn default_after_write_field(
133    struct_name: &str,
134    field_name: &str,
135    _field_value: &dyn Any,
136    context: &mut WriteContext,
137) {
138    if ENABLE_FORY_DEBUG_OUTPUT {
139        println!(
140            "after_write_field:\tstruct={struct_name},\tfield={field_name},\twriter_len={}",
141            context.writer.len()
142        );
143    }
144}
145
146fn default_before_read_field(struct_name: &str, field_name: &str, context: &mut ReadContext) {
147    if ENABLE_FORY_DEBUG_OUTPUT {
148        println!(
149            "before_read_field:\tstruct={struct_name},\tfield={field_name},\treader_cursor={}",
150            context.reader.get_cursor()
151        );
152    }
153}
154
155fn default_after_read_field(
156    struct_name: &str,
157    field_name: &str,
158    _field_value: &dyn Any,
159    context: &mut ReadContext,
160) {
161    if ENABLE_FORY_DEBUG_OUTPUT {
162        println!(
163            "after_read_field:\tstruct={struct_name},\tfield={field_name},\treader_cursor={}",
164            context.reader.get_cursor()
165        );
166    }
167}
168
169static mut BEFORE_WRITE_FIELD_FUNC: BeforeWriteFieldFunc = default_before_write_field;
170static mut AFTER_WRITE_FIELD_FUNC: AfterWriteFieldFunc = default_after_write_field;
171static mut BEFORE_READ_FIELD_FUNC: BeforeReadFieldFunc = default_before_read_field;
172static mut AFTER_READ_FIELD_FUNC: AfterReadFieldFunc = default_after_read_field;
173
174pub fn set_before_write_field_func(func: BeforeWriteFieldFunc) {
175    unsafe { BEFORE_WRITE_FIELD_FUNC = func }
176}
177
178pub fn set_after_write_field_func(func: AfterWriteFieldFunc) {
179    unsafe { AFTER_WRITE_FIELD_FUNC = func }
180}
181
182pub fn set_before_read_field_func(func: BeforeReadFieldFunc) {
183    unsafe { BEFORE_READ_FIELD_FUNC = func }
184}
185
186pub fn set_after_read_field_func(func: AfterReadFieldFunc) {
187    unsafe { AFTER_READ_FIELD_FUNC = func }
188}
189
190pub fn reset_struct_debug_hooks() {
191    unsafe {
192        BEFORE_WRITE_FIELD_FUNC = default_before_write_field;
193        AFTER_WRITE_FIELD_FUNC = default_after_write_field;
194        BEFORE_READ_FIELD_FUNC = default_before_read_field;
195        AFTER_READ_FIELD_FUNC = default_after_read_field;
196    }
197}
198
199/// Debug method to hook into struct serialization
200pub fn struct_before_write_field(
201    struct_name: &str,
202    field_name: &str,
203    field_value: &dyn Any,
204    context: &mut WriteContext,
205) {
206    unsafe { BEFORE_WRITE_FIELD_FUNC(struct_name, field_name, field_value, context) }
207}
208
209/// Debug method to hook into struct serialization
210pub fn struct_after_write_field(
211    struct_name: &str,
212    field_name: &str,
213    field_value: &dyn Any,
214    context: &mut WriteContext,
215) {
216    unsafe { AFTER_WRITE_FIELD_FUNC(struct_name, field_name, field_value, context) }
217}
218
219/// Debug method to hook into struct deserialization
220pub fn struct_before_read_field(struct_name: &str, field_name: &str, context: &mut ReadContext) {
221    unsafe { BEFORE_READ_FIELD_FUNC(struct_name, field_name, context) }
222}
223
224/// Debug method to hook into struct deserialization
225pub fn struct_after_read_field(
226    struct_name: &str,
227    field_name: &str,
228    field_value: &dyn Any,
229    context: &mut ReadContext,
230) {
231    unsafe { AFTER_READ_FIELD_FUNC(struct_name, field_name, field_value, context) }
232}