This is an automated email from the ASF dual-hosted git repository.

chaokunyang pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/fory-site.git


The following commit(s) were added to refs/heads/main by this push:
     new 00516ab2c8 πŸ”„ synced local 'docs/guide/' with remote 'docs/guide/'
00516ab2c8 is described below

commit 00516ab2c8578c22e13b5ff5ac50d20106e3503c
Author: chaokunyang <[email protected]>
AuthorDate: Thu Jun 4 08:00:03 2026 +0000

    πŸ”„ synced local 'docs/guide/' with remote 'docs/guide/'
---
 docs/guide/rust/custom-serializers.md   | 39 ++++++++++++++++++++++------
 docs/guide/rust/native-serialization.md |  5 +++-
 docs/guide/rust/polymorphism.md         | 46 ++++++++++++++++++++++++++++++---
 docs/guide/rust/schema-evolution.md     | 18 +++++++------
 4 files changed, 88 insertions(+), 20 deletions(-)

diff --git a/docs/guide/rust/custom-serializers.md 
b/docs/guide/rust/custom-serializers.md
index c3c5e8f90e..e5c273e0ab 100644
--- a/docs/guide/rust/custom-serializers.md
+++ b/docs/guide/rust/custom-serializers.md
@@ -31,7 +31,7 @@ For types that don't support `#[derive(ForyStruct)]`, 
implement the `Serializer`
 ## Implementing the Serializer Trait
 
 ```rust
-use fory::{Fory, ReadContext, WriteContext, Serializer, ForyDefault, Error};
+use fory::{Error, Fory, ForyDefault, ReadContext, Serializer, TypeResolver, 
WriteContext};
 use std::any::Any;
 
 #[derive(Debug, PartialEq, Default)]
@@ -41,20 +41,21 @@ struct CustomType {
 }
 
 impl Serializer for CustomType {
-    fn fory_write_data(&self, context: &mut WriteContext, is_field: bool) {
+    fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> 
{
         context.writer.write_i32(self.value);
-        context.writer.write_varuint32(self.name.len() as u32);
+        context.writer.write_var_u32(self.name.len() as u32);
         context.writer.write_utf8_string(&self.name);
+        Ok(())
     }
 
-    fn fory_read_data(context: &mut ReadContext, is_field: bool) -> 
Result<Self, Error> {
-        let value = context.reader.read_i32();
-        let len = context.reader.read_varuint32() as usize;
-        let name = context.reader.read_utf8_string(len);
+    fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
+        let value = context.reader.read_i32()?;
+        let len = context.reader.read_var_u32()? as usize;
+        let name = context.reader.read_utf8_string(len)?;
         Ok(Self { value, name })
     }
 
-    fn fory_type_id_dyn(&self, type_resolver: &TypeResolver) -> u32 {
+    fn fory_type_id_dyn(&self, type_resolver: &TypeResolver) -> 
Result<fory::TypeId, Error> {
         Self::fory_get_type_id(type_resolver)
     }
 
@@ -76,6 +77,28 @@ impl ForyDefault for CustomType {
 >
 > **Tip**: If your type supports `#[derive(ForyStruct)]`, you can use 
 > `#[fory(generate_default)]` to automatically generate both `ForyDefault` and 
 > `Default` implementations.
 
+## Manual Serializers and Arc Any
+
+If a manually registered serializer needs its type to round-trip behind
+`Arc<dyn Any + Send + Sync>` or preserve `UnknownCase` payloads, implement the
+send-sync Any reader and return the concrete value as a boxed `Any` value:
+
+```rust
+impl Serializer for CustomType {
+    fn fory_read_data_as_send_sync_any(
+        context: &mut ReadContext,
+    ) -> Result<Box<dyn Any + Send + Sync>, Error> {
+        Ok(Box::new(Self::fory_read_data(context)?))
+    }
+
+    // Implement the ordinary Serializer methods as shown above.
+    // ...
+}
+```
+
+Do not override this method for values that contain fields whose types are not
+`Send + Sync`, such as `Rc<T>`, `RcWeak<T>`, `RefCell<T>`, or `Cell<T>`.
+
 ## Registering Custom Serializers
 
 ```rust
diff --git a/docs/guide/rust/native-serialization.md 
b/docs/guide/rust/native-serialization.md
index e2bf6e74f4..133b022b93 100644
--- a/docs/guide/rust/native-serialization.md
+++ b/docs/guide/rust/native-serialization.md
@@ -100,7 +100,10 @@ Native serialization owns the Rust-specific object surface:
 - `Box<T>`, `Rc<T>`, `Arc<T>`, `RcWeak<T>`, and `ArcWeak<T>`.
 - `RefCell<T>` and `Mutex<T>`.
 - Trait objects such as `Box<dyn Trait>`, `Rc<dyn Trait>`, and `Arc<dyn 
