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}