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