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