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.git


The following commit(s) were added to refs/heads/main by this push:
     new 0ec7261e8 refactor(rust): refactor sync send type (#3737)
0ec7261e8 is described below

commit 0ec7261e83833867f977b95da25c24d9c678be7e
Author: Shawn Yang <[email protected]>
AuthorDate: Thu Jun 4 15:49:08 2026 +0800

    refactor(rust): refactor sync send type (#3737)
    
    ## Why?
    
    
    
    ## What does this PR do?
    
    
    
    ## Related issues
    
    #3732
    #3736
    
    ## AI Contribution Checklist
    
    
    
    - [ ] Substantial AI assistance was used in this PR: `yes` / `no`
    - [ ] If `yes`, I included a completed [AI Contribution
    
Checklist](https://github.com/apache/fory/blob/main/AI_POLICY.md#9-contributor-checklist-for-ai-assisted-prs)
    in this PR description and the required `AI Usage Disclosure`.
    - [ ] If `yes`, my PR description includes the required `ai_review`
    summary and screenshot evidence of the final clean AI review results
    from both fresh reviewers on the current PR diff or current HEAD after
    the latest code changes.
    
    
    
    ## Does this PR introduce any user-facing change?
    
    
    
    - [ ] Does this PR introduce any public API change?
    - [ ] Does this PR introduce any binary protocol compatibility change?
    
    ## Benchmark
---
 AGENTS.md                                        |   4 +-
 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 +-
 rust/README.md                                   |  12 +
 rust/fory-core/src/error.rs                      |  12 +
 rust/fory-core/src/fory.rs                       |  10 -
 rust/fory-core/src/resolver/type_resolver.rs     | 123 +++-----
 rust/fory-core/src/serializer/any.rs             | 176 +++++++----
 rust/fory-core/src/serializer/arc.rs             |  11 +-
 rust/fory-core/src/serializer/bool.rs            |  11 +
 rust/fory-core/src/serializer/core.rs            | 197 +-----------
 rust/fory-core/src/serializer/datetime.rs        |  66 ++++
 rust/fory-core/src/serializer/decimal.rs         |  11 +
 rust/fory-core/src/serializer/mod.rs             |   7 +-
 rust/fory-core/src/serializer/number.rs          |  33 ++
 rust/fory-core/src/serializer/string.rs          |  11 +
 rust/fory-core/src/serializer/tuple.rs           |  11 +
 rust/fory-core/src/serializer/unknown_case.rs    |  13 +-
 rust/fory-core/src/serializer/unsigned_number.rs |  22 ++
 rust/fory-core/src/serializer/util.rs            |  12 +
 rust/fory-core/src/types/unknown_case.rs         |   2 +-
 rust/fory-derive/src/lib.rs                      |   7 +
 rust/fory-derive/src/object/field_codec.rs       |   2 +-
 rust/fory-derive/src/object/serializer.rs        |  48 ++-
 rust/fory-derive/src/object/util.rs              |  12 +-
 rust/fory/src/lib.rs                             |  31 +-
 rust/tests/tests/test_any.rs                     | 342 ++++++++++++++++++---
 rust/tests/tests/test_collection.rs              |   9 +-
 rust/tests/tests/test_enum.rs                    |   2 +-
 rust/tests/tests/test_lifecycle_guard.rs         |  13 -
 rust/tests/tests/test_send_sync.rs               | 365 +++++++++++++++++++++++
 rust/tests/tests/test_trait_object.rs            |  87 ++++--
 rust/tests/tests/test_unsigned.rs                | 101 +++++--
 35 files changed, 1328 insertions(+), 543 deletions(-)

diff --git a/AGENTS.md b/AGENTS.md
index d6d7d31af..aca7ebaec 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -68,7 +68,9 @@ This is the entry point for AI guidance in Apache Fory. Read 
this file first, th
 - User guide docs must explain user-visible behavior, commands, and examples.
   Do not add implementation details, internal ownership rationale, build flags,
   or type-id-space caveats unless they directly clarify a confusion users can
-  act on.
+  act on. Translate internal owner-model details into concrete user actions, 
and
+  avoid phrases such as "serializer-owned capability" or "registration alone
+  does not..." in user-facing docs.
 - Add comments only when behavior is hard to understand or an algorithm is 
non-obvious.
 - Do not remove existing code comments unless they are stale, misleading, 
redundant, or no longer necessary after the change.
 - Only add tests that verify internal behaviors or fix specific bugs; do not 
create unnecessary tests unless requested.
diff --git a/docs/guide/rust/custom-serializers.md 
b/docs/guide/rust/custom-serializers.md
index c3c5e8f90..e5c273e0a 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 e2bf6e74f..133b022b9 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 fa87735ed..de8547c1b 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 2766641ca..14c536afc 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
 
diff --git a/rust/README.md b/rust/README.md
index dd9ea0708..8f238c0ce 100644
--- a/rust/README.md
+++ b/rust/README.md
@@ -251,6 +251,18 @@ The examples in this section use native mode because Rust 
trait objects and `dyn
 - `Box<dyn Any>`/`Rc<dyn Any>`/`Arc<dyn Any + Send + Sync>` - Any trait type 
objects
 - `Vec<Box<dyn Trait>>`, `HashMap<K, Box<dyn Trait>>` - Collections of trait 
objects
 
+`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.
+Generic containers such as `Vec<T>`, `HashMap<K, V>`, `HashSet<T>`, and
+`LinkedList<T>` are not supported directly as top-level erased `Any` payloads
+behind any of those carriers. This also includes primitive vector encodings 
such
+as `Vec<u8>`. Wrap the container in a registered derived type when it needs to
+travel behind an erased `Any` carrier.
+
 **Basic Trait Object Serialization Example:**
 
 ```rust
diff --git a/rust/fory-core/src/error.rs b/rust/fory-core/src/error.rs
index c12a9f751..9311a8a4a 100644
--- a/rust/fory-core/src/error.rs
+++ b/rust/fory-core/src/error.rs
@@ -552,6 +552,18 @@ impl Error {
     }
 }
 
+#[cold]
+#[inline(never)]
+pub(crate) fn unsupported_send_sync_type<T>() -> Error
+where
+    T: ?Sized,
+{
+    Error::type_error(format!(
+        "{} cannot be represented as Arc<dyn Any + Send + Sync>",
+        std::any::type_name::<T>()
+    ))
+}
+
 /// Ensures a condition is true; otherwise returns an [`enum@Error`].
 ///
 /// # Examples
diff --git a/rust/fory-core/src/fory.rs b/rust/fory-core/src/fory.rs
index 2b9b7f621..4a491616b 100644
--- a/rust/fory-core/src/fory.rs
+++ b/rust/fory-core/src/fory.rs
@@ -954,16 +954,6 @@ impl Fory {
             .register_serializer_by_name::<T>(namespace, type_name)
     }
 
-    /// Registers a generic trait object type for serialization.
-    /// This method should be used to register collection types such as 
`Vec<T>`, `HashMap<K, V>`, etc.
-    /// Don't register concrete struct types with this method. Use 
`register()` instead.
-    pub fn register_generic_trait<T: 'static + Serializer + ForyDefault>(
-        &mut self,
-    ) -> Result<(), Error> {
-        self.check_registration_allowed()?;
-        self.type_resolver.register_generic_trait::<T>()
-    }
-
     /// Writes the serialization header to the writer.
     #[inline(always)]
     pub fn write_head<T: Serializer>(&self, writer: &mut Writer) {
diff --git a/rust/fory-core/src/resolver/type_resolver.rs 
b/rust/fory-core/src/resolver/type_resolver.rs
index bb9ae8e53..3a5c9968b 100644
--- a/rust/fory-core/src/resolver/type_resolver.rs
+++ b/rust/fory-core/src/resolver/type_resolver.rs
@@ -28,7 +28,6 @@ use crate::types::{Date, Duration, Timestamp};
 use crate::TypeId;
 #[cfg(feature = "chrono")]
 use chrono::{Duration as ChronoDuration, NaiveDate, NaiveDateTime};
-use std::collections::{HashSet, LinkedList};
 use std::rc::Rc;
 use std::vec;
 
@@ -63,9 +62,9 @@ type ReadFn =
 
 type WriteDataFn = fn(&dyn Any, &mut WriteContext, has_generics: bool) -> 
Result<(), Error>;
 type ReadDataFn = fn(&mut ReadContext) -> Result<Box<dyn Any>, Error>;
-type ReadDataSendSyncFn = fn(&mut ReadContext) -> Result<Box<dyn Any + Send + 
Sync>, Error>;
+type ReadDataAsSendSyncAnyFn = fn(&mut ReadContext) -> Result<Box<dyn Any + 
Send + Sync>, Error>;
 type ReadCompatibleFn = fn(&mut ReadContext, Rc<TypeInfo>) -> Result<Box<dyn 
Any>, Error>;
-type ReadCompatibleSendSyncFn =
+type ReadCompatibleAsSendSyncAnyFn =
     fn(&mut ReadContext, Rc<TypeInfo>) -> Result<Box<dyn Any + Send + Sync>, 
Error>;
 type ToSerializerFn = fn(Box<dyn Any>) -> Result<Box<dyn Serializer>, Error>;
 type BuildTypeInfosFn = fn(&TypeResolver) -> Result<Vec<(std::any::TypeId, 
TypeInfo)>, Error>;
@@ -90,10 +89,9 @@ pub struct Harness {
     read_fn: ReadFn,
     write_data_fn: WriteDataFn,
     read_data_fn: ReadDataFn,
-    read_data_send_sync_fn: ReadDataSendSyncFn,
+    read_data_as_send_sync_any_fn: ReadDataAsSendSyncAnyFn,
     read_compatible_fn: Option<ReadCompatibleFn>,
-    read_compatible_send_sync_fn: Option<ReadCompatibleSendSyncFn>,
-    threadsafe: bool,
+    read_compatible_as_send_sync_any_fn: Option<ReadCompatibleAsSendSyncAnyFn>,
     to_serializer: ToSerializerFn,
     build_type_infos: BuildTypeInfosFn,
 }
@@ -105,10 +103,9 @@ impl Harness {
             read_fn: stub_read_fn,
             write_data_fn: stub_write_data_fn,
             read_data_fn: stub_read_data_fn,
-            read_data_send_sync_fn: stub_read_data_send_sync_fn,
+            read_data_as_send_sync_any_fn: stub_read_data_as_send_sync_any_fn,
             read_compatible_fn: None,
-            read_compatible_send_sync_fn: None,
-            threadsafe: false,
+            read_compatible_as_send_sync_any_fn: None,
             to_serializer: stub_to_serializer_fn,
             build_type_infos: stub_build_type_infos,
         }
@@ -166,23 +163,17 @@ impl Harness {
     /// This path never upgrades an ordinary `Box<dyn Any>`; it delegates to
     /// type-owned readers that construct the send-sync trait object directly.
     #[inline(always)]
-    pub fn read_polymorphic_data_send_sync(
+    pub fn read_polymorphic_data_as_send_sync_any(
         &self,
         context: &mut ReadContext,
         typeinfo: &Rc<TypeInfo>,
     ) -> Result<Box<dyn Any + Send + Sync>, Error> {
-        if !self.threadsafe {
-            return Err(Error::type_error(format!(
-                "{}::{} cannot be represented as Arc<dyn Any + Send + Sync>",
-                typeinfo.namespace.original, typeinfo.type_name.original
-            )));
-        }
         if context.is_compatible() {
-            if let Some(read_compatible_fn) = 
self.read_compatible_send_sync_fn {
+            if let Some(read_compatible_fn) = 
self.read_compatible_as_send_sync_any_fn {
                 return read_compatible_fn(context, typeinfo.clone());
             }
         }
-        (self.read_data_send_sync_fn)(context)
+        (self.read_data_as_send_sync_any_fn)(context)
     }
 }
 
@@ -331,10 +322,9 @@ impl TypeInfo {
                 read_fn: stub_read_fn,
                 write_data_fn: stub_write_data_fn,
                 read_data_fn: stub_read_data_fn,
-                read_data_send_sync_fn: stub_read_data_send_sync_fn,
+                read_data_as_send_sync_any_fn: 
stub_read_data_as_send_sync_any_fn,
                 read_compatible_fn: None,
-                read_compatible_send_sync_fn: None,
-                threadsafe: false,
+                read_compatible_as_send_sync_any_fn: None,
                 to_serializer: stub_to_serializer_fn,
                 build_type_infos: stub_build_type_infos,
             }
@@ -384,7 +374,9 @@ fn stub_read_data_fn(_: &mut ReadContext) -> Result<Box<dyn 
Any>, Error> {
     ))
 }
 
-fn stub_read_data_send_sync_fn(_: &mut ReadContext) -> Result<Box<dyn Any + 
Send + Sync>, Error> {
+fn stub_read_data_as_send_sync_any_fn(
+    _: &mut ReadContext,
+) -> Result<Box<dyn Any + Send + Sync>, Error> {
     Err(Error::type_error(
         "Cannot deserialize unknown remote type as Arc<dyn Any + Send + Sync> 
- type not registered locally",
     ))
@@ -826,15 +818,6 @@ impl TypeResolver {
         self.register_internal_serializer::<Vec<u128>>(TypeId::U128_ARRAY)?;
         self.register_internal_serializer::<Vec<isize>>(TypeId::ISIZE_ARRAY)?;
         self.register_internal_serializer::<Vec<i128>>(TypeId::INT128_ARRAY)?;
-        self.register_generic_trait::<Vec<String>>()?;
-        self.register_generic_trait::<LinkedList<i32>>()?;
-        self.register_generic_trait::<LinkedList<String>>()?;
-        self.register_generic_trait::<HashSet<String>>()?;
-        self.register_generic_trait::<HashSet<i32>>()?;
-        self.register_generic_trait::<HashSet<i64>>()?;
-        self.register_generic_trait::<HashMap<String, String>>()?;
-        self.register_generic_trait::<HashMap<String, i32>>()?;
-        self.register_generic_trait::<HashMap<String, i64>>()?;
 
         Ok(())
     }
@@ -914,6 +897,13 @@ impl TypeResolver {
         } else {
             id
         };
+        let supports_compatible_read = matches!(
+            actual_type_id,
+            x if x == TypeId::STRUCT as u32
+                || x == TypeId::COMPATIBLE_STRUCT as u32
+                || x == TypeId::NAMED_STRUCT as u32
+                || x == TypeId::NAMED_COMPATIBLE_STRUCT as u32
+        );
 
         fn write<T2: 'static + Serializer>(
             this: &dyn Any,
@@ -966,18 +956,10 @@ impl TypeResolver {
             }
         }
 
-        fn read_data_send_sync<T2: 'static + Serializer + ForyDefault>(
+        fn read_data_as_send_sync_any<T2: 'static + Serializer + ForyDefault>(
             context: &mut ReadContext,
         ) -> Result<Box<dyn Any + Send + Sync>, Error> {
-            if T2::fory_is_threadsafe_type() {
-                T2::fory_read_data_send_sync(context)
-            } else if crate::serializer::is_known_threadsafe_static_type_id(
-                T2::fory_static_type_id(),
-            ) {
-                crate::serializer::read_known_threadsafe_data::<T2>(context)
-            } else {
-                Err(crate::serializer::unsupported_threadsafe_type::<T2>())
-            }
+            T2::fory_read_data_as_send_sync_any(context)
         }
 
         fn to_serializer<T2: 'static + Serializer>(
@@ -1002,11 +984,11 @@ impl TypeResolver {
             Ok(Box::new(T2::fory_read_compatible(context, type_info)?))
         }
 
-        fn read_compatible_send_sync<T2: 'static + StructSerializer + 
ForyDefault>(
+        fn read_compatible_as_send_sync_any<T2: 'static + StructSerializer + 
ForyDefault>(
             context: &mut ReadContext,
             type_info: Rc<TypeInfo>,
         ) -> Result<Box<dyn Any + Send + Sync>, Error> {
-            T2::fory_read_compatible_send_sync(context, type_info)
+            T2::fory_read_compatible_as_send_sync_any(context, type_info)
         }
 
         let harness = Harness {
@@ -1014,11 +996,17 @@ impl TypeResolver {
             read_fn: read::<T>,
             write_data_fn: write_data::<T>,
             read_data_fn: read_data::<T>,
-            read_data_send_sync_fn: read_data_send_sync::<T>,
-            read_compatible_fn: Some(read_compatible::<T>),
-            read_compatible_send_sync_fn: Some(read_compatible_send_sync::<T>),
-            threadsafe: T::fory_is_threadsafe_type()
-                || 
crate::serializer::is_known_threadsafe_static_type_id(T::fory_static_type_id()),
+            read_data_as_send_sync_any_fn: read_data_as_send_sync_any::<T>,
+            read_compatible_fn: if supports_compatible_read {
+                Some(read_compatible::<T>)
+            } else {
+                None
+            },
+            read_compatible_as_send_sync_any_fn: if supports_compatible_read {
+                Some(read_compatible_as_send_sync_any::<T>)
+            } else {
+                None
+            },
             to_serializer: to_serializer::<T>,
             build_type_infos: build_type_infos::<T>,
         };
@@ -1212,18 +1200,10 @@ impl TypeResolver {
             }
         }
 
-        fn read_data_send_sync<T2: 'static + Serializer + ForyDefault>(
+        fn read_data_as_send_sync_any<T2: 'static + Serializer + ForyDefault>(
             context: &mut ReadContext,
         ) -> Result<Box<dyn Any + Send + Sync>, Error> {
-            if T2::fory_is_threadsafe_type() {
-                T2::fory_read_data_send_sync(context)
-            } else if crate::serializer::is_known_threadsafe_static_type_id(
-                T2::fory_static_type_id(),
-            ) {
-                crate::serializer::read_known_threadsafe_data::<T2>(context)
-            } else {
-                Err(crate::serializer::unsupported_threadsafe_type::<T2>())
-            }
+            T2::fory_read_data_as_send_sync_any(context)
         }
 
         fn to_serializer<T2: 'static + Serializer>(
@@ -1256,11 +1236,9 @@ impl TypeResolver {
             read_fn: read::<T>,
             write_data_fn: write_data::<T>,
             read_data_fn: read_data::<T>,
-            read_data_send_sync_fn: read_data_send_sync::<T>,
+            read_data_as_send_sync_any_fn: read_data_as_send_sync_any::<T>,
             read_compatible_fn: None,
-            read_compatible_send_sync_fn: None,
-            threadsafe: T::fory_is_threadsafe_type()
-                || 
crate::serializer::is_known_threadsafe_static_type_id(T::fory_static_type_id()),
+            read_compatible_as_send_sync_any_fn: None,
             to_serializer: to_serializer::<T>,
             build_type_infos: build_type_infos::<T>,
         };
@@ -1319,27 +1297,6 @@ impl TypeResolver {
         Ok(())
     }
 
-    /// Register a generic trait type like List, Map, Set
-    pub fn register_generic_trait<T: 'static + Serializer + ForyDefault>(
-        &mut self,
-    ) -> Result<(), Error> {
-        let rs_type_id = std::any::TypeId::of::<T>();
-        if self.type_info_map.contains_key(&rs_type_id) {
-            return Err(Error::type_error(format!(
-                "Type:{:?} already registered",
-                rs_type_id
-            )));
-        }
-        let type_id = T::fory_static_type_id();
-        if type_id != TypeId::LIST && type_id != TypeId::MAP && type_id != 
TypeId::SET {
-            return Err(Error::not_allowed(format!(
-                "register_generic_trait can only be used for generic trait 
types: List, Map, Set, but got type {}",
-                type_id as u32
-            )));
-        }
-        self.register_internal_serializer::<T>(type_id)
-    }
-
     pub(crate) fn set_compatible(&mut self, compatible: bool) {
         self.compatible = compatible;
     }
diff --git a/rust/fory-core/src/serializer/any.rs 
b/rust/fory-core/src/serializer/any.rs
index e4e9067be..e63bf698c 100644
--- a/rust/fory-core/src/serializer/any.rs
+++ b/rust/fory-core/src/serializer/any.rs
@@ -37,24 +37,91 @@ fn resolve_registered_type_id(
         .ok_or_else(|| Error::type_error("Type not registered"))
 }
 
-/// Check if the type info represents a generic container type (LIST, SET, 
MAP).
-/// These types cannot be deserialized polymorphically via `Box<dyn Any>` 
because
-/// different generic instantiations (e.g., `Vec<A>`, `Vec<B>`) share the same 
type ID.
 #[inline]
-pub(crate) fn check_generic_container_type(type_info: &TypeInfo) -> Result<(), 
Error> {
-    let type_id = type_info.get_type_id();
-    if type_id == TypeId::LIST || type_id == TypeId::SET || type_id == 
TypeId::MAP {
-        return Err(Error::type_error(
-            "Cannot deserialize generic container types (Vec, HashSet, 
HashMap) polymorphically \
-            via Box<dyn Any>, Rc<dyn Any>, or Arc<dyn Any + Send + Sync>. The 
serialization protocol does not preserve the element type \
-            information needed to distinguish between different generic 
instantiations \
-            (e.g., Vec<StructA> vs Vec<StructB>). Consider wrapping the 
container in a \
-            named struct type instead.",
-        ));
+fn is_erased_any_container_type(type_id: TypeId) -> bool {
+    matches!(
+        type_id,
+        TypeId::LIST
+            | TypeId::SET
+            | TypeId::MAP
+            | TypeId::BINARY
+            | TypeId::ARRAY
+            | TypeId::BOOL_ARRAY
+            | TypeId::INT8_ARRAY
+            | TypeId::INT16_ARRAY
+            | TypeId::INT32_ARRAY
+            | TypeId::INT64_ARRAY
+            | TypeId::UINT8_ARRAY
+            | TypeId::UINT16_ARRAY
+            | TypeId::UINT32_ARRAY
+            | TypeId::UINT64_ARRAY
+            | TypeId::FLOAT8_ARRAY
+            | TypeId::FLOAT16_ARRAY
+            | TypeId::BFLOAT16_ARRAY
+            | TypeId::FLOAT32_ARRAY
+            | TypeId::FLOAT64_ARRAY
+            | TypeId::U128_ARRAY
+            | TypeId::INT128_ARRAY
+            | TypeId::USIZE_ARRAY
+            | TypeId::ISIZE_ARRAY
+    )
+}
+
+#[cold]
+#[inline(never)]
+fn unsupported_erased_any_container() -> Error {
+    Error::type_error(
+        "List-, map-, and set-like containers cannot be used as top-level 
erased Any \
+        payloads via Box<dyn Any>, Rc<dyn Any>, or Arc<dyn Any + Send + Sync>. 
This \
+        includes Vec<T>, byte and numeric vectors, LinkedList<T>, HashSet<T>, 
and \
+        HashMap<K, V>. Wrap the container in a registered struct, enum, or 
union and \
+        use that wrapper as the erased payload.",
+    )
+}
+
+#[cold]
+#[inline(never)]
+fn erased_any_type_info_error(err: Error) -> Error {
+    Error::type_error(format!(
+        "{err}. Erased Any payloads require a registered concrete 
non-container type. \
+        Top-level list-, map-, and set-like containers such as Vec<T>, 
LinkedList<T>, \
+        HashSet<T>, and HashMap<K, V> are unsupported; wrap the container in a 
\
+        registered struct, enum, or union."
+    ))
+}
+
+#[inline]
+pub(crate) fn check_erased_any_payload_type(type_info: &TypeInfo) -> 
Result<(), Error> {
+    if is_erased_any_container_type(type_info.get_type_id()) {
+        return Err(unsupported_erased_any_container());
     }
     Ok(())
 }
 
+#[inline]
+fn get_erased_any_type_info(
+    context: &WriteContext,
+    concrete_type_id: &std::any::TypeId,
+) -> Result<Rc<TypeInfo>, Error> {
+    let type_info = context
+        .get_type_info(concrete_type_id)
+        .map_err(erased_any_type_info_error)?;
+    check_erased_any_payload_type(&type_info)?;
+    Ok(type_info)
+}
+
+#[inline]
+fn write_erased_any_type_info(
+    context: &mut WriteContext,
+    concrete_type_id: std::any::TypeId,
+) -> Result<Rc<TypeInfo>, Error> {
+    let type_info = context
+        .write_any_type_info(TypeId::UNKNOWN as u32, concrete_type_id)
+        .map_err(erased_any_type_info_error)?;
+    check_erased_any_payload_type(&type_info)?;
+    Ok(type_info)
+}
+
 /// Helper function to deserialize to `Box<dyn Any>`
 pub fn deserialize_any_box(context: &mut ReadContext) -> Result<Box<dyn Any>, 
Error> {
     context.inc_depth()?;
@@ -63,8 +130,7 @@ pub fn deserialize_any_box(context: &mut ReadContext) -> 
Result<Box<dyn Any>, Er
         return Err(Error::invalid_ref("Expected NotNullValue for Box<dyn 
Any>"));
     }
     let typeinfo = context.read_any_type_info()?;
-    // Check for generic container types which cannot be deserialized 
polymorphically
-    check_generic_container_type(&typeinfo)?;
+    check_erased_any_payload_type(&typeinfo)?;
     let result = typeinfo
         .get_harness()
         .read_polymorphic_data(context, &typeinfo);
@@ -101,7 +167,7 @@ impl Serializer for Box<dyn Any> {
         has_generics: bool,
     ) -> Result<(), Error> {
         let concrete_type_id = (**self).type_id();
-        let typeinfo = context.get_type_info(&concrete_type_id)?;
+        let typeinfo = get_erased_any_type_info(context, &concrete_type_id)?;
         let serializer_fn = typeinfo.get_harness().get_write_data_fn();
         serializer_fn(&**self, context, has_generics)
     }
@@ -131,7 +197,7 @@ impl Serializer for Box<dyn Any> {
 
     fn fory_read_data(_: &mut ReadContext) -> Result<Self, Error> {
         Err(Error::not_allowed(
-            "fory_read_data should not be called directly on polymorphic 
Rc<dyn Any> trait object",
+            "fory_read_data should not be called directly on polymorphic 
Box<dyn Any> trait object",
         ))
     }
 
@@ -188,9 +254,9 @@ pub fn write_box_any(
     }
     let concrete_type_id = value.type_id();
     let typeinfo = if write_type_info {
-        context.write_any_type_info(TypeId::UNKNOWN as u32, concrete_type_id)?
+        write_erased_any_type_info(context, concrete_type_id)?
     } else {
-        context.get_type_info(&concrete_type_id)?
+        get_erased_any_type_info(context, &concrete_type_id)?
     };
     let serializer_fn = typeinfo.get_harness().get_write_data_fn();
     serializer_fn(value, context, has_generics)
@@ -222,8 +288,7 @@ pub fn read_box_any(
         );
         context.read_any_type_info()?
     };
-    // Check for generic container types which cannot be deserialized 
polymorphically
-    check_generic_container_type(&typeinfo)?;
+    check_erased_any_payload_type(&typeinfo)?;
     let result = typeinfo
         .get_harness()
         .read_polymorphic_data(context, &typeinfo);
@@ -251,16 +316,12 @@ impl Serializer for Rc<dyn Any> {
                 .try_write_rc_ref(&mut context.writer, self)
         {
             let concrete_type_id: std::any::TypeId = (**self).type_id();
-            let write_data_fn = if write_type_info {
-                let typeinfo =
-                    context.write_any_type_info(TypeId::UNKNOWN as u32, 
concrete_type_id)?;
-                typeinfo.get_harness().get_write_data_fn()
+            let typeinfo = if write_type_info {
+                write_erased_any_type_info(context, concrete_type_id)?
             } else {
-                context
-                    .get_type_info(&concrete_type_id)?
-                    .get_harness()
-                    .get_write_data_fn()
+                get_erased_any_type_info(context, &concrete_type_id)?
             };
+            let write_data_fn = typeinfo.get_harness().get_write_data_fn();
             write_data_fn(&**self, context, has_generics)?;
         }
         Ok(())
@@ -298,10 +359,9 @@ impl Serializer for Rc<dyn Any> {
     }
 
     fn fory_read_data(_: &mut ReadContext) -> Result<Self, Error> {
-        Err(Error::not_allowed(format!(
-            "fory_read_data should not be called directly on polymorphic 
Rc<dyn {}> trait object",
-            stringify!($trait_name)
-        )))
+        Err(Error::not_allowed(
+            "fory_read_data should not be called directly on polymorphic 
Rc<dyn Any> trait object",
+        ))
     }
 
     fn fory_get_type_id(_: &TypeResolver) -> Result<TypeId, Error> {
@@ -321,14 +381,6 @@ impl Serializer for Rc<dyn Any> {
     fn fory_is_shared_ref() -> bool {
         true
     }
-
-    fn fory_is_threadsafe_type() -> bool
-    where
-        Self: Sized,
-    {
-        true
-    }
-
     fn fory_is_polymorphic() -> bool {
         true
     }
@@ -381,8 +433,7 @@ pub fn read_rc_any(
             } else {
                 type_info.ok_or_else(|| Error::type_error("No type info found 
for read"))?
             };
-            // Check for generic container types which cannot be deserialized 
polymorphically
-            check_generic_container_type(&typeinfo)?;
+            check_erased_any_payload_type(&typeinfo)?;
             let boxed = typeinfo
                 .get_harness()
                 .read_polymorphic_data(context, &typeinfo)?;
@@ -390,20 +441,20 @@ pub fn read_rc_any(
             Ok(Rc::<dyn Any>::from(boxed))
         }
         RefFlag::RefValue => {
+            let ref_id = context.ref_reader.reserve_ref_id();
             context.inc_depth()?;
             let typeinfo = if read_type_info {
                 context.read_any_type_info()?
             } else {
                 type_info.ok_or_else(|| Error::type_error("No type info found 
for read"))?
             };
-            // Check for generic container types which cannot be deserialized 
polymorphically
-            check_generic_container_type(&typeinfo)?;
+            check_erased_any_payload_type(&typeinfo)?;
             let boxed = typeinfo
                 .get_harness()
                 .read_polymorphic_data(context, &typeinfo)?;
             context.dec_depth();
             let rc: Rc<dyn Any> = Rc::from(boxed);
-            context.ref_reader.store_rc_ref(rc.clone());
+            context.ref_reader.store_rc_ref_at(ref_id, rc.clone());
             Ok(rc)
         }
     }
@@ -430,18 +481,13 @@ impl Serializer for Arc<dyn Any + Send + Sync> {
         {
             let value: &dyn Any = self.as_ref();
             let concrete_type_id: std::any::TypeId = value.type_id();
-            if write_type_info {
-                let typeinfo =
-                    context.write_any_type_info(TypeId::UNKNOWN as u32, 
concrete_type_id)?;
-                let serializer_fn = typeinfo.get_harness().get_write_data_fn();
-                serializer_fn(value, context, has_generics)?;
+            let typeinfo = if write_type_info {
+                write_erased_any_type_info(context, concrete_type_id)?
             } else {
-                let serializer_fn = context
-                    .get_type_info(&concrete_type_id)?
-                    .get_harness()
-                    .get_write_data_fn();
-                serializer_fn(value, context, has_generics)?;
-            }
+                get_erased_any_type_info(context, &concrete_type_id)?
+            };
+            let serializer_fn = typeinfo.get_harness().get_write_data_fn();
+            serializer_fn(value, context, has_generics)?;
         }
         Ok(())
     }
@@ -504,7 +550,6 @@ impl Serializer for Arc<dyn Any + Send + Sync> {
     fn fory_is_shared_ref() -> bool {
         true
     }
-
     fn fory_static_type_id() -> TypeId {
         TypeId::UNKNOWN
     }
@@ -519,7 +564,7 @@ impl Serializer for Arc<dyn Any + Send + Sync> {
         Ok(())
     }
 
-    fn fory_read_data_send_sync(
+    fn fory_read_data_as_send_sync_any(
         context: &mut ReadContext,
     ) -> Result<Box<dyn Any + Send + Sync>, Error>
     where
@@ -574,15 +619,15 @@ pub fn read_arc_any(
                     Error::type_error("No type info found for read Arc<dyn Any 
+ Send + Sync>")
                 })?
             };
-            // Check for generic container types which cannot be deserialized 
polymorphically
-            check_generic_container_type(&typeinfo)?;
+            check_erased_any_payload_type(&typeinfo)?;
             let boxed = typeinfo
                 .get_harness()
-                .read_polymorphic_data_send_sync(context, &typeinfo)?;
+                .read_polymorphic_data_as_send_sync_any(context, &typeinfo)?;
             context.dec_depth();
             Ok(Arc::<dyn Any + Send + Sync>::from(boxed))
         }
         RefFlag::RefValue => {
+            let ref_id = context.ref_reader.reserve_ref_id();
             context.inc_depth()?;
             let typeinfo = if read_type_info {
                 context.read_any_type_info()?
@@ -591,14 +636,13 @@ pub fn read_arc_any(
                     Error::type_error("No type info found for read Arc<dyn Any 
+ Send + Sync>")
                 })?
             };
-            // Check for generic container types which cannot be deserialized 
polymorphically
-            check_generic_container_type(&typeinfo)?;
+            check_erased_any_payload_type(&typeinfo)?;
             let boxed = typeinfo
                 .get_harness()
-                .read_polymorphic_data_send_sync(context, &typeinfo)?;
+                .read_polymorphic_data_as_send_sync_any(context, &typeinfo)?;
             context.dec_depth();
             let arc: Arc<dyn Any + Send + Sync> = Arc::from(boxed);
-            context.ref_reader.store_arc_ref(arc.clone());
+            context.ref_reader.store_arc_ref_at(ref_id, arc.clone());
             Ok(arc)
         }
     }
diff --git a/rust/fory-core/src/serializer/arc.rs 
b/rust/fory-core/src/serializer/arc.rs
index 5535dc706..1e69ae15c 100644
--- a/rust/fory-core/src/serializer/arc.rs
+++ b/rust/fory-core/src/serializer/arc.rs
@@ -28,15 +28,6 @@ impl<T: Serializer + ForyDefault + Send + Sync + 'static> 
Serializer for Arc<T>
     fn fory_is_shared_ref() -> bool {
         true
     }
-
-    #[inline(always)]
-    fn fory_is_threadsafe_type() -> bool
-    where
-        Self: Sized,
-    {
-        true
-    }
-
     fn fory_write(
         &self,
         context: &mut WriteContext,
@@ -129,7 +120,7 @@ impl<T: Serializer + ForyDefault + Send + Sync + 'static> 
Serializer for Arc<T>
     }
 
     #[inline]
-    fn fory_read_data_send_sync(
+    fn fory_read_data_as_send_sync_any(
         context: &mut ReadContext,
     ) -> Result<Box<dyn std::any::Any + Send + Sync>, Error>
     where
diff --git a/rust/fory-core/src/serializer/bool.rs 
b/rust/fory-core/src/serializer/bool.rs
index 09307e168..dcc7bfbfd 100644
--- a/rust/fory-core/src/serializer/bool.rs
+++ b/rust/fory-core/src/serializer/bool.rs
@@ -35,6 +35,17 @@ impl Serializer for bool {
     fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
         Ok(context.reader.read_u8()? == 1)
     }
+    #[inline]
+    fn fory_read_data_as_send_sync_any(
+        context: &mut ReadContext,
+    ) -> Result<Box<dyn std::any::Any + Send + Sync>, Error>
+    where
+        Self: Sized + ForyDefault,
+    {
+        Ok(crate::serializer::box_send_sync(Self::fory_read_data(
+            context,
+        )?))
+    }
 
     #[inline(always)]
     fn fory_reserved_space() -> usize {
diff --git a/rust/fory-core/src/serializer/core.rs 
b/rust/fory-core/src/serializer/core.rs
index 25a9f0c94..2f155792d 100644
--- a/rust/fory-core/src/serializer/core.rs
+++ b/rust/fory-core/src/serializer/core.rs
@@ -890,33 +890,20 @@ pub trait Serializer: 'static {
     where
         Self: Sized + ForyDefault;
 
-    /// Whether this serialized value can be safely represented behind
-    /// `Arc<dyn Any + Send + Sync>` after a dynamic read.
-    ///
-    /// The default is conservative. Implementations should return true only
-    /// when the concrete value produced by this serializer is `Send + Sync`.
-    #[inline(always)]
-    fn fory_is_threadsafe_type() -> bool
-    where
-        Self: Sized,
-    {
-        false
-    }
-
-    /// Deserialize data for dynamic thread-safe carriers.
+    /// Deserialize data for dynamic send-sync carriers.
     ///
     /// This method must construct the `Box<dyn Any + Send + Sync>` from the
     /// concrete value before it is erased as `dyn Any`. It must never try to
     /// upgrade a `Box<dyn Any>` returned by the ordinary dynamic read path.
     #[inline(always)]
-    fn fory_read_data_send_sync(
+    fn fory_read_data_as_send_sync_any(
         context: &mut ReadContext,
     ) -> Result<Box<dyn Any + Send + Sync>, Error>
     where
         Self: Sized + ForyDefault,
     {
         let _ = context;
-        Err(unsupported_threadsafe_type::<Self>())
+        Err(crate::error::unsupported_send_sync_type::<Self>())
     }
 
     /// Read and validate type metadata from the buffer.
@@ -1467,12 +1454,12 @@ pub trait StructSerializer: Serializer + 'static {
     where
         Self: Sized;
 
-    /// Deserialize compatible data for dynamic thread-safe carriers.
+    /// Deserialize compatible data for dynamic send-sync carriers.
     ///
     /// Implementations are generated only when the resulting struct/enum is
     /// known to be `Send + Sync`.
     #[inline(always)]
-    fn fory_read_compatible_send_sync(
+    fn fory_read_compatible_as_send_sync_any(
         context: &mut ReadContext,
         type_info: Rc<TypeInfo>,
     ) -> Result<Box<dyn Any + Send + Sync>, Error>
@@ -1481,7 +1468,7 @@ pub trait StructSerializer: Serializer + 'static {
     {
         let _ = context;
         let _ = type_info;
-        Err(unsupported_threadsafe_type::<Self>())
+        Err(crate::error::unsupported_send_sync_type::<Self>())
     }
 }
 
@@ -1502,175 +1489,3 @@ pub fn write_data<T: Serializer>(this: &T, context: 
&mut WriteContext) -> Result
 pub fn read_data<T: Serializer + ForyDefault>(context: &mut ReadContext) -> 
Result<T, Error> {
     T::fory_read_data(context)
 }
-
-#[inline(always)]
-pub fn box_send_sync<T>(value: T) -> Box<dyn Any + Send + Sync>
-where
-    T: Any + Send + Sync,
-{
-    Box::new(value)
-}
-
-#[inline(always)]
-pub(crate) fn is_known_threadsafe_static_type_id(type_id: TypeId) -> bool {
-    matches!(
-        type_id,
-        TypeId::NONE
-            | TypeId::BOOL
-            | TypeId::INT8
-            | TypeId::INT16
-            | TypeId::INT32
-            | TypeId::VARINT32
-            | TypeId::INT64
-            | TypeId::VARINT64
-            | TypeId::TAGGED_INT64
-            | TypeId::UINT8
-            | TypeId::UINT16
-            | TypeId::UINT32
-            | TypeId::VAR_UINT32
-            | TypeId::UINT64
-            | TypeId::VAR_UINT64
-            | TypeId::TAGGED_UINT64
-            | TypeId::FLOAT16
-            | TypeId::BFLOAT16
-            | TypeId::FLOAT32
-            | TypeId::FLOAT64
-            | TypeId::STRING
-            | TypeId::DURATION
-            | TypeId::TIMESTAMP
-            | TypeId::DATE
-            | TypeId::DECIMAL
-            | TypeId::BINARY
-            | TypeId::BOOL_ARRAY
-            | TypeId::INT8_ARRAY
-            | TypeId::INT16_ARRAY
-            | TypeId::INT32_ARRAY
-            | TypeId::INT64_ARRAY
-            | TypeId::UINT8_ARRAY
-            | TypeId::UINT16_ARRAY
-            | TypeId::UINT32_ARRAY
-            | TypeId::UINT64_ARRAY
-            | TypeId::FLOAT16_ARRAY
-            | TypeId::BFLOAT16_ARRAY
-            | TypeId::FLOAT32_ARRAY
-            | TypeId::FLOAT64_ARRAY
-            | TypeId::U128
-            | TypeId::INT128
-            | TypeId::USIZE
-            | TypeId::ISIZE
-            | TypeId::U128_ARRAY
-            | TypeId::INT128_ARRAY
-            | TypeId::USIZE_ARRAY
-            | TypeId::ISIZE_ARRAY
-    )
-}
-
-pub(crate) fn read_known_threadsafe_data<T>(
-    context: &mut ReadContext,
-) -> Result<Box<dyn Any + Send + Sync>, Error>
-where
-    T: Serializer + ForyDefault,
-{
-    let boxed: Box<dyn Any> = Box::new(T::fory_read_data(context)?);
-    box_known_threadsafe_data(T::fory_static_type_id(), boxed)
-}
-
-#[cold]
-#[inline(never)]
-fn unexpected_threadsafe_type_id(type_id: TypeId) -> Error {
-    Error::type_error(format!(
-        "deserialized value did not match thread-safe static type id {:?}",
-        type_id
-    ))
-}
-
-macro_rules! downcast_threadsafe_data {
-    ($boxed:expr, $type_id:expr, $ty:ty) => {
-        $boxed
-            .downcast::<$ty>()
-            .map(|value| value as Box<dyn Any + Send + Sync>)
-            .map_err(|_| unexpected_threadsafe_type_id($type_id))
-    };
-}
-
-fn box_known_threadsafe_data(
-    type_id: TypeId,
-    boxed: Box<dyn Any>,
-) -> Result<Box<dyn Any + Send + Sync>, Error> {
-    match type_id {
-        TypeId::NONE => downcast_threadsafe_data!(boxed, type_id, ()),
-        TypeId::BOOL => downcast_threadsafe_data!(boxed, type_id, bool),
-        TypeId::INT8 => downcast_threadsafe_data!(boxed, type_id, i8),
-        TypeId::INT16 => downcast_threadsafe_data!(boxed, type_id, i16),
-        TypeId::INT32 | TypeId::VARINT32 => downcast_threadsafe_data!(boxed, 
type_id, i32),
-        TypeId::INT64 | TypeId::VARINT64 | TypeId::TAGGED_INT64 => {
-            downcast_threadsafe_data!(boxed, type_id, i64)
-        }
-        TypeId::UINT8 => downcast_threadsafe_data!(boxed, type_id, u8),
-        TypeId::UINT16 => downcast_threadsafe_data!(boxed, type_id, u16),
-        TypeId::UINT32 | TypeId::VAR_UINT32 => 
downcast_threadsafe_data!(boxed, type_id, u32),
-        TypeId::UINT64 | TypeId::VAR_UINT64 | TypeId::TAGGED_UINT64 => {
-            downcast_threadsafe_data!(boxed, type_id, u64)
-        }
-        TypeId::FLOAT16 => {
-            downcast_threadsafe_data!(boxed, type_id, 
crate::types::float16::float16)
-        }
-        TypeId::BFLOAT16 => {
-            downcast_threadsafe_data!(boxed, type_id, 
crate::types::bfloat16::bfloat16)
-        }
-        TypeId::FLOAT32 => downcast_threadsafe_data!(boxed, type_id, f32),
-        TypeId::FLOAT64 => downcast_threadsafe_data!(boxed, type_id, f64),
-        TypeId::STRING => downcast_threadsafe_data!(boxed, type_id, String),
-        TypeId::DURATION => downcast_threadsafe_data!(boxed, type_id, 
crate::types::Duration),
-        TypeId::TIMESTAMP => downcast_threadsafe_data!(boxed, type_id, 
crate::types::Timestamp),
-        TypeId::DATE => downcast_threadsafe_data!(boxed, type_id, 
crate::types::Date),
-        TypeId::DECIMAL => downcast_threadsafe_data!(boxed, type_id, 
crate::types::Decimal),
-        TypeId::BINARY | TypeId::UINT8_ARRAY => 
downcast_threadsafe_data!(boxed, type_id, Vec<u8>),
-        TypeId::BOOL_ARRAY => downcast_threadsafe_data!(boxed, type_id, 
Vec<bool>),
-        TypeId::INT8_ARRAY => downcast_threadsafe_data!(boxed, type_id, 
Vec<i8>),
-        TypeId::INT16_ARRAY => downcast_threadsafe_data!(boxed, type_id, 
Vec<i16>),
-        TypeId::INT32_ARRAY => downcast_threadsafe_data!(boxed, type_id, 
Vec<i32>),
-        TypeId::INT64_ARRAY => downcast_threadsafe_data!(boxed, type_id, 
Vec<i64>),
-        TypeId::UINT16_ARRAY => downcast_threadsafe_data!(boxed, type_id, 
Vec<u16>),
-        TypeId::UINT32_ARRAY => downcast_threadsafe_data!(boxed, type_id, 
Vec<u32>),
-        TypeId::UINT64_ARRAY => downcast_threadsafe_data!(boxed, type_id, 
Vec<u64>),
-        TypeId::FLOAT16_ARRAY => {
-            downcast_threadsafe_data!(boxed, type_id, 
Vec<crate::types::float16::float16>)
-        }
-        TypeId::BFLOAT16_ARRAY => {
-            downcast_threadsafe_data!(boxed, type_id, 
Vec<crate::types::bfloat16::bfloat16>)
-        }
-        TypeId::FLOAT32_ARRAY => downcast_threadsafe_data!(boxed, type_id, 
Vec<f32>),
-        TypeId::FLOAT64_ARRAY => downcast_threadsafe_data!(boxed, type_id, 
Vec<f64>),
-        TypeId::U128 => downcast_threadsafe_data!(boxed, type_id, u128),
-        TypeId::INT128 => downcast_threadsafe_data!(boxed, type_id, i128),
-        TypeId::USIZE => downcast_threadsafe_data!(boxed, type_id, usize),
-        TypeId::ISIZE => downcast_threadsafe_data!(boxed, type_id, isize),
-        TypeId::U128_ARRAY => downcast_threadsafe_data!(boxed, type_id, 
Vec<u128>),
-        TypeId::INT128_ARRAY => downcast_threadsafe_data!(boxed, type_id, 
Vec<i128>),
-        TypeId::USIZE_ARRAY => downcast_threadsafe_data!(boxed, type_id, 
Vec<usize>),
-        TypeId::ISIZE_ARRAY => downcast_threadsafe_data!(boxed, type_id, 
Vec<isize>),
-        _ => Err(unsupported_threadsafe_type_id(type_id)),
-    }
-}
-
-#[cold]
-#[inline(never)]
-pub(crate) fn unsupported_threadsafe_type_id(type_id: TypeId) -> Error {
-    Error::type_error(format!(
-        "{:?} cannot be represented as Arc<dyn Any + Send + Sync>",
-        type_id
-    ))
-}
-
-#[cold]
-#[inline(never)]
-pub fn unsupported_threadsafe_type<T>() -> Error
-where
-    T: ?Sized,
-{
-    Error::type_error(format!(
-        "{} cannot be represented as Arc<dyn Any + Send + Sync>",
-        std::any::type_name::<T>()
-    ))
-}
diff --git a/rust/fory-core/src/serializer/datetime.rs 
b/rust/fory-core/src/serializer/datetime.rs
index dec6eaddb..3edb169b3 100644
--- a/rust/fory-core/src/serializer/datetime.rs
+++ b/rust/fory-core/src/serializer/datetime.rs
@@ -40,6 +40,17 @@ impl Serializer for Timestamp {
         let nanos = context.reader.read_u32()?;
         Timestamp::new(seconds, nanos)
     }
+    #[inline]
+    fn fory_read_data_as_send_sync_any(
+        context: &mut ReadContext,
+    ) -> Result<Box<dyn std::any::Any + Send + Sync>, Error>
+    where
+        Self: Sized + ForyDefault,
+    {
+        Ok(crate::serializer::box_send_sync(Self::fory_read_data(
+            context,
+        )?))
+    }
 
     #[inline(always)]
     fn fory_reserved_space() -> usize {
@@ -109,6 +120,17 @@ impl Serializer for Date {
         };
         Ok(Date::from_epoch_days(days))
     }
+    #[inline]
+    fn fory_read_data_as_send_sync_any(
+        context: &mut ReadContext,
+    ) -> Result<Box<dyn std::any::Any + Send + Sync>, Error>
+    where
+        Self: Sized + ForyDefault,
+    {
+        Ok(crate::serializer::box_send_sync(Self::fory_read_data(
+            context,
+        )?))
+    }
 
     #[inline(always)]
     fn fory_reserved_space() -> usize {
@@ -168,6 +190,17 @@ impl Serializer for Duration {
         let nanos = context.reader.read_i32()?;
         Duration::new(seconds, nanos)
     }
+    #[inline]
+    fn fory_read_data_as_send_sync_any(
+        context: &mut ReadContext,
+    ) -> Result<Box<dyn std::any::Any + Send + Sync>, Error>
+    where
+        Self: Sized + ForyDefault,
+    {
+        Ok(crate::serializer::box_send_sync(Self::fory_read_data(
+            context,
+        )?))
+    }
 
     #[inline(always)]
     fn fory_reserved_space() -> usize {
@@ -228,6 +261,17 @@ mod chrono_support {
         fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
             Timestamp::fory_read_data(context)?.try_into()
         }
+        #[inline]
+        fn fory_read_data_as_send_sync_any(
+            context: &mut ReadContext,
+        ) -> Result<Box<dyn std::any::Any + Send + Sync>, Error>
+        where
+            Self: Sized + ForyDefault,
+        {
+            Ok(crate::serializer::box_send_sync(Self::fory_read_data(
+                context,
+            )?))
+        }
 
         #[inline(always)]
         fn fory_reserved_space() -> usize {
@@ -282,6 +326,17 @@ mod chrono_support {
         fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
             Date::fory_read_data(context)?.try_into()
         }
+        #[inline]
+        fn fory_read_data_as_send_sync_any(
+            context: &mut ReadContext,
+        ) -> Result<Box<dyn std::any::Any + Send + Sync>, Error>
+        where
+            Self: Sized + ForyDefault,
+        {
+            Ok(crate::serializer::box_send_sync(Self::fory_read_data(
+                context,
+            )?))
+        }
 
         #[inline(always)]
         fn fory_reserved_space() -> usize {
@@ -336,6 +391,17 @@ mod chrono_support {
         fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
             Duration::fory_read_data(context)?.try_into()
         }
+        #[inline]
+        fn fory_read_data_as_send_sync_any(
+            context: &mut ReadContext,
+        ) -> Result<Box<dyn std::any::Any + Send + Sync>, Error>
+        where
+            Self: Sized + ForyDefault,
+        {
+            Ok(crate::serializer::box_send_sync(Self::fory_read_data(
+                context,
+            )?))
+        }
 
         #[inline(always)]
         fn fory_reserved_space() -> usize {
diff --git a/rust/fory-core/src/serializer/decimal.rs 
b/rust/fory-core/src/serializer/decimal.rs
index 4775df108..0c1f88ece 100644
--- a/rust/fory-core/src/serializer/decimal.rs
+++ b/rust/fory-core/src/serializer/decimal.rs
@@ -39,6 +39,17 @@ impl Serializer for Decimal {
         let unscaled = read_decimal_unscaled(&mut context.reader)?;
         Ok(Self { unscaled, scale })
     }
+    #[inline]
+    fn fory_read_data_as_send_sync_any(
+        context: &mut ReadContext,
+    ) -> Result<Box<dyn std::any::Any + Send + Sync>, Error>
+    where
+        Self: Sized + ForyDefault,
+    {
+        Ok(crate::serializer::box_send_sync(Self::fory_read_data(
+            context,
+        )?))
+    }
 
     #[inline(always)]
     fn fory_get_type_id(_: &TypeResolver) -> Result<TypeId, Error> {
diff --git a/rust/fory-core/src/serializer/mod.rs 
b/rust/fory-core/src/serializer/mod.rs
index 5de0bc095..5e18880c3 100644
--- a/rust/fory-core/src/serializer/mod.rs
+++ b/rust/fory-core/src/serializer/mod.rs
@@ -50,8 +50,5 @@ pub mod weak;
 mod core;
 mod decimal;
 pub use any::{read_box_any, write_box_any};
-pub use core::{
-    box_send_sync, read_data, unsupported_threadsafe_type, write_data, 
ForyDefault, Serializer,
-    StructSerializer,
-};
-pub(crate) use core::{is_known_threadsafe_static_type_id, 
read_known_threadsafe_data};
+pub use core::{read_data, write_data, ForyDefault, Serializer, 
StructSerializer};
+pub use util::send_sync::box_send_sync;
diff --git a/rust/fory-core/src/serializer/number.rs 
b/rust/fory-core/src/serializer/number.rs
index d42d4b219..ebdb83a1f 100644
--- a/rust/fory-core/src/serializer/number.rs
+++ b/rust/fory-core/src/serializer/number.rs
@@ -40,6 +40,17 @@ macro_rules! impl_num_serializer {
             fn fory_read_data(context: &mut ReadContext) -> Result<Self, 
Error> {
                 $reader(&mut context.reader)
             }
+            #[inline]
+            fn fory_read_data_as_send_sync_any(
+                context: &mut ReadContext,
+            ) -> Result<Box<dyn std::any::Any + Send + Sync>, Error>
+            where
+                Self: Sized + ForyDefault,
+            {
+                Ok(crate::serializer::box_send_sync(Self::fory_read_data(
+                    context,
+                )?))
+            }
 
             #[inline(always)]
             fn fory_reserved_space() -> usize {
@@ -114,6 +125,17 @@ impl Serializer for float16 {
     fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
         Reader::read_f16(&mut context.reader)
     }
+    #[inline]
+    fn fory_read_data_as_send_sync_any(
+        context: &mut ReadContext,
+    ) -> Result<Box<dyn std::any::Any + Send + Sync>, Error>
+    where
+        Self: Sized + ForyDefault,
+    {
+        Ok(crate::serializer::box_send_sync(Self::fory_read_data(
+            context,
+        )?))
+    }
     #[inline(always)]
     fn fory_reserved_space() -> usize {
         std::mem::size_of::<float16>()
@@ -162,6 +184,17 @@ impl Serializer for bfloat16 {
     fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
         Reader::read_bf16(&mut context.reader)
     }
+    #[inline]
+    fn fory_read_data_as_send_sync_any(
+        context: &mut ReadContext,
+    ) -> Result<Box<dyn std::any::Any + Send + Sync>, Error>
+    where
+        Self: Sized + ForyDefault,
+    {
+        Ok(crate::serializer::box_send_sync(Self::fory_read_data(
+            context,
+        )?))
+    }
     #[inline(always)]
     fn fory_reserved_space() -> usize {
         std::mem::size_of::<bfloat16>()
diff --git a/rust/fory-core/src/serializer/string.rs 
b/rust/fory-core/src/serializer/string.rs
index abbb82d93..79771fd0c 100644
--- a/rust/fory-core/src/serializer/string.rs
+++ b/rust/fory-core/src/serializer/string.rs
@@ -66,6 +66,17 @@ impl Serializer for String {
         }?;
         Ok(s)
     }
+    #[inline]
+    fn fory_read_data_as_send_sync_any(
+        context: &mut ReadContext,
+    ) -> Result<Box<dyn std::any::Any + Send + Sync>, Error>
+    where
+        Self: Sized + ForyDefault,
+    {
+        Ok(crate::serializer::box_send_sync(Self::fory_read_data(
+            context,
+        )?))
+    }
 
     #[inline(always)]
     fn fory_reserved_space() -> usize {
diff --git a/rust/fory-core/src/serializer/tuple.rs 
b/rust/fory-core/src/serializer/tuple.rs
index a0789a906..bbda7383b 100644
--- a/rust/fory-core/src/serializer/tuple.rs
+++ b/rust/fory-core/src/serializer/tuple.rs
@@ -38,6 +38,17 @@ impl Serializer for () {
         // Unit type has no data to read
         Ok(())
     }
+    #[inline]
+    fn fory_read_data_as_send_sync_any(
+        context: &mut ReadContext,
+    ) -> Result<Box<dyn std::any::Any + Send + Sync>, Error>
+    where
+        Self: Sized + ForyDefault,
+    {
+        Ok(crate::serializer::box_send_sync(Self::fory_read_data(
+            context,
+        )?))
+    }
 
     #[inline(always)]
     fn fory_reserved_space() -> usize {
diff --git a/rust/fory-core/src/serializer/unknown_case.rs 
b/rust/fory-core/src/serializer/unknown_case.rs
index 7423f384e..15a658a82 100644
--- a/rust/fory-core/src/serializer/unknown_case.rs
+++ b/rust/fory-core/src/serializer/unknown_case.rs
@@ -18,7 +18,7 @@
 use crate::context::{ReadContext, WriteContext};
 use crate::error::Error;
 use crate::resolver::{RefFlag, RefMode};
-use crate::serializer::any::check_generic_container_type;
+use crate::serializer::any::check_erased_any_payload_type;
 use crate::serializer::{ForyDefault, Serializer};
 use crate::type_id::{self, TypeId};
 use crate::types::UnknownCase;
@@ -154,10 +154,10 @@ pub fn read_payload(context: &mut ReadContext, case_id: 
u32) -> Result<UnknownCa
             // boundary by itself, and real nested payload serializers perform 
their
             // own depth checks.
             let type_info = context.read_any_type_info()?;
-            check_generic_container_type(&type_info)?;
+            check_erased_any_payload_type(&type_info)?;
             let boxed = type_info
                 .get_harness()
-                .read_polymorphic_data_send_sync(context, &type_info)?;
+                .read_polymorphic_data_as_send_sync_any(context, &type_info)?;
             let value: Arc<dyn std::any::Any + Send + Sync> = Arc::from(boxed);
             if let Some(ref_id) = ref_id {
                 context.ref_reader.store_arc_ref_at(ref_id, value.clone());
@@ -207,12 +207,7 @@ impl Serializer for UnknownCase {
     fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
         read_payload(context, 0)
     }
-
-    fn fory_is_threadsafe_type() -> bool {
-        true
-    }
-
-    fn fory_read_data_send_sync(
+    fn fory_read_data_as_send_sync_any(
         context: &mut ReadContext,
     ) -> Result<Box<dyn Any + Send + Sync>, Error> {
         Ok(crate::serializer::box_send_sync(read_payload(context, 0)?))
diff --git a/rust/fory-core/src/serializer/unsigned_number.rs 
b/rust/fory-core/src/serializer/unsigned_number.rs
index e5f49d008..6c679df7f 100644
--- a/rust/fory-core/src/serializer/unsigned_number.rs
+++ b/rust/fory-core/src/serializer/unsigned_number.rs
@@ -38,6 +38,17 @@ macro_rules! impl_xlang_unsigned_num_serializer {
             fn fory_read_data(context: &mut ReadContext) -> Result<Self, 
Error> {
                 $reader(&mut context.reader)
             }
+            #[inline]
+            fn fory_read_data_as_send_sync_any(
+                context: &mut ReadContext,
+            ) -> Result<Box<dyn std::any::Any + Send + Sync>, Error>
+            where
+                Self: Sized + ForyDefault,
+            {
+                Ok(crate::serializer::box_send_sync(Self::fory_read_data(
+                    context,
+                )?))
+            }
 
             #[inline(always)]
             fn fory_reserved_space() -> usize {
@@ -104,6 +115,17 @@ macro_rules! impl_rust_unsigned_num_serializer {
             fn fory_read_data(context: &mut ReadContext) -> Result<Self, 
Error> {
                 $reader(&mut context.reader)
             }
+            #[inline]
+            fn fory_read_data_as_send_sync_any(
+                context: &mut ReadContext,
+            ) -> Result<Box<dyn std::any::Any + Send + Sync>, Error>
+            where
+                Self: Sized + ForyDefault,
+            {
+                Ok(crate::serializer::box_send_sync(Self::fory_read_data(
+                    context,
+                )?))
+            }
 
             #[inline(always)]
             fn fory_reserved_space() -> usize {
diff --git a/rust/fory-core/src/serializer/util.rs 
b/rust/fory-core/src/serializer/util.rs
index d339cc972..559713261 100644
--- a/rust/fory-core/src/serializer/util.rs
+++ b/rust/fory-core/src/serializer/util.rs
@@ -95,3 +95,15 @@ pub fn write_dyn_data_generic<T: Serializer>(
         .get_write_data_fn();
     serializer_fn(any_value, context, has_generics)
 }
+
+pub(crate) mod send_sync {
+    use std::any::Any;
+
+    #[inline(always)]
+    pub fn box_send_sync<T>(value: T) -> Box<dyn Any + Send + Sync>
+    where
+        T: Any + Send + Sync,
+    {
+        Box::new(value)
+    }
+}
diff --git a/rust/fory-core/src/types/unknown_case.rs 
b/rust/fory-core/src/types/unknown_case.rs
index 0496ef4f4..cc9a8c5e3 100644
--- a/rust/fory-core/src/types/unknown_case.rs
+++ b/rust/fory-core/src/types/unknown_case.rs
@@ -27,7 +27,7 @@ pub struct UnknownCase {
     type_id: u32,
     // Keep resolver TypeInfo/Rc out of the carrier. Generated unions can 
outlive or move
     // independently from the resolver context, so the carrier stores only 
stable metadata
-    // plus a dynamic payload whose thread-safety is guaranteed by the trait 
object.
+    // plus a dynamic payload whose `Send + Sync` guarantee is carried by the 
trait object.
     value: Arc<dyn Any + Send + Sync>,
 }
 
diff --git a/rust/fory-derive/src/lib.rs b/rust/fory-derive/src/lib.rs
index 932c9c15a..b337e5b3a 100644
--- a/rust/fory-derive/src/lib.rs
+++ b/rust/fory-derive/src/lib.rs
@@ -143,6 +143,11 @@
 //! **Custom Types:**
 //! - Any type that implements `Serializer` (for `Fory`) or `Row` (for 
`ForyRow`)
 //!
+//! Derived structs, enums, and unions can be used behind
+//! `Arc<dyn Any + Send + Sync>` when the concrete type satisfies `Send + 
Sync`.
+//! Known non-`Send + Sync` field types such as `Rc<T>` and `RefCell<T>` are 
not
+//! eligible for that carrier.
+//!
 //! ## Usage with Fory
 //!
 //! After deriving the macros, you can use the types with the Fory 
serialization
@@ -340,6 +345,8 @@ fn parse_fory_attrs(attrs: &[Attribute]) -> 
syn::Result<ForyAttrs> {
                         Some(_) => evolving_flag,
                         None => Some(value),
                     };
+                } else {
+                    return Err(meta.error("unsupported type-level fory 
attribute"));
                 }
                 Ok(())
             })?;
diff --git a/rust/fory-derive/src/object/field_codec.rs 
b/rust/fory-derive/src/object/field_codec.rs
index 8543e044d..f310f4600 100644
--- a/rust/fory-derive/src/object/field_codec.rs
+++ b/rust/fory-derive/src/object/field_codec.rs
@@ -766,7 +766,7 @@ pub(crate) fn codec_type_for(
             );
         }
         return Ok(quote! {
-            compile_error!("Arc<dyn Any> is not a shared thread-safe carrier; 
use Arc<dyn Any + Send + Sync>")
+            compile_error!("Arc<dyn Any> is not a shared Send + Sync carrier; 
use Arc<dyn Any + Send + Sync>")
         });
     }
 
diff --git a/rust/fory-derive/src/object/serializer.rs 
b/rust/fory-derive/src/object/serializer.rs
index 5721dd9dc..9dc9dcd8c 100644
--- a/rust/fory-derive/src/object/serializer.rs
+++ b/rust/fory-derive/src/object/serializer.rs
@@ -52,8 +52,8 @@ pub fn derive_serializer(ast: &syn::DeriveInput, attrs: 
ForyAttrs) -> TokenStrea
     } else {
         quote! {}
     };
-    let threadsafe_tokens = generate_threadsafe_tokens(ast);
-    let serializer_threadsafe_ts = threadsafe_tokens.serializer.clone();
+    let send_sync_tokens = generate_send_sync_tokens(ast);
+    let serializer_send_sync_ts = send_sync_tokens.serializer.clone();
 
     // StructSerializer
     let (
@@ -62,7 +62,7 @@ pub fn derive_serializer(ast: &syn::DeriveInput, attrs: 
ForyAttrs) -> TokenStrea
         fields_info_ts,
         variants_fields_info_ts,
         read_compatible_ts,
-        read_compatible_send_sync_ts,
+        read_compatible_as_send_sync_any_ts,
         enum_variant_meta_types,
     ) = match &ast.data {
         syn::Data::Struct(s) => {
@@ -79,7 +79,7 @@ pub fn derive_serializer(ast: &syn::DeriveInput, attrs: 
ForyAttrs) -> TokenStrea
                 misc::gen_field_fields_info(&source_fields),
                 quote! { ::std::result::Result::Ok(::std::vec::Vec::new()) }, 
// No variants for structs
                 read::gen_read_compatible(&source_fields),
-                threadsafe_tokens.struct_read_compatible.clone(),
+                send_sync_tokens.struct_read_compatible.clone(),
                 vec![], // No variant meta types for structs
             )
         }
@@ -185,7 +185,7 @@ pub fn derive_serializer(ast: &syn::DeriveInput, attrs: 
ForyAttrs) -> TokenStrea
                 #read_compatible_ts
             }
 
-            #read_compatible_send_sync_ts
+            #read_compatible_as_send_sync_any_ts
         }
 
         impl #impl_generics ::fory_core::Serializer for #name #ty_generics 
#where_clause {
@@ -250,7 +250,7 @@ pub fn derive_serializer(ast: &syn::DeriveInput, attrs: 
ForyAttrs) -> TokenStrea
                 #read_data_ts
             }
 
-            #serializer_threadsafe_ts
+            #serializer_send_sync_ts
 
             #[inline(always)]
             fn fory_read_type_info(context: &mut ::fory_core::ReadContext) -> 
::std::result::Result<(), ::fory_core::error::Error> {
@@ -263,14 +263,14 @@ pub fn derive_serializer(ast: &syn::DeriveInput, attrs: 
ForyAttrs) -> TokenStrea
     code
 }
 
-struct ThreadsafeTokens {
+struct SendSyncTokens {
     serializer: proc_macro2::TokenStream,
     struct_read_compatible: proc_macro2::TokenStream,
 }
 
-fn generate_threadsafe_tokens(ast: &syn::DeriveInput) -> ThreadsafeTokens {
-    if !derive_type_is_threadsafe(ast) {
-        return ThreadsafeTokens {
+fn generate_send_sync_tokens(ast: &syn::DeriveInput) -> SendSyncTokens {
+    if !derive_type_is_send_sync(ast) {
+        return SendSyncTokens {
             serializer: quote! {},
             struct_read_compatible: quote! {},
         };
@@ -278,7 +278,7 @@ fn generate_threadsafe_tokens(ast: &syn::DeriveInput) -> 
ThreadsafeTokens {
     let struct_read_compatible = if matches!(ast.data, syn::Data::Struct(_)) {
         quote! {
             #[inline]
-            fn fory_read_compatible_send_sync(
+            fn fory_read_compatible_as_send_sync_any(
                 context: &mut ::fory_core::ReadContext,
                 type_info: ::std::rc::Rc<::fory_core::TypeInfo>,
             ) -> ::std::result::Result<::std::boxed::Box<dyn ::std::any::Any + 
Send + Sync>, ::fory_core::error::Error> {
@@ -289,18 +289,10 @@ fn generate_threadsafe_tokens(ast: &syn::DeriveInput) -> 
ThreadsafeTokens {
     } else {
         quote! {}
     };
-    ThreadsafeTokens {
+    SendSyncTokens {
         serializer: quote! {
-            #[inline(always)]
-            fn fory_is_threadsafe_type() -> bool
-            where
-                Self: Sized,
-            {
-                true
-            }
-
             #[inline]
-            fn fory_read_data_send_sync(
+            fn fory_read_data_as_send_sync_any(
                 context: &mut ::fory_core::ReadContext,
             ) -> ::std::result::Result<::std::boxed::Box<dyn ::std::any::Any + 
Send + Sync>, ::fory_core::error::Error>
             where
@@ -314,14 +306,14 @@ fn generate_threadsafe_tokens(ast: &syn::DeriveInput) -> 
ThreadsafeTokens {
     }
 }
 
-fn derive_type_is_threadsafe(ast: &syn::DeriveInput) -> bool {
+fn derive_type_is_send_sync(ast: &syn::DeriveInput) -> bool {
     use crate::object::util::{
-        all_type_params_send_sync, type_is_threadsafe, 
type_param_send_sync_bounds,
+        all_type_params_send_sync, type_is_send_sync, 
type_param_send_sync_bounds,
     };
 
-    // This is a syntactic filter for generating the send-sync reader. The
-    // generated reader still boxes `Self`, so Rust enforces the final
-    // `Send + Sync` invariant for nested user-defined field types.
+    // This syntactic filter rejects field types that are known not to satisfy
+    // `Send + Sync`. Opaque custom field types are allowed through, and Rust
+    // validates the final `Self: Send + Sync` bound when compiling the reader.
     if !all_type_params_send_sync(&ast.generics) {
         return false;
     }
@@ -330,12 +322,12 @@ fn derive_type_is_threadsafe(ast: &syn::DeriveInput) -> 
bool {
         syn::Data::Struct(data) => data
             .fields
             .iter()
-            .all(|field| type_is_threadsafe(&field.ty, &send_sync_params)),
+            .all(|field| type_is_send_sync(&field.ty, &send_sync_params)),
         syn::Data::Enum(data) => data.variants.iter().all(|variant| {
             variant
                 .fields
                 .iter()
-                .all(|field| type_is_threadsafe(&field.ty, &send_sync_params))
+                .all(|field| type_is_send_sync(&field.ty, &send_sync_params))
         }),
         syn::Data::Union(_) => false,
     }
diff --git a/rust/fory-derive/src/object/util.rs 
b/rust/fory-derive/src/object/util.rs
index 4fc38b893..260159b82 100644
--- a/rust/fory-derive/src/object/util.rs
+++ b/rust/fory-derive/src/object/util.rs
@@ -963,13 +963,13 @@ pub(crate) fn all_type_params_send_sync(generics: 
&syn::Generics) -> bool {
         .all(|param| bounded.contains(&param.ident.to_string()))
 }
 
-pub(crate) fn type_is_threadsafe(ty: &Type, send_sync_params: 
&HashSet<String>) -> bool {
+pub(crate) fn type_is_send_sync(ty: &Type, send_sync_params: &HashSet<String>) 
-> bool {
     match ty {
-        Type::Array(array) => type_is_threadsafe(array.elem.as_ref(), 
send_sync_params),
+        Type::Array(array) => type_is_send_sync(array.elem.as_ref(), 
send_sync_params),
         Type::Tuple(tuple) => tuple
             .elems
             .iter()
-            .all(|elem| type_is_threadsafe(elem, send_sync_params)),
+            .all(|elem| type_is_send_sync(elem, send_sync_params)),
         Type::Path(type_path) => {
             let Some(segment) = type_path.path.segments.last() else {
                 return false;
@@ -996,15 +996,15 @@ pub(crate) fn type_is_threadsafe(ty: &Type, 
send_sync_params: &HashSet<String>)
                             trait_object_is_any_send_sync(trait_obj)
                         }
                         (_, Type::TraitObject(_)) => false,
-                        _ => type_is_threadsafe(inner, send_sync_params),
+                        _ => type_is_send_sync(inner, send_sync_params),
                     }
                 }
                 "HashMap" | "BTreeMap" => {
                     let Some((key, value)) = 
two_path_type_args(&segment.arguments) else {
                         return false;
                     };
-                    type_is_threadsafe(key, send_sync_params)
-                        && type_is_threadsafe(value, send_sync_params)
+                    type_is_send_sync(key, send_sync_params)
+                        && type_is_send_sync(value, send_sync_params)
                 }
                 _ => true,
             }
diff --git a/rust/fory/src/lib.rs b/rust/fory/src/lib.rs
index e190d0c8d..70327c2a9 100644
--- a/rust/fory/src/lib.rs
+++ b/rust/fory/src/lib.rs
@@ -340,7 +340,8 @@
 //! - `Box<dyn Trait>` - Owned trait objects
 //! - `Rc<dyn Trait>` - Reference-counted trait objects
 //! - `Arc<dyn Trait>` - Thread-safe reference-counted trait objects
-//! - `Rc<dyn Any>` / `Arc<dyn Any + Send + Sync>` - Runtime type dispatch 
without custom traits
+//! - `Box<dyn Any>` / `Rc<dyn Any>` / `Arc<dyn Any + Send + Sync>` - Runtime 
type
+//!   dispatch without custom traits for registered non-container payloads
 //! - Collections: `Vec<Box<dyn Trait>>`, `HashMap<K, Box<dyn Trait>>`
 //!
 //! #### Basic Trait Object Serialization
@@ -401,7 +402,7 @@
 //!
 //! #### Serializing `dyn Any` Trait Objects
 //!
-//! **What it does:** Supports serializing `Rc<dyn Any>` and
+//! **What it does:** Supports serializing `Box<dyn Any>`, `Rc<dyn Any>`, and
 //! `Arc<dyn Any + Send + Sync>` for maximum runtime type flexibility without
 //! defining custom traits.
 //!
@@ -410,7 +411,7 @@
 //!
 //! **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
 //!
@@ -470,6 +471,18 @@
 //! # }
 //! ```
 //!
+//! `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.
+//! Generic containers such as `Vec<T>`, `HashMap<K, V>`, `HashSet<T>`, and
+//! `LinkedList<T>` are not supported directly as top-level erased `Any`
+//! payloads behind any of those carriers. This also includes primitive vector
+//! encodings such as `Vec<u8>`. Wrap the container in a registered derived 
type
+//! when it needs to travel behind an erased `Any` carrier.
+//!
 //! #### Rc/Arc-Based Trait Objects in Structs
 //!
 //! For struct fields containing `Rc<dyn Trait>` or `Arc<dyn Trait>`, Apache 
Fory™
@@ -536,8 +549,9 @@
 //! `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:
 //!
@@ -1005,8 +1019,11 @@
 //! - `Box<dyn Trait>` - Owned trait objects
 //! - `Rc<dyn Trait>` - Reference-counted trait objects
 //! - `Arc<dyn Trait>` - Thread-safe reference-counted trait objects
-//! - `Rc<dyn Any>` - Runtime type dispatch without custom traits
-//! - `Arc<dyn Any + Send + Sync>` - Thread-safe runtime type dispatch
+//! - `Box<dyn Any>` - Runtime type dispatch for registered non-container 
payloads
+//! - `Rc<dyn Any>` - Reference-counted runtime type dispatch for registered
+//!   non-container payloads
+//! - `Arc<dyn Any + Send + Sync>` - Thread-safe runtime type dispatch for
+//!   registered non-container payloads
 //!
 //! ## Wire Modes And Schema Evolution
 //!
diff --git a/rust/tests/tests/test_any.rs b/rust/tests/tests/test_any.rs
index d7c4a7b57..8bc978c52 100644
--- a/rust/tests/tests/test_any.rs
+++ b/rust/tests/tests/test_any.rs
@@ -16,13 +16,113 @@
 // under the License.
 
 use fory_core::fory::Fory;
-use fory_derive::ForyStruct;
+use fory_derive::{ForyEnum, ForyStruct, ForyUnion};
 use std::any::Any;
-use std::collections::HashMap;
+use std::collections::{HashMap, HashSet, LinkedList};
 use std::rc::Rc;
 use std::sync::Arc;
 use std::vec;
 
+fn assert_erased_container_error(message: String) {
+    assert!(
+        message.contains("top-level erased Any")
+            || message.contains("Erased Any payloads require")
+            || message.contains("not found in type_info registry"),
+        "unexpected error: {message}"
+    );
+}
+
+fn assert_box_any_unsupported<T: 'static>(fory: &Fory, value: T) {
+    let wrapped: Box<dyn Any> = Box::new(value);
+    match fory.serialize(&wrapped) {
+        Ok(bytes) => {
+            let result: Result<Box<dyn Any>, _> = fory.deserialize(&bytes);
+            let err = result.expect_err("expected Box<dyn Any> container read 
to fail");
+            assert_erased_container_error(err.to_string());
+        }
+        Err(err) => assert_erased_container_error(err.to_string()),
+    }
+}
+
+fn assert_rc_any_unsupported<T: 'static>(fory: &Fory, value: T) {
+    let wrapped: Rc<dyn Any> = Rc::new(value);
+    match fory.serialize(&wrapped) {
+        Ok(bytes) => {
+            let result: Result<Rc<dyn Any>, _> = fory.deserialize(&bytes);
+            let err = result.expect_err("expected Rc<dyn Any> container read 
to fail");
+            assert_erased_container_error(err.to_string());
+        }
+        Err(err) => assert_erased_container_error(err.to_string()),
+    }
+}
+
+fn assert_arc_any_unsupported<T: 'static + Send + Sync>(fory: &Fory, value: T) 
{
+    let wrapped: Arc<dyn Any + Send + Sync> = Arc::new(value);
+    match fory.serialize(&wrapped) {
+        Ok(bytes) => {
+            let result: Result<Arc<dyn Any + Send + Sync>, _> = 
fory.deserialize(&bytes);
+            let err = result.expect_err("expected Arc<dyn Any> container read 
to fail");
+            assert_erased_container_error(err.to_string());
+        }
+        Err(err) => assert_erased_container_error(err.to_string()),
+    }
+}
+
+fn assert_box_any_values_unsupported(fory: &Fory, values: Vec<Box<dyn Any>>) {
+    let result = fory
+        .serialize(&values)
+        .and_then(|bytes| fory.deserialize::<Vec<Box<dyn 
Any>>>(&bytes).map(|_| ()));
+    let err = result.expect_err("expected Box<dyn Any> container values to 
fail");
+    assert_erased_container_error(err.to_string());
+}
+
+fn assert_rc_any_values_unsupported(fory: &Fory, values: Vec<Rc<dyn Any>>) {
+    let result = fory
+        .serialize(&values)
+        .and_then(|bytes| fory.deserialize::<Vec<Rc<dyn Any>>>(&bytes).map(|_| 
()));
+    let err = result.expect_err("expected Rc<dyn Any> container values to 
fail");
+    assert_erased_container_error(err.to_string());
+}
+
+fn assert_arc_any_values_unsupported(fory: &Fory, values: Vec<Arc<dyn Any + 
Send + Sync>>) {
+    let result = fory.serialize(&values).and_then(|bytes| {
+        fory.deserialize::<Vec<Arc<dyn Any + Send + Sync>>>(&bytes)
+            .map(|_| ())
+    });
+    let err = result.expect_err("expected Arc<dyn Any> container values to 
fail");
+    assert_erased_container_error(err.to_string());
+}
+
+fn assert_box_any_map_unsupported(fory: &Fory, values: HashMap<String, Box<dyn 
Any>>) {
+    let result = fory.serialize(&values).and_then(|bytes| {
+        fory.deserialize::<HashMap<String, Box<dyn Any>>>(&bytes)
+            .map(|_| ())
+    });
+    let err = result.expect_err("expected Box<dyn Any> map values to fail");
+    assert_erased_container_error(err.to_string());
+}
+
+fn assert_rc_any_map_unsupported(fory: &Fory, values: HashMap<String, Rc<dyn 
Any>>) {
+    let result = fory.serialize(&values).and_then(|bytes| {
+        fory.deserialize::<HashMap<String, Rc<dyn Any>>>(&bytes)
+            .map(|_| ())
+    });
+    let err = result.expect_err("expected Rc<dyn Any> map values to fail");
+    assert_erased_container_error(err.to_string());
+}
+
+fn assert_arc_any_map_unsupported(
+    fory: &Fory,
+    values: HashMap<String, Arc<dyn Any + Send + Sync>>,
+) {
+    let result = fory.serialize(&values).and_then(|bytes| {
+        fory.deserialize::<HashMap<String, Arc<dyn Any + Send + Sync>>>(&bytes)
+            .map(|_| ())
+    });
+    let err = result.expect_err("expected Arc<dyn Any> map values to fail");
+    assert_erased_container_error(err.to_string());
+}
+
 #[test]
 fn test_box_dyn_any() {
     let fory = Fory::builder().xlang(false).build();
@@ -90,13 +190,10 @@ fn test_arc_dyn_any() {
     let deserialized2: Arc<dyn Any + Send + Sync> = 
fory.deserialize(&bytes2).unwrap();
     assert_eq!(deserialized2.downcast_ref::<i32>().unwrap(), &123i32);
 
-    let value3: Arc<dyn Any + Send + Sync> = Arc::new(vec![1, 2, 3]);
+    let value3: Arc<dyn Any + Send + Sync> = Arc::new(true);
     let bytes3 = fory.serialize(&value3).unwrap();
     let deserialized3: Arc<dyn Any + Send + Sync> = 
fory.deserialize(&bytes3).unwrap();
-    assert_eq!(
-        deserialized3.downcast_ref::<Vec<i32>>().unwrap(),
-        &vec![1, 2, 3]
-    );
+    assert_eq!(deserialized3.downcast_ref::<bool>().unwrap(), &true);
 }
 
 #[test]
@@ -122,17 +219,17 @@ fn test_rc_dyn_any_shared_reference() {
 fn test_arc_dyn_any_shared_reference() {
     let fory = Fory::builder().xlang(false).build();
 
-    let shared_vec: Arc<dyn Any + Send + Sync> = Arc::new(vec![1, 2, 3]);
+    let shared_vec: Arc<dyn Any + Send + Sync> = 
Arc::new("shared".to_string());
 
     let data = vec![shared_vec.clone(), shared_vec.clone()];
 
     let bytes = fory.serialize(&data).unwrap();
     let deserialized: Vec<Arc<dyn Any + Send + Sync>> = 
fory.deserialize(&bytes).unwrap();
 
-    let first_vec = deserialized[0].downcast_ref::<Vec<i32>>().unwrap();
-    let second_vec = deserialized[1].downcast_ref::<Vec<i32>>().unwrap();
-    assert_eq!(first_vec, &vec![1, 2, 3]);
-    assert_eq!(second_vec, &vec![1, 2, 3]);
+    let first_vec = deserialized[0].downcast_ref::<String>().unwrap();
+    let second_vec = deserialized[1].downcast_ref::<String>().unwrap();
+    assert_eq!(first_vec, "shared");
+    assert_eq!(second_vec, "shared");
     assert_eq!(Arc::strong_count(&shared_vec), 3);
 }
 
@@ -207,6 +304,197 @@ struct Container {
     items: Vec<String>,
 }
 
+#[derive(ForyStruct, PartialEq, Debug)]
+struct RcRefPayload {
+    name: String,
+    shared: Rc<String>,
+}
+
+#[derive(ForyStruct, PartialEq, Debug)]
+struct ArcRefPayload {
+    name: String,
+    shared: Arc<String>,
+}
+
+#[test]
+fn wrapped_container_box_any() {
+    let mut fory = Fory::builder().xlang(false).build();
+    fory.register_by_name::<Container>("", "Container").unwrap();
+
+    let value: Box<dyn Any> = Box::new(Container {
+        id: 321,
+        items: vec!["wrapped".to_string(), "values".to_string()],
+    });
+    let bytes = fory.serialize(&value).unwrap();
+    let decoded: Box<dyn Any> = fory.deserialize(&bytes).unwrap();
+    let result = decoded.downcast_ref::<Container>().unwrap();
+
+    assert_eq!(result.id, 321);
+    assert_eq!(result.items, vec!["wrapped", "values"]);
+}
+
+#[test]
+fn rc_any_refvalue_keeps_outer_ref() {
+    let mut fory = Fory::builder().xlang(false).build();
+    fory.register_by_name::<RcRefPayload>("", "RcRefPayload")
+        .unwrap();
+
+    let payload: Rc<dyn Any> = Rc::new(RcRefPayload {
+        name: "outer".to_string(),
+        shared: Rc::new("nested".to_string()),
+    });
+    let values = vec![payload.clone(), payload.clone()];
+
+    let bytes = fory.serialize(&values).unwrap();
+    let decoded: Vec<Rc<dyn Any>> = fory.deserialize(&bytes).unwrap();
+
+    assert!(Rc::ptr_eq(&decoded[0], &decoded[1]));
+    let payload = decoded[0].downcast_ref::<RcRefPayload>().unwrap();
+    assert_eq!(payload.name, "outer");
+    assert_eq!(payload.shared.as_str(), "nested");
+}
+
+#[test]
+fn arc_any_refvalue_keeps_outer_ref() {
+    let mut fory = Fory::builder().xlang(false).build();
+    fory.register_by_name::<ArcRefPayload>("", "ArcRefPayload")
+        .unwrap();
+
+    let payload: Arc<dyn Any + Send + Sync> = Arc::new(ArcRefPayload {
+        name: "outer".to_string(),
+        shared: Arc::new("nested".to_string()),
+    });
+    let values = vec![payload.clone(), payload.clone()];
+
+    let bytes = fory.serialize(&values).unwrap();
+    let decoded: Vec<Arc<dyn Any + Send + Sync>> = 
fory.deserialize(&bytes).unwrap();
+
+    assert!(Arc::ptr_eq(&decoded[0], &decoded[1]));
+    let payload = decoded[0].downcast_ref::<ArcRefPayload>().unwrap();
+    assert_eq!(payload.name, "outer");
+    assert_eq!(payload.shared.as_str(), "nested");
+}
+
+#[test]
+fn generic_containers_rejected_in_any() {
+    let fory = Fory::builder().xlang(false).build();
+
+    assert_box_any_unsupported(&fory, vec![1_i32, 2, 3]);
+    assert_rc_any_unsupported(&fory, vec![1_i32, 2, 3]);
+    assert_arc_any_unsupported(&fory, vec![1_i32, 2, 3]);
+
+    assert_box_any_unsupported(&fory, LinkedList::from([1_i32, 2, 3]));
+    assert_rc_any_unsupported(&fory, HashSet::from([1_i32, 2, 3]));
+    assert_arc_any_unsupported(
+        &fory,
+        HashMap::from([("one".to_string(), 1_i32), ("two".to_string(), 2)]),
+    );
+}
+
+#[test]
+fn any_collection_rejects_containers() {
+    let fory = Fory::builder().xlang(false).build();
+
+    assert_box_any_values_unsupported(&fory, vec![Box::new(vec![1_i32, 2, 3]) 
as Box<dyn Any>]);
+    assert_box_any_values_unsupported(
+        &fory,
+        vec![
+            Box::new(vec![1_i32, 2, 3]) as Box<dyn Any>,
+            Box::new(vec![4_i32, 5, 6]) as Box<dyn Any>,
+        ],
+    );
+
+    assert_rc_any_values_unsupported(&fory, vec![Rc::new(vec![1_i32, 2, 3]) as 
Rc<dyn Any>]);
+    assert_rc_any_values_unsupported(
+        &fory,
+        vec![
+            Rc::new(vec![1_i32, 2, 3]) as Rc<dyn Any>,
+            Rc::new(vec![4_i32, 5, 6]) as Rc<dyn Any>,
+        ],
+    );
+
+    assert_arc_any_values_unsupported(
+        &fory,
+        vec![Arc::new(vec![1_i32, 2, 3]) as Arc<dyn Any + Send + Sync>],
+    );
+    assert_arc_any_values_unsupported(
+        &fory,
+        vec![
+            Arc::new(vec![1_i32, 2, 3]) as Arc<dyn Any + Send + Sync>,
+            Arc::new(vec![4_i32, 5, 6]) as Arc<dyn Any + Send + Sync>,
+        ],
+    );
+}
+
+#[test]
+fn any_map_values_reject_containers() {
+    let fory = Fory::builder().xlang(false).build();
+
+    assert_box_any_map_unsupported(
+        &fory,
+        HashMap::from([(
+            "list".to_string(),
+            Box::new(vec![1_i32, 2, 3]) as Box<dyn Any>,
+        )]),
+    );
+    assert_rc_any_map_unsupported(
+        &fory,
+        HashMap::from([(
+            "map".to_string(),
+            Rc::new(HashMap::from([("one".to_string(), 1_i32)])) as Rc<dyn 
Any>,
+        )]),
+    );
+    assert_arc_any_map_unsupported(
+        &fory,
+        HashMap::from([(
+            "list".to_string(),
+            Arc::new(vec![1_i32, 2, 3]) as Arc<dyn Any + Send + Sync>,
+        )]),
+    );
+}
+
+#[test]
+fn compatible_enum_box_any_read() {
+    #[derive(ForyEnum, Debug, Default, PartialEq)]
+    enum Status {
+        #[default]
+        Active,
+        Inactive,
+    }
+
+    let mut fory = Fory::builder().xlang(false).compatible(true).build();
+    fory.register::<Status>(710).unwrap();
+
+    let value: Box<dyn Any> = Box::new(Status::Inactive);
+    let bytes = fory.serialize(&value).unwrap();
+    let decoded: Box<dyn Any> = fory.deserialize(&bytes).unwrap();
+
+    assert_eq!(decoded.downcast_ref::<Status>().unwrap(), &Status::Inactive);
+}
+
+#[test]
+fn compatible_union_rc_any_read() {
+    #[derive(ForyUnion, Debug, PartialEq)]
+    enum Event {
+        #[fory(unknown)]
+        Unknown(fory_core::UnknownCase),
+        #[fory(id = 0, default)]
+        Value(String),
+    }
+
+    let mut fory = Fory::builder().xlang(false).compatible(true).build();
+    fory.register_union::<Event>(711).unwrap();
+
+    let value: Rc<dyn Any> = Rc::new(Event::Value("compatible".to_string()));
+    let bytes = fory.serialize(&value).unwrap();
+    let decoded: Rc<dyn Any> = fory.deserialize(&bytes).unwrap();
+
+    assert_eq!(
+        decoded.downcast_ref::<Event>().unwrap(),
+        &Event::Value("compatible".to_string())
+    );
+}
+
 #[derive(ForyStruct)]
 struct ArcAnyHolder {
     value: Arc<dyn Any + Send + Sync>,
@@ -348,36 +636,18 @@ struct StructB {
     i: i32,
 }
 
-/// Test that serializing different Vec<T> types in Box<dyn Any> returns a 
clear error.
+/// Test that different Vec<T> types in Box<dyn Any> return a clear error.
 ///
-/// This tests for a known limitation of the xlang serialization protocol:
-/// different generic container types (Vec<StructA>, Vec<StructB>) share the 
same
-/// type ID (LIST=21), so they cannot be distinguished during polymorphic 
deserialization.
+/// Different generic container instantiations share broad container metadata, 
so
+/// they cannot be used as unambiguous top-level erased Any payloads.
 ///
 /// Previously this caused non-deterministic failures. Now it returns a clear 
error message.
 #[test]
-fn test_vec_of_different_struct_types_in_box_any_returns_error() {
+fn generic_vecs_rejected_in_box_any() {
     let mut fory = Fory::builder().xlang(false).build();
-    // Register both struct types
     fory.register_by_name::<StructA>("", "StructA").unwrap();
-    fory.register_generic_trait::<Vec<StructA>>().unwrap();
     fory.register_by_name::<StructB>("", "StructB").unwrap();
-    fory.register_generic_trait::<Vec<StructB>>().unwrap();
-
-    // Create Box<dyn Any> wrappers for Vec<StructA> and Vec<StructB>
-    let a_vec: Box<dyn Any> = Box::new(vec![StructA { a: 11 }; 5]);
-    let b_vec: Box<dyn Any> = Box::new(vec![StructB { i: 1 }; 5]);
-    let any_vec: Vec<Box<dyn Any>> = vec![a_vec, b_vec];
 
-    let bytes = fory.serialize(&any_vec).unwrap();
-
-    // Deserialization should fail with a clear error about generic containers
-    let result: Result<Vec<Box<dyn Any>>, _> = fory.deserialize(&bytes);
-    assert!(result.is_err());
-    let err_msg = result.unwrap_err().to_string();
-    assert!(
-        err_msg.contains("generic container types"),
-        "Expected error about generic containers, got: {}",
-        err_msg
-    );
+    assert_box_any_unsupported(&fory, vec![StructA { a: 11 }; 5]);
+    assert_box_any_unsupported(&fory, vec![StructB { i: 1 }; 5]);
 }
diff --git a/rust/tests/tests/test_collection.rs 
b/rust/tests/tests/test_collection.rs
index 9271e39ae..c71e4af20 100644
--- a/rust/tests/tests/test_collection.rs
+++ b/rust/tests/tests/test_collection.rs
@@ -15,23 +15,20 @@
 // specific language governing permissions and limitations
 // under the License.
 
-use fory_core::{Fory, Serializer};
+use fory_core::Fory;
 use fory_derive::ForyStruct;
 use std::collections::{BTreeSet, BinaryHeap, HashSet};
 
 #[test]
 fn test_btreeset_roundtrip() {
-    let mut fory: Fory = Fory::builder().xlang(false).build();
-    fory.register_generic_trait::<BTreeSet<i32>>().unwrap();
+    let fory: Fory = Fory::builder().xlang(false).build();
 
     let mut original = BTreeSet::new();
     original.insert(1);
     original.insert(2);
     original.insert(3);
 
-    let trait_obj: Box<dyn Serializer> = Box::new(original.clone());
-    let serialized = fory.serialize(&trait_obj).unwrap();
-
+    let serialized = fory.serialize(&original).unwrap();
     let deserialized_concrete: BTreeSet<i32> = 
fory.deserialize(&serialized).unwrap();
 
     assert_eq!(deserialized_concrete.len(), 3);
diff --git a/rust/tests/tests/test_enum.rs b/rust/tests/tests/test_enum.rs
index 566baff9d..5398d68a7 100644
--- a/rust/tests/tests/test_enum.rs
+++ b/rust/tests/tests/test_enum.rs
@@ -223,7 +223,7 @@ fn union_compatible_enum_xlang_format() {
 }
 
 #[test]
-fn unknown_case_reads_threadsafe_generated_payload() {
+fn unknown_case_reads_send_sync_payload() {
     use fory_core::ArcWeak;
     use std::sync::{Arc, Mutex};
 
diff --git a/rust/tests/tests/test_lifecycle_guard.rs 
b/rust/tests/tests/test_lifecycle_guard.rs
index 56e8eb64b..7c3c9f80a 100644
--- a/rust/tests/tests/test_lifecycle_guard.rs
+++ b/rust/tests/tests/test_lifecycle_guard.rs
@@ -195,19 +195,6 @@ fn 
test_register_serializer_by_name_with_namespace_after_serialize_fails() {
     assert!(matches!(err, Error::NotAllowed(_)));
 }
 
-/// Ensures `register_generic_trait()` is forbidden after snapshot init.
-#[test]
-fn test_register_generic_trait_after_serialize_fails() {
-    let mut fory = Fory::builder().xlang(false).build();
-    fory.register::<Point>(100).unwrap();
-    let _bytes = fory.serialize(&Point { x: 0, y: 0 }).unwrap();
-
-    let err = fory
-        .register_generic_trait::<Vec<i32>>()
-        .expect_err("register_generic_trait after serialize should fail");
-    assert!(matches!(err, Error::NotAllowed(_)));
-}
-
 /// Ensures `register_union()` is forbidden after snapshot init.
 #[test]
 fn test_register_union_after_serialize_fails() {
diff --git a/rust/tests/tests/test_send_sync.rs 
b/rust/tests/tests/test_send_sync.rs
new file mode 100644
index 000000000..d7b5a7773
--- /dev/null
+++ b/rust/tests/tests/test_send_sync.rs
@@ -0,0 +1,365 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#![allow(dead_code)]
+
+use fory_core::fory::Fory;
+use fory_core::{
+    read_data, write_data, Config, Error, ForyDefault, ReadContext, 
Serializer, TypeResolver,
+    WriteContext,
+};
+use fory_derive::{ForyEnum, ForyStruct, ForyUnion};
+use std::{
+    any::Any,
+    collections::{HashMap, HashSet, LinkedList},
+    fmt::Debug,
+    rc::Rc,
+    sync::Arc,
+};
+
+fn assert_arc_any_roundtrip<T>(fory: &Fory, value: T)
+where
+    T: 'static + Clone + Debug + PartialEq + Send + Sync,
+{
+    let wrapped: Arc<dyn Any + Send + Sync> = Arc::new(value.clone());
+    let bytes = fory.serialize(&wrapped).unwrap();
+    let decoded: Arc<dyn Any + Send + Sync> = 
fory.deserialize(&bytes).unwrap();
+    assert_eq!(decoded.downcast_ref::<T>().unwrap(), &value);
+}
+
+fn assert_arc_any_unsupported<T>(fory: &Fory, value: T)
+where
+    T: 'static + Send + Sync,
+{
+    let wrapped: Arc<dyn Any + Send + Sync> = Arc::new(value);
+    let err = match fory.serialize(&wrapped) {
+        Ok(bytes) => {
+            let result: Result<Arc<dyn Any + Send + Sync>, _> = 
fory.deserialize(&bytes);
+            match result {
+                Ok(_) => panic!("expected direct generic container payload to 
be unsupported"),
+                Err(err) => err,
+            }
+        }
+        Err(err) => err,
+    };
+    let message = err.to_string();
+    assert!(
+        message.contains("top-level erased Any")
+            || message.contains("Erased Any payloads require")
+            || message.contains("cannot be represented as Arc<dyn Any + Send + 
Sync>"),
+        "unexpected error: {err}"
+    );
+}
+
+fn assert_send_sync_reader_unsupported<T>()
+where
+    T: Serializer + ForyDefault,
+{
+    let mut context = ReadContext::new(TypeResolver::default(), 
Config::default());
+    let result = T::fory_read_data_as_send_sync_any(&mut context);
+    let err = match result {
+        Ok(_) => panic!("expected send-sync Any reader to be unsupported"),
+        Err(err) => err,
+    };
+    let message = err.to_string();
+    assert!(
+        message.contains("cannot be represented as Arc<dyn Any + Send + 
Sync>"),
+        "unexpected error: {err}"
+    );
+}
+
+#[test]
+fn test_builtin_send_sync_arc_any_reads() {
+    let fory = Fory::builder().xlang(false).build();
+
+    assert_arc_any_roundtrip(&fory, 42_i32);
+    assert_arc_any_roundtrip(&fory, true);
+    assert_arc_any_roundtrip(&fory, "thread-safe".to_string());
+}
+
+#[test]
+fn test_derived_send_sync_arc_any_read() {
+    #[derive(ForyStruct, Clone, Debug, PartialEq)]
+    struct Value {
+        name: String,
+        count: i32,
+    }
+
+    let mut fory = Fory::builder().xlang(false).build();
+    fory.register::<Value>(900).unwrap();
+
+    assert_arc_any_roundtrip(
+        &fory,
+        Value {
+            name: "derived".to_string(),
+            count: 7,
+        },
+    );
+}
+
+#[test]
+fn compatible_struct_arc_any_read() {
+    #[derive(ForyStruct, Clone, Debug, PartialEq)]
+    struct ValueV1 {
+        #[fory(id = 0)]
+        name: String,
+        #[fory(id = 1)]
+        count: i32,
+    }
+
+    #[derive(ForyStruct, Clone, Debug, PartialEq)]
+    struct ValueV2 {
+        #[fory(id = 0)]
+        name: String,
+        #[fory(id = 1)]
+        count: i32,
+        #[fory(id = 2)]
+        label: String,
+    }
+
+    let mut writer = Fory::builder().xlang(false).compatible(true).build();
+    writer.register::<ValueV1>(909).unwrap();
+
+    let mut reader = Fory::builder().xlang(false).compatible(true).build();
+    reader.register::<ValueV2>(909).unwrap();
+
+    let value: Arc<dyn Any + Send + Sync> = Arc::new(ValueV1 {
+        name: "compatible".to_string(),
+        count: 11,
+    });
+    let bytes = writer.serialize(&value).unwrap();
+    let decoded: Arc<dyn Any + Send + Sync> = 
reader.deserialize(&bytes).unwrap();
+    let value = decoded.downcast_ref::<ValueV2>().unwrap();
+
+    assert_eq!(value.name, "compatible");
+    assert_eq!(value.count, 11);
+    assert_eq!(value.label, String::default());
+}
+
+#[test]
+fn wrapped_container_arc_any_read() {
+    #[derive(ForyStruct, Clone, Debug, PartialEq)]
+    struct IntList {
+        values: Vec<i32>,
+    }
+
+    let mut fory = Fory::builder().xlang(false).build();
+    fory.register::<IntList>(901).unwrap();
+
+    assert_arc_any_roundtrip(
+        &fory,
+        IntList {
+            values: vec![1, 2, 3],
+        },
+    );
+}
+
+#[test]
+fn generic_containers_rejected_arc_any() {
+    let fory = Fory::builder().xlang(false).build();
+
+    assert_arc_any_unsupported(&fory, vec![1_i32, 2, 3]);
+    assert_arc_any_unsupported(&fory, LinkedList::from([1_i32, 2, 3]));
+    assert_arc_any_unsupported(&fory, HashSet::from([1_i32, 2, 3]));
+    assert_arc_any_unsupported(
+        &fory,
+        HashMap::from([("one".to_string(), 1_i32), ("two".to_string(), 2)]),
+    );
+}
+
+#[test]
+fn test_auto_send_sync_struct() {
+    #[derive(ForyStruct, Clone, Debug, PartialEq)]
+    struct Value {
+        name: String,
+    }
+
+    let mut fory = Fory::builder().xlang(false).build();
+    fory.register::<Value>(902).unwrap();
+
+    assert_arc_any_roundtrip(
+        &fory,
+        Value {
+            name: "auto".to_string(),
+        },
+    );
+}
+
+#[test]
+fn non_send_sync_carrier_reader_unsupported() {
+    assert_send_sync_reader_unsupported::<Rc<dyn Any>>();
+}
+
+#[test]
+fn manual_serializer_arc_any_read() {
+    #[derive(Clone, Debug, PartialEq)]
+    struct ManualValue {
+        id: i32,
+        name: String,
+    }
+
+    impl ForyDefault for ManualValue {
+        fn fory_default() -> Self {
+            Self {
+                id: 0,
+                name: String::new(),
+            }
+        }
+    }
+
+    impl Serializer for ManualValue {
+        fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), 
Error> {
+            write_data(&self.id, context)?;
+            write_data(&self.name, context)
+        }
+
+        fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
+            Ok(Self {
+                id: read_data(context)?,
+                name: read_data(context)?,
+            })
+        }
+
+        fn fory_read_data_as_send_sync_any(
+            context: &mut ReadContext,
+        ) -> Result<Box<dyn Any + Send + Sync>, Error> {
+            Ok(fory_core::serializer::box_send_sync(Self::fory_read_data(
+                context,
+            )?))
+        }
+
+        fn fory_type_id_dyn(
+            &self,
+            type_resolver: &TypeResolver,
+        ) -> Result<fory_core::TypeId, Error> {
+            Self::fory_get_type_id(type_resolver)
+        }
+
+        fn as_any(&self) -> &dyn Any {
+            self
+        }
+    }
+
+    let mut fory = Fory::builder().xlang(false).build();
+    fory.register_serializer::<ManualValue>(910).unwrap();
+
+    assert_arc_any_roundtrip(
+        &fory,
+        ManualValue {
+            id: 7,
+            name: "manual".to_string(),
+        },
+    );
+}
+
+#[test]
+fn test_nested_custom_default() {
+    #[derive(ForyStruct, Clone, Debug, PartialEq)]
+    struct Leaf {
+        name: String,
+    }
+
+    #[derive(ForyStruct, Clone, Debug, PartialEq)]
+    struct Value {
+        leaf: Leaf,
+    }
+
+    let mut fory = Fory::builder().xlang(false).build();
+    fory.register::<Leaf>(902).unwrap();
+    fory.register::<Value>(903).unwrap();
+
+    assert_arc_any_roundtrip(
+        &fory,
+        Value {
+            leaf: Leaf {
+                name: "nested".to_string(),
+            },
+        },
+    );
+}
+
+#[test]
+fn test_known_non_send_sync_struct() {
+    #[derive(ForyStruct)]
+    struct Value {
+        name: Rc<String>,
+    }
+
+    assert_send_sync_reader_unsupported::<Value>();
+}
+
+#[test]
+fn test_send_sync_union() {
+    #[derive(ForyUnion, Clone, Debug, PartialEq)]
+    enum Event {
+        #[fory(unknown)]
+        Unknown(fory_core::UnknownCase),
+        #[fory(id = 0, default)]
+        Value(String),
+    }
+
+    let mut fory = Fory::builder().xlang(false).build();
+    fory.register_union::<Event>(905).unwrap();
+
+    assert_arc_any_roundtrip(&fory, Event::Value("union".to_string()));
+}
+
+#[test]
+fn test_send_sync_enum() {
+    #[derive(ForyEnum, Clone, Debug, Default, PartialEq)]
+    enum Status {
+        #[default]
+        Active,
+        Inactive,
+    }
+
+    let mut fory = Fory::builder().xlang(false).build();
+    fory.register::<Status>(906).unwrap();
+
+    assert_arc_any_roundtrip(&fory, Status::Inactive);
+}
+
+#[test]
+fn compatible_union_arc_any_read() {
+    #[derive(ForyUnion, Clone, Debug, PartialEq)]
+    enum Event {
+        #[fory(unknown)]
+        Unknown(fory_core::UnknownCase),
+        #[fory(id = 0, default)]
+        Value(String),
+    }
+
+    let mut fory = Fory::builder().xlang(false).compatible(true).build();
+    fory.register_union::<Event>(907).unwrap();
+
+    assert_arc_any_roundtrip(&fory, Event::Value("compatible".to_string()));
+}
+
+#[test]
+fn compatible_enum_arc_any_read() {
+    #[derive(ForyEnum, Clone, Debug, Default, PartialEq)]
+    enum Status {
+        #[default]
+        Active,
+        Inactive,
+    }
+
+    let mut fory = Fory::builder().xlang(false).compatible(true).build();
+    fory.register::<Status>(908).unwrap();
+
+    assert_arc_any_roundtrip(&fory, Status::Inactive);
+}
diff --git a/rust/tests/tests/test_trait_object.rs 
b/rust/tests/tests/test_trait_object.rs
index 9544c4bdb..923ae6266 100644
--- a/rust/tests/tests/test_trait_object.rs
+++ b/rust/tests/tests/test_trait_object.rs
@@ -17,7 +17,9 @@
 
 use fory_core::fory::Fory;
 use fory_core::register_trait_type;
+use fory_core::resolver::RefFlag;
 use fory_core::serializer::Serializer;
+use fory_core::TypeId;
 use fory_derive::ForyStruct;
 use std::collections::{HashMap, HashSet};
 
@@ -25,6 +27,16 @@ fn fory_compatible() -> Fory {
     Fory::builder().xlang(false).compatible(true).build()
 }
 
+fn assert_erased_serializer_container_error(err: fory_core::Error) {
+    let message = err.to_string();
+    assert!(
+        message.contains("Type info for internal type not found")
+            || message.contains("not found in type_info registry")
+            || message.contains("ID harness not found"),
+        "unexpected error: {message}"
+    );
+}
+
 #[test]
 fn test_multiple_types_in_sequence() {
     let fory = fory_compatible();
@@ -74,41 +86,64 @@ fn test_option_some_roundtrip() {
 }
 
 #[test]
-fn test_hashmap_roundtrip() {
+fn trait_object_map_set_payloads_rejected() {
     let fory = fory_compatible();
-    let mut original = HashMap::new();
-    original.insert(String::from("one"), 1);
-    original.insert(String::from("two"), 2);
-    original.insert(String::from("three"), 3);
 
-    let trait_obj: Box<dyn Serializer> = Box::new(original.clone());
-    let serialized = fory.serialize(&trait_obj).unwrap();
-
-    let deserialized_concrete: HashMap<String, i32> = 
fory.deserialize(&serialized).unwrap();
-
-    assert_eq!(deserialized_concrete.len(), 3);
-    assert_eq!(deserialized_concrete.get("one"), Some(&1));
-    assert_eq!(deserialized_concrete.get("two"), Some(&2));
-    assert_eq!(deserialized_concrete.get("three"), Some(&3));
+    let list: Box<dyn Serializer> = Box::new(vec!["one".to_string(), 
"two".to_string()]);
+    
assert_erased_serializer_container_error(fory.serialize(&list).unwrap_err());
+
+    let representative_map: Box<dyn Serializer> = Box::new(HashMap::from([
+        ("one".to_string(), 1_i32),
+        ("two".to_string(), 2),
+    ]));
+    
assert_erased_serializer_container_error(fory.serialize(&representative_map).unwrap_err());
+
+    let other_map: Box<dyn Serializer> = Box::new(HashMap::from([
+        ("one".to_string(), "first".to_string()),
+        ("two".to_string(), "second".to_string()),
+    ]));
+    
assert_erased_serializer_container_error(fory.serialize(&other_map).unwrap_err());
+
+    let representative_set: Box<dyn Serializer> = 
Box::new(HashSet::from([1_i32, 2, 3]));
+    
assert_erased_serializer_container_error(fory.serialize(&representative_set).unwrap_err());
+
+    let other_set: Box<dyn Serializer> = Box::new(HashSet::from([
+        "one".to_string(),
+        "two".to_string(),
+        "three".to_string(),
+    ]));
+    
assert_erased_serializer_container_error(fory.serialize(&other_set).unwrap_err());
 }
 
 #[test]
-fn test_hashset_roundtrip() {
+fn trait_object_map_values_reject_containers() {
     let fory = fory_compatible();
-    let mut original = HashSet::new();
-    original.insert(1);
-    original.insert(2);
-    original.insert(3);
 
-    let trait_obj: Box<dyn Serializer> = Box::new(original.clone());
-    let serialized = fory.serialize(&trait_obj).unwrap();
+    let mut values: HashMap<String, Box<dyn Serializer>> = HashMap::new();
+    values.insert(
+        "map".to_string(),
+        Box::new(HashMap::from([("one".to_string(), 1_i32)])),
+    );
+    
assert_erased_serializer_container_error(fory.serialize(&values).unwrap_err());
+
+    let mut values: HashMap<String, Box<dyn Serializer>> = HashMap::new();
+    values.insert("set".to_string(), Box::new(HashSet::from([1_i32, 2, 3])));
+    
assert_erased_serializer_container_error(fory.serialize(&values).unwrap_err());
+}
 
-    let deserialized_concrete: HashSet<i32> = 
fory.deserialize(&serialized).unwrap();
+#[test]
+fn trait_object_container_type_ids_rejected_on_read() {
+    let fory = fory_compatible();
 
-    assert_eq!(deserialized_concrete.len(), 3);
-    assert!(deserialized_concrete.contains(&1));
-    assert!(deserialized_concrete.contains(&2));
-    assert!(deserialized_concrete.contains(&3));
+    for type_id in [TypeId::LIST, TypeId::SET, TypeId::MAP] {
+        let bytes = vec![0, RefFlag::NotNullValue as i8 as u8, type_id as u8];
+        let result: Result<Box<dyn Serializer>, _> = fory.deserialize(&bytes);
+        let err = match result {
+            Ok(_) => panic!("expected erased container type id to fail"),
+            Err(err) => err,
+        };
+        assert_erased_serializer_container_error(err);
+    }
 }
 
 #[test]
diff --git a/rust/tests/tests/test_unsigned.rs 
b/rust/tests/tests/test_unsigned.rs
index 4f4be267a..dd75467b5 100644
--- a/rust/tests/tests/test_unsigned.rs
+++ b/rust/tests/tests/test_unsigned.rs
@@ -19,8 +19,65 @@ mod test_helpers;
 
 use fory_core::fory::Fory;
 use fory_derive::ForyStruct;
+use std::any::Any;
+use std::rc::Rc;
+use std::sync::Arc;
 use test_helpers::{test_arc_any, test_box_any, test_rc_any, test_roundtrip};
 
+fn assert_erased_container_error(message: String) {
+    assert!(
+        message.contains("top-level erased Any")
+            || message.contains("Erased Any payloads require")
+            || message.contains("cannot be represented as Arc<dyn Any + Send + 
Sync>"),
+        "unexpected error: {message}"
+    );
+}
+
+fn test_box_any_unsupported<T>(fory: &Fory, value: T)
+where
+    T: 'static,
+{
+    let wrapped: Box<dyn Any> = Box::new(value);
+    match fory.serialize(&wrapped) {
+        Ok(bytes) => {
+            let result: Result<Box<dyn Any>, _> = fory.deserialize(&bytes);
+            let err = result.expect_err("expected Box<dyn Any> container read 
to fail");
+            assert_erased_container_error(err.to_string());
+        }
+        Err(err) => assert_erased_container_error(err.to_string()),
+    }
+}
+
+fn test_rc_any_unsupported<T>(fory: &Fory, value: T)
+where
+    T: 'static,
+{
+    let wrapped: Rc<dyn Any> = Rc::new(value);
+    match fory.serialize(&wrapped) {
+        Ok(bytes) => {
+            let result: Result<Rc<dyn Any>, _> = fory.deserialize(&bytes);
+            let err = result.expect_err("expected Rc<dyn Any> container read 
to fail");
+            assert_erased_container_error(err.to_string());
+        }
+        Err(err) => assert_erased_container_error(err.to_string()),
+    }
+}
+
+fn test_arc_any_unsupported<T>(fory: &Fory, value: T)
+where
+    T: 'static + Send + Sync,
+{
+    let wrapped: Arc<dyn Any + Send + Sync> = Arc::new(value);
+    match fory.serialize(&wrapped) {
+        Ok(bytes) => {
+            let result: Result<Arc<dyn Any + Send + Sync>, _> = 
fory.deserialize(&bytes);
+            let err = result.expect_err("expected Arc<dyn Any> container read 
to fail");
+            assert_erased_container_error(err.to_string());
+        }
+        Err(err) => assert_erased_container_error(err.to_string()),
+    };
+}
+
 #[test]
 fn test_unsigned_numbers() {
     let fory = Fory::builder().xlang(false).build();
@@ -443,27 +500,25 @@ fn test_unsigned_with_smart_pointers() {
     test_arc_any(&fory, usize::MAX);
     test_arc_any(&fory, u128::MAX);
 
-    // Test Box<dyn Any> with unsigned arrays
-    test_box_any(&fory, vec![0u8, 127, u8::MAX]);
-    test_box_any(&fory, vec![0u16, 1000, u16::MAX]);
-    test_box_any(&fory, vec![0u32, 1000000, u32::MAX]);
-    test_box_any(&fory, vec![0u64, 1000000000000, u64::MAX]);
-    test_box_any(&fory, vec![0usize, 1000000000000, usize::MAX]);
-    test_box_any(&fory, vec![0u128, 1000000000000, u128::MAX]);
-
-    // Test Rc<dyn Any> with unsigned arrays
-    test_rc_any(&fory, vec![0u8, 127, u8::MAX]);
-    test_rc_any(&fory, vec![100u16, 200, 300, u16::MAX]);
-    test_rc_any(&fory, vec![1000u32, 2000, 3000, u32::MAX]);
-    test_rc_any(&fory, vec![0u64, 1000000000000, u64::MAX]);
-    test_rc_any(&fory, vec![0usize, 1000000000000, usize::MAX]);
-    test_rc_any(&fory, vec![0u128, 1000000000000, u128::MAX]);
-
-    // Test Arc<dyn Any + Send + Sync> with unsigned arrays
-    test_arc_any(&fory, vec![0u8, 127, u8::MAX]);
-    test_arc_any(&fory, vec![100u16, 200, 300, u16::MAX]);
-    test_arc_any(&fory, vec![999u32, 888, 777, u32::MAX]);
-    test_arc_any(&fory, vec![123u64, 456789, 987654321, u64::MAX]);
-    test_arc_any(&fory, vec![123usize, 456789, 987654321, usize::MAX]);
-    test_arc_any(&fory, vec![0u128, 1000000000000, u128::MAX]);
+    // Direct vectors are not supported as top-level erased Any payloads.
+    test_box_any_unsupported(&fory, vec![0u8, 127, u8::MAX]);
+    test_box_any_unsupported(&fory, vec![0u16, 1000, u16::MAX]);
+    test_box_any_unsupported(&fory, vec![0u32, 1000000, u32::MAX]);
+    test_box_any_unsupported(&fory, vec![0u64, 1000000000000, u64::MAX]);
+    test_box_any_unsupported(&fory, vec![0usize, 1000000000000, usize::MAX]);
+    test_box_any_unsupported(&fory, vec![0u128, 1000000000000, u128::MAX]);
+
+    test_rc_any_unsupported(&fory, vec![0u8, 127, u8::MAX]);
+    test_rc_any_unsupported(&fory, vec![100u16, 200, 300, u16::MAX]);
+    test_rc_any_unsupported(&fory, vec![1000u32, 2000, 3000, u32::MAX]);
+    test_rc_any_unsupported(&fory, vec![0u64, 1000000000000, u64::MAX]);
+    test_rc_any_unsupported(&fory, vec![0usize, 1000000000000, usize::MAX]);
+    test_rc_any_unsupported(&fory, vec![0u128, 1000000000000, u128::MAX]);
+
+    test_arc_any_unsupported(&fory, vec![0u8, 127, u8::MAX]);
+    test_arc_any_unsupported(&fory, vec![100u16, 200, 300, u16::MAX]);
+    test_arc_any_unsupported(&fory, vec![999u32, 888, 777, u32::MAX]);
+    test_arc_any_unsupported(&fory, vec![123u64, 456789, 987654321, u64::MAX]);
+    test_arc_any_unsupported(&fory, vec![123usize, 456789, 987654321, 
usize::MAX]);
+    test_arc_any_unsupported(&fory, vec![0u128, 1000000000000, u128::MAX]);
 }


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

Reply via email to