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