Trait>`.
-- Runtime type dispatch with `Rc<dyn Any>` and `Arc<dyn Any + Send + Sync>`.
+- Runtime type dispatch with `Box<dyn Any>`, `Rc<dyn Any>`, and
+  `Arc<dyn Any + Send + Sync>` for registered non-container payloads. Wrap
+  containers in registered structs, enums, or unions before using them behind
+  erased `Any` carriers.
 - Date and time carriers, including optional `chrono` support.
 
 Use [Basic Serialization](basic-serialization.md), 
[References](references.md), and
diff --git a/docs/guide/rust/polymorphism.md b/docs/guide/rust/polymorphism.md
index fa87735edd..de8547c1b7 100644
--- a/docs/guide/rust/polymorphism.md
+++ b/docs/guide/rust/polymorphism.md
@@ -85,12 +85,12 @@ assert_eq!(decoded.star_animal.speak(), "Woof!");
 
 ## Serializing dyn Any Trait Objects
 
-Apache Foryβ„’ supports serializing `Rc<dyn Any>` and
+Apache Foryβ„’ supports serializing `Box<dyn Any>`, `Rc<dyn Any>`, and
 `Arc<dyn Any + Send + Sync>` for runtime type dispatch:
 
 **Key points:**
 
-- Works with any type that implements `Serializer`
+- Works with registered concrete non-container types that implement 
`Serializer`
 - Requires downcasting after deserialization to access the concrete type
 - Type information is preserved during serialization
 - Useful for plugin systems and dynamic type handling
@@ -132,6 +132,46 @@ let unwrapped = decoded.downcast_ref::<Dog>().unwrap();
 assert_eq!(unwrapped.name, "Buddy");
 ```
 
+`Box<dyn Any>`, `Rc<dyn Any>`, and `Arc<dyn Any + Send + Sync>` are supported
+erased `Any` carriers for registered concrete non-container payloads.
+Use `Arc<dyn Any + Send + Sync>` when the erased payload must be shareable
+across threads; the concrete payload type must also satisfy `Send + Sync`.
+Registered structs, enums, and unions that satisfy those bounds can be used as
+the erased payload.
+
+The unsupported case is a generic container used directly as the top-level
+erased payload. This applies to all erased `Any` carriers: `Box<dyn Any>`,
+`Rc<dyn Any>`, and `Arc<dyn Any + Send + Sync>`. Unsupported direct payloads
+include list-, map-, and set-like containers such as `Vec<T>`, `Vec<u8>`,
+`HashMap<K, V>`, `HashSet<T>`, and `LinkedList<T>`.
+
+If you need to put a container in an erased `Any` payload, wrap it in a
+registered struct, enum, or union and use that wrapper as the erased payload:
+
+```rust
+use fory::{Fory, ForyStruct};
+use std::any::Any;
+use std::sync::Arc;
+
+#[derive(ForyStruct)]
+struct IntList {
+    values: Vec<i32>,
+}
+
+let mut fory = Fory::builder().xlang(false).build();
+fory.register::<IntList>(100)?;
+
+let value: Arc<dyn Any + Send + Sync> = Arc::new(IntList {
+    values: vec![1, 2, 3],
+});
+let bytes = fory.serialize(&value)?;
+let decoded: Arc<dyn Any + Send + Sync> = fory.deserialize(&bytes)?;
+```
+
+The wrapper makes the erased payload a concrete registered type while the
+container remains a normal typed field. The same wrapper model is the supported
+path for `Box<dyn Any>` and `Rc<dyn Any>`.
+
 ## Rc/Arc-Based Trait Objects in Structs
 
 For fields with `Rc<dyn Trait>` or `Arc<dyn Trait>`, Fory automatically 
handles the conversion:
@@ -180,7 +220,7 @@ assert_eq!(decoded.animals_arc[0].speak(), "Woof!");
 
 Due to Rust's orphan rule, `Rc<dyn Trait>` and `Arc<dyn Trait>` cannot 
implement `Serializer` directly. For standalone serialization (not inside 
struct fields), the `register_trait_type!` macro generates wrapper types.
 
-**Note:** If you don't want to use wrapper types, you can serialize as `Rc<dyn 
Any>` or `Arc<dyn Any + Send + Sync>` instead (see the dyn Any section above).
+**Note:** If you don't want to use wrapper types for concrete non-container 
payloads, you can serialize as `Box<dyn Any>`, `Rc<dyn Any>`, or `Arc<dyn Any + 
Send + Sync>` instead (see the dyn Any section above).
 
 The `register_trait_type!` macro generates `AnimalRc` and `AnimalArc` wrapper 
types:
 
diff --git a/docs/guide/rust/schema-evolution.md 
b/docs/guide/rust/schema-evolution.md
index 2766641ca9..14c536afc4 100644
--- a/docs/guide/rust/schema-evolution.md
+++ b/docs/guide/rust/schema-evolution.md
@@ -129,14 +129,16 @@ let decoded: Value = fory.deserialize(&bytes)?;
 assert_eq!(value, decoded);
 ```
 
-For typed ADT unions whose schema cases are unit or single-payload variants,
-`#[fory(unknown)] Unknown(::fory::UnknownCase)` is only the runtime
-forward-compatibility carrier. It cannot be the default variant, and the union
-must include at least one real schema case. The marker only selects the carrier
-and does not add an entry to the schema case table; schema cases use
-non-negative IDs. `UnknownCase` stores its payload as
-`Arc<dyn Any + Send + Sync>`, so locally registered future payload types must 
be
-thread-safe to be preserved as unknown cases.
+For typed ADT unions whose cases are unit or single-payload variants, add an
+`#[fory(unknown)] Unknown(::fory::UnknownCase)` variant when you need to
+preserve future payload variants. Do not make the unknown variant the default;
+keep a real schema case marked `#[fory(default)]`. Register future payload 
types
+locally before deserializing unknown cases you need to preserve.
+
+`UnknownCase` stores its payload as `Arc<dyn Any + Send + Sync>`, so preserved
+payload types must satisfy `Send + Sync`. Direct generic containers are not
+supported as erased `Any` payloads; wrap the container in a registered derived
+type if an unknown case needs to preserve it.
 
 ### Enum Schema Evolution
 


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to