Skip to main content

fory_core/
fory.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::buffer::{Reader, Writer};
19use crate::config::Config;
20use crate::context::{ContextCache, ReadContext, WriteContext};
21use crate::ensure;
22use crate::error::Error;
23use crate::resolver::RefMode;
24use crate::resolver::TypeResolver;
25use crate::serializer::ForyDefault;
26use crate::serializer::{Serializer, StructSerializer};
27use crate::type_id::config_flags::{IS_CROSS_LANGUAGE_FLAG, IS_OUT_OF_BAND_FLAG};
28use crate::type_id::SIZE_OF_REF_AND_TYPE;
29use std::cell::UnsafeCell;
30use std::mem;
31use std::sync::atomic::{AtomicU64, Ordering};
32use std::sync::OnceLock;
33
34/// Global counter to assign unique IDs to each Fory instance.
35static FORY_ID_COUNTER: AtomicU64 = AtomicU64::new(0);
36
37thread_local! {
38    /// Thread-local storage for WriteContext instances with fast path caching.
39    static WRITE_CONTEXTS: UnsafeCell<ContextCache<WriteContext<'static>>> =
40        UnsafeCell::new(ContextCache::new());
41
42    /// Thread-local storage for ReadContext instances with fast path caching.
43    static READ_CONTEXTS: UnsafeCell<ContextCache<ReadContext<'static>>> =
44        UnsafeCell::new(ContextCache::new());
45}
46
47/// Builder for configuring a [`Fory`] instance before first use.
48///
49/// `ForyBuilder` owns the configuration phase. Call [`build`](Self::build) to create the
50/// instance, then use [`Fory`] for registration and serialization operations.
51///
52/// ```rust
53/// use fory_core::Fory;
54///
55/// let fory = Fory::builder()
56///     .compress_string(true)
57///     .max_dyn_depth(10)
58///     .build();
59/// ```
60#[derive(Default)]
61pub struct ForyBuilder {
62    config: Config,
63    compatible_set: bool,
64}
65
66impl ForyBuilder {
67    /// Sets the serialization compatible mode for this Fory builder.
68    ///
69    /// # Arguments
70    ///
71    /// * `compatible` - The serialization compatible mode to use. Options are:
72    ///   - `false`: Every reader and writer must use the same schema.
73    ///     Use only for smaller, faster same-schema payloads.
74    ///   - `true`: Supports schema evolution and type metadata sharing for better
75    ///     cross-version compatibility.
76    ///
77    /// # Returns
78    ///
79    /// Returns `self` for method chaining.
80    ///
81    /// # Note
82    ///
83    /// Setting the compatible mode also automatically configures the `share_meta` flag:
84    /// - `false` → `share_meta = false`
85    /// - `true` → `share_meta = true`
86    ///
87    /// # Examples
88    ///
89    /// ```rust
90    /// use fory_core::Fory;
91    ///
92    /// // Same-schema optimization.
93    /// let fory = Fory::builder().compatible(false).build();
94    /// ```
95    pub fn compatible(mut self, compatible: bool) -> Self {
96        self.compatible_set = true;
97        // Setting share_meta individually is not supported currently
98        self.config.share_meta = compatible;
99        self.config.compatible = compatible;
100        if compatible {
101            self.config.check_struct_version = false;
102        } else if self.config.xlang {
103            self.config.check_struct_version = true;
104        }
105        self
106    }
107
108    /// Enables or disables xlang mode.
109    ///
110    /// # Arguments
111    ///
112    /// * `xlang` - If `true`, uses the xlang wire format compatible with other Fory
113    ///   implementations (Java, Python, C++, etc.). If `false`, uses Rust native mode.
114    ///
115    /// # Returns
116    ///
117    /// Returns `self` for method chaining.
118    ///
119    /// # Default
120    ///
121    /// The default value is `true`.
122    ///
123    /// # Examples
124    ///
125    /// ```rust
126    /// use fory_core::Fory;
127    ///
128    /// // Xlang mode, the default cross-language wire format
129    /// let fory = Fory::builder().xlang(true).build();
130    ///
131    /// // Native mode for Rust-only traffic
132    /// let fory = Fory::builder().xlang(false).build();
133    /// ```
134    pub fn xlang(mut self, xlang: bool) -> Self {
135        self.config.xlang = xlang;
136        if !self.compatible_set {
137            self.config.share_meta = true;
138            self.config.compatible = true;
139            self.config.check_struct_version = false;
140            return self;
141        }
142        if !self.config.check_struct_version {
143            self.config.check_struct_version = !self.config.compatible;
144        }
145        self
146    }
147
148    /// Enables or disables meta string compression.
149    ///
150    /// # Arguments
151    ///
152    /// * `compress_string` - If `true`, enables meta string compression to reduce serialized
153    ///   payload size by deduplicating and encoding frequently used strings (such as type names
154    ///   and field names). If `false`, strings are serialized without compression.
155    ///
156    /// # Returns
157    ///
158    /// Returns `self` for method chaining.
159    ///
160    /// # Default
161    ///
162    /// The default value is `false`.
163    ///
164    /// # Trade-offs
165    ///
166    /// - **Enabled**: Smaller payload size, slightly higher CPU overhead
167    /// - **Disabled**: Larger payload size, faster serialization/deserialization
168    ///
169    /// # Examples
170    ///
171    /// ```rust
172    /// use fory_core::Fory;
173    ///
174    /// let fory = Fory::builder().compress_string(true).build();
175    /// ```
176    pub fn compress_string(mut self, compress_string: bool) -> Self {
177        self.config.compress_string = compress_string;
178        self
179    }
180
181    /// Enables or disables checked UTF-8 string reads.
182    ///
183    /// Checked reads validate UTF-8 payload bytes before constructing Rust `String` values.
184    /// Disabling this keeps the faster unchecked construction path and must only be used when
185    /// serialized bytes are trusted to contain valid UTF-8 strings.
186    ///
187    /// # Default
188    ///
189    /// The default value is `true`.
190    pub fn check_string_read(mut self, check_string_read: bool) -> Self {
191        self.config.check_string_read = check_string_read;
192        self
193    }
194
195    /// Enables or disables schema hash checking for same-schema payloads.
196    ///
197    /// # Arguments
198    ///
199    /// * `check_struct_version` - If `true`, enables schema hash checking for same-schema
200    ///   serialization and deserialization. When enabled,
201    ///   a version hash computed from field types is written/read to detect schema mismatches.
202    ///   If `false`, no version checking is performed.
203    ///
204    /// # Returns
205    ///
206    /// Returns `self` for method chaining.
207    ///
208    /// # Default
209    ///
210    /// The default value is `false`.
211    ///
212    /// # Note
213    ///
214    /// This feature is only effective when `compatible` mode is `false`. In compatible mode,
215    /// schema evolution is supported and version checking is not needed.
216    ///
217    /// # Examples
218    ///
219    /// ```rust
220    /// use fory_core::Fory;
221    ///
222    /// let fory = Fory::builder()
223    ///     .compatible(false)
224    ///     .check_struct_version(true)
225    ///     .build();
226    /// ```
227    pub fn check_struct_version(mut self, check_struct_version: bool) -> Self {
228        if self.config.compatible && check_struct_version {
229            // ignore setting if compatible mode is on
230            return self;
231        }
232        self.config.check_struct_version = check_struct_version;
233        self
234    }
235
236    /// Enables or disables reference tracking for shared and circular references.
237    ///
238    /// # Arguments
239    ///
240    /// * `track_ref` - If `true`, enables reference tracking which allows
241    ///   preserving shared object references and circular references during
242    ///   serialization/deserialization.
243    ///
244    /// # Returns
245    ///
246    /// Returns `self` for method chaining.
247    ///
248    /// # Default
249    ///
250    /// The default value is `false`.
251    ///
252    /// # Examples
253    ///
254    /// ```rust
255    /// use fory_core::Fory;
256    ///
257    /// let fory = Fory::builder().track_ref(true).build();
258    /// ```
259    pub fn track_ref(mut self, track_ref: bool) -> Self {
260        self.config.track_ref = track_ref;
261        self
262    }
263
264    /// Sets the approximate graph-memory gate for one root deserialization.
265    ///
266    /// Mainly gates materialized collections, maps, arrays, structs, and objects. Leaf values are
267    /// gated by unread input bytes instead, and actual process memory can be higher. Defaults to
268    /// 128 MiB. Values must be positive byte limits.
269    pub fn max_graph_memory_bytes(mut self, max_bytes: usize) -> Self {
270        assert!(
271            max_bytes > 0,
272            "max_graph_memory_bytes must be in [1, usize::MAX]"
273        );
274        self.config.max_graph_memory_bytes = max_bytes;
275        self
276    }
277
278    /// Sets the maximum depth for nested dynamic object serialization.
279    ///
280    /// # Arguments
281    ///
282    /// * `max_dyn_depth` - The maximum nesting depth allowed for dynamically-typed objects
283    ///   (e.g., trait objects, boxed types). This prevents stack overflow from deeply nested
284    ///   structures in dynamic serialization scenarios.
285    ///
286    /// # Returns
287    ///
288    /// Returns `self` for method chaining.
289    ///
290    /// # Default
291    ///
292    /// The default value is `5`.
293    ///
294    /// # Behavior
295    ///
296    /// When the depth limit is exceeded during deserialization, an error is returned to prevent
297    /// potential stack overflow or infinite recursion.
298    ///
299    /// # Examples
300    ///
301    /// ```rust
302    /// use fory_core::Fory;
303    ///
304    /// // Allow deeper nesting for complex object graphs
305    /// let fory = Fory::builder().max_dyn_depth(10).build();
306    ///
307    /// // Restrict nesting for safer deserialization
308    /// let fory = Fory::builder().max_dyn_depth(3).build();
309    /// ```
310    pub fn max_dyn_depth(mut self, max_dyn_depth: u32) -> Self {
311        self.config.max_dyn_depth = max_dyn_depth;
312        self
313    }
314
315    /// Sets the maximum field count accepted in one received struct TypeMeta.
316    pub fn max_type_fields(mut self, max_fields: usize) -> Self {
317        assert!(max_fields > 0, "max_type_fields must be positive");
318        assert!(
319            u32::try_from(max_fields).is_ok(),
320            "max_type_fields is too large"
321        );
322        self.config.max_type_fields = max_fields as u32;
323        self
324    }
325
326    /// Sets the maximum body size accepted for one received TypeMeta.
327    pub fn max_type_meta_bytes(mut self, max_bytes: usize) -> Self {
328        assert!(max_bytes > 0, "max_type_meta_bytes must be positive");
329        assert!(
330            u32::try_from(max_bytes).is_ok(),
331            "max_type_meta_bytes is too large"
332        );
333        self.config.max_type_meta_bytes = max_bytes as u32;
334        self
335    }
336
337    /// Sets the maximum accepted remote metadata versions for one logical type.
338    pub fn max_schema_versions_per_type(mut self, max_versions: usize) -> Self {
339        assert!(
340            max_versions > 0,
341            "max_schema_versions_per_type must be positive"
342        );
343        assert!(
344            u32::try_from(max_versions).is_ok(),
345            "max_schema_versions_per_type is too large"
346        );
347        self.config.max_schema_versions_per_type = max_versions as u32;
348        self
349    }
350
351    /// Sets the maximum accepted average remote metadata versions across logical types.
352    pub fn max_average_schema_versions_per_type(mut self, max_versions: usize) -> Self {
353        assert!(
354            max_versions > 0,
355            "max_average_schema_versions_per_type must be positive"
356        );
357        assert!(
358            u32::try_from(max_versions).is_ok(),
359            "max_average_schema_versions_per_type is too large"
360        );
361        self.config.max_average_schema_versions_per_type = max_versions as u32;
362        self
363    }
364
365    fn finish_config(self) -> Config {
366        let mut config = self.config;
367        if !self.compatible_set {
368            config.share_meta = true;
369            config.compatible = true;
370            config.check_struct_version = false;
371        }
372        config
373    }
374
375    /// Builds a [`Fory`] instance with the current builder configuration.
376    pub fn build(self) -> Fory {
377        let config = self.finish_config();
378        Fory::from_config(config)
379    }
380}
381
382/// The main Fory serialization framework instance.
383///
384/// `Fory` provides high-performance serialization and deserialization with xlang mode,
385/// native mode, reference tracking, and trait object serialization.
386///
387/// # Features
388///
389/// - **Xlang mode**: Default wire format for cross-language payloads
390/// - **Native mode**: Rust-only wire format selected with `.xlang(false)`
391/// - **Schema evolution**: Compatible mode by default, with a same-schema optimization available
392/// - **Reference tracking**: Handles shared and circular references
393/// - **Trait object serialization**: Supports serializing polymorphic trait objects
394/// - **Dynamic depth limiting**: Configurable limit for nested dynamic object serialization
395///
396/// # Examples
397///
398/// Basic usage:
399///
400/// ```rust, ignore
401/// use fory::Fory;
402/// use fory::{ForyEnum, ForyStruct, ForyUnion};
403///
404/// #[derive(ForyStruct)]
405/// struct User {
406///     name: String,
407///     age: u32,
408/// }
409///
410/// let mut fory = Fory::builder().xlang(true).build();
411/// fory.register_by_name::<User>("example.User").unwrap();
412/// let user = User { name: "Alice".to_string(), age: 30 };
413/// let bytes = fory.serialize(&user).unwrap();
414/// let deserialized: User = fory.deserialize(&bytes).unwrap();
415/// ```
416///
417/// Custom configuration:
418///
419/// ```rust
420/// use fory_core::Fory;
421///
422/// let fory = Fory::builder()
423///     .compress_string(true)
424///     .max_dyn_depth(10)
425///     .build();
426/// ```
427pub struct Fory {
428    /// Unique identifier for this Fory instance, used as key in thread-local context maps.
429    id: u64,
430    type_resolver: TypeResolver,
431    /// Lazy-initialized final type resolver (thread-safe, one-time initialization).
432    final_type_resolver: OnceLock<Result<TypeResolver, Error>>,
433    /// Configuration for serialization behavior.
434    ///
435    /// Keep this cold field after the resolver/cache fields. Remote metadata
436    /// limits make Config larger, but serialize hot paths repeatedly access
437    /// the instance id and resolver snapshot, not the cold limit values.
438    config: Config,
439}
440
441impl Default for Fory {
442    fn default() -> Self {
443        Self::builder().build()
444    }
445}
446
447impl Fory {
448    /// Creates a builder for configuring a [`Fory`] instance.
449    pub fn builder() -> ForyBuilder {
450        ForyBuilder::default()
451    }
452
453    fn from_config(config: Config) -> Self {
454        let mut type_resolver = TypeResolver::default();
455        type_resolver.set_compatible(config.compatible);
456        type_resolver.set_xlang(config.xlang);
457        Self {
458            id: FORY_ID_COUNTER.fetch_add(1, Ordering::Relaxed),
459            config,
460            type_resolver,
461            final_type_resolver: OnceLock::new(),
462        }
463    }
464
465    /// Returns whether xlang mode is enabled.
466    pub fn is_xlang(&self) -> bool {
467        self.config.xlang
468    }
469
470    /// Returns whether compatible schema evolution is enabled.
471    ///
472    /// # Returns
473    ///
474    /// `true` if compatible schema evolution is enabled, `false` otherwise.
475    pub fn is_compatible(&self) -> bool {
476        self.config.compatible
477    }
478
479    /// Returns whether string compression is enabled.
480    ///
481    /// # Returns
482    ///
483    /// `true` if meta string compression is enabled, `false` otherwise.
484    pub fn is_compress_string(&self) -> bool {
485        self.config.compress_string
486    }
487
488    /// Returns whether UTF-8 string payload validation is enabled.
489    pub fn is_check_string_read(&self) -> bool {
490        self.config.check_string_read
491    }
492
493    /// Returns whether metadata sharing is enabled.
494    ///
495    /// # Returns
496    ///
497    /// `true` if metadata sharing is enabled, `false` otherwise.
498    pub fn is_share_meta(&self) -> bool {
499        self.config.share_meta
500    }
501
502    /// Returns the maximum depth for nested dynamic object serialization.
503    pub fn get_max_dyn_depth(&self) -> u32 {
504        self.config.max_dyn_depth
505    }
506
507    /// Returns whether class version checking is enabled.
508    ///
509    /// # Returns
510    ///
511    /// `true` if class version checking is enabled, `false` otherwise.
512    pub fn is_check_struct_version(&self) -> bool {
513        self.config.check_struct_version
514    }
515
516    /// Returns a reference to the configuration.
517    pub fn config(&self) -> &Config {
518        &self.config
519    }
520
521    /// Checks whether the final type resolver has already been initialized.
522    ///
523    /// If it has, further type registrations would be silently ignored (the frozen
524    /// snapshot is what serialize/deserialize actually use),so we fail fast with
525    /// a clear error instead.
526    ///
527    /// # errors
528    ///
529    /// returns [`Error::NotAllowed`] when the resolver snapshot has already been
530    /// built (i.e after the first `serialize` / `deserialize` call).
531    fn check_registration_allowed(&self) -> Result<(), Error> {
532        if self.final_type_resolver.get().is_some() {
533            return Err(Error::not_allowed(
534                "Type registration is not allowed after the first serialize/deserialize call. \
535                 The type resolver snapshot has already been finalized. \
536                 Please complete all type registrations before performing any serialization or deserialization.",
537            ));
538        }
539        Ok(())
540    }
541
542    /// Serializes a value of type `T` into a byte vector.
543    ///
544    /// # Type Parameters
545    ///
546    /// * `T` - The type of the value to serialize. Must implement `Serializer`.
547    ///
548    /// # Arguments
549    ///
550    /// * `record` - A reference to the value to serialize.
551    ///
552    /// # Returns
553    ///
554    /// A `Vec<u8>` containing the serialized data.
555    ///
556    /// # Examples
557    ///
558    /// ```rust, ignore
559    /// use fory::Fory;
560    /// use fory::{ForyEnum, ForyStruct, ForyUnion};
561    ///
562    /// #[derive(ForyStruct)]
563    /// struct Point { x: i32, y: i32 }
564    ///
565    /// let mut fory = Fory::builder().xlang(true).build();
566    /// fory.register_by_name::<Point>("example.Point").unwrap();
567    /// let point = Point { x: 10, y: 20 };
568    /// let bytes = fory.serialize(&point).unwrap();
569    /// ```
570    pub fn serialize<T: Serializer>(&self, record: &T) -> Result<Vec<u8>, Error> {
571        self.with_write_context(
572            |context| match self.serialize_with_context(record, context) {
573                Ok(_) => {
574                    let result = context.writer.dump();
575                    context.writer.reset();
576                    Ok(result)
577                }
578                Err(err) => {
579                    context.writer.reset();
580                    Err(err)
581                }
582            },
583        )
584    }
585
586    /// Serializes a value of type `T` into the provided byte buffer.
587    ///
588    /// The serialized data is appended to the end of the buffer by default.
589    /// To write from a specific position, resize the buffer before calling this method.
590    ///
591    /// # Type Parameters
592    ///
593    /// * `T` - The type of the value to serialize. Must implement `Serializer`.
594    ///
595    /// # Arguments
596    ///
597    /// * `buf` - A mutable reference to the byte buffer to append the serialized data to.
598    ///   The buffer will be resized as needed during serialization.
599    /// * `record` - A reference to the value to serialize.
600    ///
601    /// # Returns
602    ///
603    /// The number of bytes written to the buffer on success, or an error if serialization fails.
604    ///
605    /// # Notes
606    ///
607    /// - Multiple `serialize_to` calls to the same buffer will append data sequentially.
608    ///
609    /// # Examples
610    ///
611    /// Basic usage - appending to a buffer:
612    ///
613    /// ```rust, ignore
614    /// use fory_core::Fory;
615    /// use fory_derive::{ForyEnum, ForyStruct, ForyUnion};
616    ///
617    /// #[derive(ForyStruct)]
618    /// struct Point {
619    ///     x: i32,
620    ///     y: i32,
621    /// }
622    ///
623    /// let mut fory = Fory::builder().xlang(true).build();
624    /// fory.register_by_name::<Point>("example.Point").unwrap();
625    /// let point = Point { x: 1, y: 2 };
626    ///
627    /// let mut buf = Vec::new();
628    /// let bytes_written = fory.serialize_to(&mut buf, &point).unwrap();
629    /// assert_eq!(bytes_written, buf.len());
630    /// ```
631    ///
632    /// Multiple serializations to the same buffer:
633    ///
634    /// ```rust, ignore
635    /// use fory_core::Fory;
636    /// use fory_derive::{ForyEnum, ForyStruct, ForyUnion};
637    ///
638    /// #[derive(ForyStruct, PartialEq, Debug)]
639    /// struct Point {
640    ///     x: i32,
641    ///     y: i32,
642    /// }
643    ///
644    /// let mut fory = Fory::builder().xlang(true).build();
645    /// fory.register_by_name::<Point>("example.Point").unwrap();
646    /// let p1 = Point { x: 1, y: 2 };
647    /// let p2 = Point { x: -3, y: 4 };
648    ///
649    /// let mut buf = Vec::new();
650    ///
651    /// // First serialization
652    /// let len1 = fory.serialize_to(&mut buf, &p1).unwrap();
653    /// let offset1 = buf.len();
654    ///
655    /// // Second serialization - appends to existing data
656    /// let len2 = fory.serialize_to(&mut buf, &p2).unwrap();
657    /// let offset2 = buf.len();
658    ///
659    /// assert_eq!(offset1, len1);
660    /// assert_eq!(offset2, len1 + len2);
661    ///
662    /// // Deserialize both objects
663    /// let deserialized1: Point = fory.deserialize(&buf[0..offset1]).unwrap();
664    /// let deserialized2: Point = fory.deserialize(&buf[offset1..offset2]).unwrap();
665    /// assert_eq!(deserialized1, p1);
666    /// assert_eq!(deserialized2, p2);
667    /// ```
668    ///
669    /// Writing to a specific position using `resize`:
670    /// # Notes on `vec.resize()`
671    ///
672    /// When calling `vec.resize(n, 0)`, note that if `n` is smaller than the current length,
673    /// the buffer will be truncated (not shrunk in capacity). The capacity remains unchanged,
674    /// making subsequent writes efficient for buffer reuse patterns:
675    ///
676    /// ```rust, ignore
677    /// use fory_core::Fory;
678    /// use fory_derive::{ForyEnum, ForyStruct, ForyUnion};
679    ///
680    /// #[derive(ForyStruct)]
681    /// struct Point {
682    ///     x: i32,
683    ///     y: i32,
684    /// }
685    ///
686    /// let mut fory = Fory::builder().xlang(true).build();
687    /// fory.register_by_name::<Point>("example.Point").unwrap();
688    /// let point = Point { x: 1, y: 2 };
689    ///
690    /// let mut buf = Vec::with_capacity(1024);
691    /// buf.resize(16, 0);  // Set length to 16 to append the write, capacity stays 1024
692    ///
693    /// let initial_capacity = buf.capacity();
694    /// fory.serialize_to(&mut buf, &point).unwrap();
695    ///
696    /// // Reset to smaller size to append the write - capacity unchanged
697    /// buf.resize(16, 0);
698    /// assert_eq!(buf.capacity(), initial_capacity);  // Capacity not shrunk
699    ///
700    /// // Reuse buffer efficiently without reallocation
701    /// fory.serialize_to(&mut buf, &point).unwrap();
702    /// assert_eq!(buf.capacity(), initial_capacity);  // Still no reallocation
703    /// ```
704    pub fn serialize_to<T: Serializer>(
705        &self,
706        buf: &mut Vec<u8>,
707        record: &T,
708    ) -> Result<usize, Error> {
709        let start = buf.len();
710        self.with_write_context(|context| {
711            // Context from thread-local would be 'static. but context hold the buffer through `writer` field,
712            // so we should make buffer live longer.
713            // After serializing, `detach_writer` will be called, the writer in context will be set to dangling pointer.
714            // So it's safe to make buf live to the end of this method.
715            let outlive_buffer = unsafe { mem::transmute::<&mut Vec<u8>, &mut Vec<u8>>(buf) };
716            context.attach_writer(Writer::from_buffer(outlive_buffer));
717            let result = self.serialize_with_context(record, context);
718            let written_size = context.writer.len() - start;
719            context.detach_writer();
720            match result {
721                Ok(_) => Ok(written_size),
722                Err(err) => Err(err),
723            }
724        })
725    }
726
727    /// Gets the final type resolver, building it lazily on first access.
728    #[inline(always)]
729    fn get_final_type_resolver(&self) -> Result<&TypeResolver, Error> {
730        let result = self
731            .final_type_resolver
732            .get_or_init(|| self.type_resolver.build_final_type_resolver());
733        result
734            .as_ref()
735            .map_err(|e| Error::type_error(format!("Failed to build type resolver: {}", e)))
736    }
737
738    /// Executes a closure with mutable access to a WriteContext for this Fory instance.
739    /// The context is stored in thread-local storage, eliminating all lock contention.
740    /// Uses fast path caching for O(1) access when using the same Fory instance repeatedly.
741    #[inline(always)]
742    fn with_write_context<R>(
743        &self,
744        f: impl FnOnce(&mut WriteContext) -> Result<R, Error>,
745    ) -> Result<R, Error> {
746        // SAFETY: Thread-local storage is only accessed from the current thread.
747        // We use UnsafeCell to avoid RefCell's runtime borrow checking overhead.
748        // The closure `f` does not recursively call with_write_context, so there's no aliasing.
749        WRITE_CONTEXTS.with(|cache| {
750            let cache = unsafe { &mut *cache.get() };
751            let id = self.id;
752
753            let context = cache.get_or_insert_result(id, || {
754                // Only fetch type resolver when creating a new context
755                let type_resolver = self.get_final_type_resolver()?;
756                Ok(Box::new(WriteContext::new(
757                    type_resolver.clone(),
758                    self.config.clone(),
759                )))
760            })?;
761            f(context)
762        })
763    }
764
765    /// Serializes a value of type `T` into a byte vector.
766    #[inline(always)]
767    fn serialize_with_context<T: Serializer>(
768        &self,
769        record: &T,
770        context: &mut WriteContext,
771    ) -> Result<(), Error> {
772        let result = self.serialize_with_context_inner::<T>(record, context);
773        context.reset();
774        result
775    }
776
777    #[inline(always)]
778    fn serialize_with_context_inner<T: Serializer>(
779        &self,
780        record: &T,
781        context: &mut WriteContext,
782    ) -> Result<(), Error> {
783        self.write_head::<T>(&mut context.writer);
784        // Use RefMode based on config:
785        // - If track_ref is enabled, use RefMode::Tracking for the root object
786        // - Otherwise, use RefMode::NullOnly which writes NOT_NULL_VALUE_FLAG
787        let ref_mode = if self.config.track_ref {
788            RefMode::Tracking
789        } else {
790            RefMode::NullOnly
791        };
792        // TypeMeta is written inline during serialization (streaming protocol)
793        <T as Serializer>::fory_write(record, context, ref_mode, true, false)?;
794        Ok(())
795    }
796
797    /// Registers a struct type with a numeric type ID for serialization.
798    ///
799    /// # Type Parameters
800    ///
801    /// * `T` - The struct type to register. Must implement `StructSerializer`, `Serializer`, and `ForyDefault`.
802    ///
803    /// # Arguments
804    ///
805    /// * `id` - A unique numeric identifier for the type. This ID is used in the serialized format
806    ///   to identify the type during deserialization.
807    ///
808    /// # Panics
809    ///
810    /// May panic if the type ID conflicts with an already registered type.
811    ///
812    /// # Examples
813    ///
814    /// ```rust, ignore
815    /// use fory::Fory;
816    /// use fory::{ForyEnum, ForyStruct, ForyUnion};
817    ///
818    /// #[derive(ForyStruct)]
819    /// struct User { name: String, age: u32 }
820    ///
821    /// let mut fory = Fory::builder().xlang(true).build();
822    /// fory.register::<User>(100).unwrap();
823    /// ```
824    pub fn register<T: 'static + StructSerializer + Serializer + ForyDefault>(
825        &mut self,
826        id: u32,
827    ) -> Result<(), Error> {
828        self.check_registration_allowed()?;
829        self.type_resolver.register::<T>(id)
830    }
831
832    /// Register a union type with a numeric type ID.
833    ///
834    /// This is intended for union-compatible enums generated by the compiler.
835    pub fn register_union<T: 'static + StructSerializer + Serializer + ForyDefault>(
836        &mut self,
837        id: u32,
838    ) -> Result<(), Error> {
839        self.check_registration_allowed()?;
840        self.type_resolver.register_union::<T>(id)
841    }
842
843    /// Registers a struct type with a qualified type name for xlang serialization.
844    ///
845    /// # Type Parameters
846    ///
847    /// * `T` - The struct type to register. Must implement `StructSerializer`, `Serializer`, and `ForyDefault`.
848    ///
849    /// # Arguments
850    ///
851    /// * `name` - The type name, optionally prefixed with a namespace separated by `.`.
852    ///   For example, `"com.example.User"` uses namespace `"com.example"` and type name `"User"`.
853    ///   Use `"User"` for the default namespace.
854    ///
855    /// # Notes
856    ///
857    /// This registration method is preferred for xlang serialization because it uses
858    /// human-readable type identifiers instead of numeric IDs, which improves compatibility
859    /// across different language implementations.
860    ///
861    /// # Examples
862    ///
863    /// The example uses xlang mode because name-based registration is the preferred
864    /// registration style for cross-language payloads.
865    ///
866    /// ```rust, ignore
867    /// use fory::Fory;
868    /// use fory::{ForyEnum, ForyStruct, ForyUnion};
869    ///
870    /// #[derive(ForyStruct)]
871    /// struct User { name: String, age: u32 }
872    ///
873    /// let mut fory = Fory::builder().xlang(true).build();
874    /// fory.register_by_name::<User>("com.example.User").unwrap();
875    /// ```
876    pub fn register_by_name<T: 'static + StructSerializer + Serializer + ForyDefault>(
877        &mut self,
878        name: &str,
879    ) -> Result<(), Error> {
880        self.check_registration_allowed()?;
881        self.type_resolver.register_by_name::<T>(name)
882    }
883
884    /// Register a union type with a qualified type name.
885    ///
886    /// This is intended for union-compatible enums generated by the compiler.
887    pub fn register_union_by_name<T: 'static + StructSerializer + Serializer + ForyDefault>(
888        &mut self,
889        name: &str,
890    ) -> Result<(), Error> {
891        self.check_registration_allowed()?;
892        self.type_resolver.register_union_by_name::<T>(name)
893    }
894
895    /// Registers a custom serializer type with a numeric type ID.
896    ///
897    /// # Type Parameters
898    ///
899    /// * `T` - The type to register. Must implement `Serializer` and `ForyDefault`.
900    ///   Unlike `register()`, this does not require `StructSerializer`, making it suitable
901    ///   for non-struct types or types with custom serialization logic.
902    ///
903    /// # Arguments
904    ///
905    /// * `id` - A unique numeric identifier for the type.
906    ///
907    /// # Use Cases
908    ///
909    /// Use this method to register:
910    /// - Enum types with custom serialization
911    /// - Wrapper types
912    /// - Types with hand-written `Serializer` implementations
913    ///
914    /// # Examples
915    ///
916    /// ```rust, ignore
917    /// use fory_core::Fory;
918    ///
919    /// let mut fory = Fory::builder().xlang(false).build();
920    /// fory.register_serializer::<MyCustomType>(200).unwrap();
921    /// ```
922    pub fn register_serializer<T: Serializer + ForyDefault>(
923        &mut self,
924        id: u32,
925    ) -> Result<(), Error> {
926        self.check_registration_allowed()?;
927        self.type_resolver.register_serializer::<T>(id)
928    }
929
930    /// Registers a custom serializer type with a qualified type name.
931    ///
932    /// # Type Parameters
933    ///
934    /// * `T` - The type to register. Must implement `Serializer` and `ForyDefault`.
935    ///
936    /// # Arguments
937    ///
938    /// * `name` - The type name, optionally prefixed with a namespace separated by `.`.
939    ///
940    /// # Notes
941    ///
942    /// This is the named equivalent of `register_serializer()`, preferred for
943    /// xlang serialization scenarios.
944    ///
945    pub fn register_serializer_by_name<T: Serializer + ForyDefault>(
946        &mut self,
947        name: &str,
948    ) -> Result<(), Error> {
949        self.check_registration_allowed()?;
950        self.type_resolver.register_serializer_by_name::<T>(name)
951    }
952
953    /// Writes the serialization header to the writer.
954    #[inline(always)]
955    pub fn write_head<T: Serializer>(&self, writer: &mut Writer) {
956        const HEAD_SIZE: usize = 10;
957        writer.reserve(T::fory_reserved_space() + SIZE_OF_REF_AND_TYPE + HEAD_SIZE);
958        let bitmap = if self.config.xlang {
959            IS_CROSS_LANGUAGE_FLAG
960        } else {
961            0
962        };
963        writer.write_u8(bitmap);
964    }
965
966    /// Deserializes data from a byte slice into a value of type `T`.
967    ///
968    /// # Type Parameters
969    ///
970    /// * `T` - The target type to deserialize into. Must implement `Serializer` and `ForyDefault`.
971    ///
972    /// # Arguments
973    ///
974    /// * `bf` - The byte slice containing the serialized data.
975    ///
976    /// # Returns
977    ///
978    /// * `Ok(T)` - The deserialized value on success.
979    /// * `Err(Error)` - An error if deserialization fails (e.g., invalid format, type mismatch).
980    ///
981    /// # Panics
982    ///
983    /// Panics in debug mode if there are unread bytes remaining after successful deserialization,
984    /// indicating a potential protocol violation.
985    ///
986    /// # Examples
987    ///
988    /// ```rust, ignore
989    /// use fory::Fory;
990    /// use fory::{ForyEnum, ForyStruct, ForyUnion};
991    ///
992    /// #[derive(ForyStruct)]
993    /// struct Point { x: i32, y: i32 }
994    ///
995    /// let mut fory = Fory::builder().xlang(true).build();
996    /// fory.register_by_name::<Point>("example.Point").unwrap();
997    /// let point = Point { x: 10, y: 20 };
998    /// let bytes = fory.serialize(&point).unwrap();
999    /// let deserialized: Point = fory.deserialize(&bytes).unwrap();
1000    /// ```
1001    pub fn deserialize<T: Serializer + ForyDefault>(&self, bf: &[u8]) -> Result<T, Error> {
1002        self.with_read_context(|context| {
1003            let outlive_buffer = unsafe { mem::transmute::<&[u8], &[u8]>(bf) };
1004            context.attach_reader(Reader::new(outlive_buffer));
1005            context.remaining_graph_memory_bytes = self.config.max_graph_memory_bytes;
1006            let result = self.deserialize_with_context(context);
1007            context.detach_reader();
1008            result
1009        })
1010    }
1011
1012    /// Deserializes data from a `Reader` into a value of type `T`.
1013    ///
1014    /// This method is the paired read operation for [`serialize_to`](Self::serialize_to).
1015    /// It reads serialized data from the current position of the reader and automatically
1016    /// advances the cursor to the end of the read data, making it suitable for reading
1017    /// multiple objects sequentially from the same buffer.
1018    ///
1019    /// # Type Parameters
1020    ///
1021    /// * `T` - The target type to deserialize into. Must implement `Serializer` and `ForyDefault`.
1022    ///
1023    /// # Arguments
1024    ///
1025    /// * `reader` - A mutable reference to the `Reader` containing the serialized data.
1026    ///   The reader's cursor will be advanced to the end of the deserialized data.
1027    ///
1028    /// # Returns
1029    ///
1030    /// * `Ok(T)` - The deserialized value on success.
1031    /// * `Err(Error)` - An error if deserialization fails (e.g., invalid format, type mismatch).
1032    ///
1033    /// # Notes
1034    ///
1035    /// - The reader's cursor is automatically updated after each successful read.
1036    /// - This method is ideal for reading multiple objects from the same buffer sequentially.
1037    /// - See [`serialize_to`](Self::serialize_to) for complete usage examples.
1038    ///
1039    /// # Examples
1040    ///
1041    /// Basic usage:
1042    ///
1043    /// ```rust, ignore
1044    /// use fory_core::{Fory, Reader};
1045    /// use fory_derive::{ForyEnum, ForyStruct, ForyUnion};
1046    ///
1047    /// #[derive(ForyStruct)]
1048    /// struct Point { x: i32, y: i32 }
1049    ///
1050    /// let mut fory = Fory::builder().xlang(true).build();
1051    /// fory.register_by_name::<Point>("example.Point").unwrap();
1052    /// let point = Point { x: 10, y: 20 };
1053    ///
1054    /// let mut buf = Vec::new();
1055    /// fory.serialize_to(&mut buf, &point).unwrap();
1056    ///
1057    /// let mut reader = Reader::new(&buf);
1058    /// let deserialized: Point = fory.deserialize_from(&mut reader).unwrap();
1059    /// ```
1060    pub fn deserialize_from<T: Serializer + ForyDefault>(
1061        &self,
1062        reader: &mut Reader,
1063    ) -> Result<T, Error> {
1064        self.with_read_context(|context| {
1065            let outlive_buffer = unsafe { mem::transmute::<&[u8], &[u8]>(reader.bf) };
1066            let mut new_reader = Reader::new(outlive_buffer);
1067            new_reader.set_cursor(reader.cursor);
1068            context.attach_reader(new_reader);
1069            context.remaining_graph_memory_bytes = self.config.max_graph_memory_bytes;
1070            let result = self.deserialize_with_context(context);
1071            let end = context.detach_reader().get_cursor();
1072            reader.set_cursor(end);
1073            result
1074        })
1075    }
1076
1077    /// Executes a closure with mutable access to a ReadContext for this Fory instance.
1078    /// The context is stored in thread-local storage, eliminating all lock contention.
1079    /// Uses fast path caching for O(1) access when using the same Fory instance repeatedly.
1080    #[inline(always)]
1081    fn with_read_context<R>(
1082        &self,
1083        f: impl FnOnce(&mut ReadContext) -> Result<R, Error>,
1084    ) -> Result<R, Error> {
1085        // SAFETY: Thread-local storage is only accessed from the current thread.
1086        // We use UnsafeCell to avoid RefCell's runtime borrow checking overhead.
1087        // The closure `f` does not recursively call with_read_context, so there's no aliasing.
1088        READ_CONTEXTS.with(|cache| {
1089            let cache = unsafe { &mut *cache.get() };
1090            let id = self.id;
1091
1092            let context = cache.get_or_insert_result(id, || {
1093                // Only fetch type resolver when creating a new context
1094                let type_resolver = self.get_final_type_resolver()?;
1095                Ok(Box::new(ReadContext::new(
1096                    type_resolver.clone(),
1097                    self.config.clone(),
1098                )))
1099            })?;
1100            f(context)
1101        })
1102    }
1103
1104    #[inline(always)]
1105    fn deserialize_with_context<T: Serializer + ForyDefault>(
1106        &self,
1107        context: &mut ReadContext,
1108    ) -> Result<T, Error> {
1109        let result = self.deserialize_with_context_inner::<T>(context);
1110        context.reset();
1111        result
1112    }
1113
1114    #[inline(always)]
1115    fn deserialize_with_context_inner<T: Serializer + ForyDefault>(
1116        &self,
1117        context: &mut ReadContext,
1118    ) -> Result<T, Error> {
1119        self.read_head(&mut context.reader)?;
1120        // Use RefMode based on config:
1121        // - If track_ref is enabled, use RefMode::Tracking for the root object
1122        // - Otherwise, use RefMode::NullOnly
1123        let ref_mode = if self.config.track_ref {
1124            RefMode::Tracking
1125        } else {
1126            RefMode::NullOnly
1127        };
1128        let result = <T as Serializer>::fory_read(context, ref_mode, true);
1129        context.ref_reader.resolve_callbacks();
1130        result
1131    }
1132
1133    #[inline(always)]
1134    fn read_head(&self, reader: &mut Reader) -> Result<(), Error> {
1135        let bitmap = reader.read_u8()?;
1136        let expected = if self.config.xlang {
1137            IS_CROSS_LANGUAGE_FLAG
1138        } else {
1139            0
1140        };
1141        if bitmap != expected {
1142            return self.read_head_slow(bitmap, expected);
1143        }
1144        Ok(())
1145    }
1146
1147    #[cold]
1148    #[inline(never)]
1149    fn read_head_slow(&self, bitmap: u8, expected: u8) -> Result<(), Error> {
1150        const KNOWN_FLAGS: u8 = IS_CROSS_LANGUAGE_FLAG | IS_OUT_OF_BAND_FLAG;
1151        ensure!(
1152            (bitmap & !KNOWN_FLAGS) == 0 && (bitmap & IS_OUT_OF_BAND_FLAG) == 0,
1153            Error::invalid_data("unsupported root header bitmap")
1154        );
1155        ensure!(
1156            (bitmap & IS_CROSS_LANGUAGE_FLAG) == (expected & IS_CROSS_LANGUAGE_FLAG),
1157            Error::invalid_data("header bitmap mismatch at xlang bit")
1158        );
1159        Ok(())
1160    }
1161}
1162
1163#[cfg(test)]
1164mod tests {
1165    use super::Fory;
1166
1167    #[test]
1168    fn compatible_defaults_and_overrides() {
1169        let default_xlang = Fory::builder().xlang(true).finish_config();
1170        let default_native = Fory::builder().xlang(false).finish_config();
1171        let explicit_same_schema = Fory::builder()
1172            .compatible(false)
1173            .xlang(true)
1174            .finish_config();
1175        let explicit_same_schema_reverse_order = Fory::builder()
1176            .xlang(true)
1177            .compatible(false)
1178            .finish_config();
1179
1180        assert!(default_xlang.compatible);
1181        assert!(default_xlang.share_meta);
1182        assert!(!default_xlang.check_struct_version);
1183        assert!(default_native.compatible);
1184        assert!(default_native.share_meta);
1185        assert!(!default_native.check_struct_version);
1186
1187        assert!(!explicit_same_schema.compatible);
1188        assert!(!explicit_same_schema.share_meta);
1189        assert!(explicit_same_schema.check_struct_version);
1190        assert!(!explicit_same_schema_reverse_order.compatible);
1191        assert!(!explicit_same_schema_reverse_order.share_meta);
1192        assert!(explicit_same_schema_reverse_order.check_struct_version);
1193    }
1194}