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