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 f742b4bf0 feat(rust): support unsigned number for rust (#2857)
f742b4bf0 is described below
commit f742b4bf017f8014506948eb49116d1f65aabc63
Author: Shawn Yang <[email protected]>
AuthorDate: Fri Oct 31 22:32:04 2025 +0800
feat(rust): support unsigned number for rust (#2857)
## Why?
<!-- Describe the purpose of this PR. -->
## What does this PR do?
support unsigend for rust native serialization.
Note that for xlang mode, the unsigend will not be allowed
## Related issues
<!--
Is there any related issue? If this PR closes them you say say
fix/closes:
- #xxxx0
- #xxxx1
- Fixes #xxxx2
-->
## Does this PR introduce any user-facing change?
<!--
If any user-facing interface changes, please [open an
issue](https://github.com/apache/fory/issues/new/choose) describing the
need to do so and update the document if necessary.
Delete section if not applicable.
-->
- [ ] Does this PR introduce any public API change?
- [ ] Does this PR introduce any binary protocol compatibility change?
## Benchmark
<!--
When the PR has an impact on performance (if you don't know whether the
PR will have an impact on performance, you can submit the PR first, and
if it will have impact on performance, the code reviewer will explain
it), be sure to attach a benchmark data here.
Delete section if not applicable.
-->
---
AGENTS.md | 2 +
rust/fory-core/Cargo.toml | 1 -
rust/fory-core/src/meta/type_meta.rs | 4 +
rust/fory-core/src/resolver/type_resolver.rs | 12 +
rust/fory-core/src/serializer/box_.rs | 16 ++
rust/fory-core/src/serializer/core.rs | 8 +
rust/fory-core/src/serializer/list.rs | 160 ++++++++---
rust/fory-core/src/serializer/mod.rs | 1 +
rust/fory-core/src/serializer/mutex.rs | 21 ++
rust/fory-core/src/serializer/option.rs | 7 +
rust/fory-core/src/serializer/primitive_list.rs | 13 +-
rust/fory-core/src/serializer/refcell.rs | 21 ++
rust/fory-core/src/serializer/skip.rs | 8 +
rust/fory-core/src/serializer/trait_object.rs | 27 ++
rust/fory-core/src/serializer/unsigned_number.rs | 94 +++++++
rust/fory-core/src/serializer/util.rs | 6 +-
rust/fory-core/src/types.rs | 62 ++++-
rust/fory-derive/Cargo.toml | 1 -
rust/fory-derive/src/object/util.rs | 15 +-
rust/tests/tests/compatible/test_struct_enum.rs | 2 +-
rust/tests/tests/test_helpers.rs | 65 +++++
rust/tests/tests/test_unsigned.rs | 339 +++++++++++++++++++++++
22 files changed, 825 insertions(+), 60 deletions(-)
diff --git a/AGENTS.md b/AGENTS.md
index d1468a686..4c5772a21 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -125,6 +125,8 @@ go generate ./...
- All changes to `rust` must pass the clippy check and tests.
- You must set `RUST_BACKTRACE=1 FORY_PANIC_ON_ERROR=1` when debuging rust
tests to get backtrace.
- You must not set `FORY_PANIC_ON_ERROR=1` when runing all rust tests to check
whether all tests pass, some tests will check Error content, which will fail if
error just panic.
+- When making changes to enum discriminant values in Rust, always run `cargo
clean` to ensure no stale build artifacts
+ remain.
```bash
# Check code
diff --git a/rust/fory-core/Cargo.toml b/rust/fory-core/Cargo.toml
index de95ce180..912782a74 100644
--- a/rust/fory-core/Cargo.toml
+++ b/rust/fory-core/Cargo.toml
@@ -21,7 +21,6 @@ version.workspace = true
edition.workspace = true
rust-version.workspace = true
description = "Apache Fory: Blazingly fast multi-language serialization
framework with trait objects and reference support."
-license = "Apache-2.0"
license-file = "../../LICENSE"
readme = "../README.md"
repository = "https://github.com/apache/fory"
diff --git a/rust/fory-core/src/meta/type_meta.rs
b/rust/fory-core/src/meta/type_meta.rs
index eaf908d6d..8ef3019db 100644
--- a/rust/fory-core/src/meta/type_meta.rs
+++ b/rust/fory-core/src/meta/type_meta.rs
@@ -407,6 +407,10 @@ impl TypeMetaLayer {
TypeId::FLOAT16 => 2,
TypeId::FLOAT32 => 4,
TypeId::FLOAT64 => 8,
+ TypeId::U8 => 1,
+ TypeId::U16 => 2,
+ TypeId::U32 => 4,
+ TypeId::U64 => 8,
_ => unreachable!(),
}
}
diff --git a/rust/fory-core/src/resolver/type_resolver.rs
b/rust/fory-core/src/resolver/type_resolver.rs
index 35bd9b53a..9b0a5ae7b 100644
--- a/rust/fory-core/src/resolver/type_resolver.rs
+++ b/rust/fory-core/src/resolver/type_resolver.rs
@@ -24,9 +24,11 @@ use crate::meta::{
use crate::serializer::{ForyDefault, Serializer, StructSerializer};
use crate::util::get_ext_actual_type_id;
use crate::{Reader, TypeId};
+use chrono::{NaiveDate, NaiveDateTime};
use std::collections::{HashSet, LinkedList};
use std::rc::Rc;
use std::vec;
+
use std::{any::Any, collections::HashMap};
type WriteFn = fn(
@@ -455,7 +457,13 @@ impl TypeResolver {
self.register_internal_serializer::<i64>(TypeId::INT64)?;
self.register_internal_serializer::<f32>(TypeId::FLOAT32)?;
self.register_internal_serializer::<f64>(TypeId::FLOAT64)?;
+ self.register_internal_serializer::<u8>(TypeId::U8)?;
+ self.register_internal_serializer::<u16>(TypeId::U16)?;
+ self.register_internal_serializer::<u32>(TypeId::U32)?;
+ self.register_internal_serializer::<u64>(TypeId::U64)?;
self.register_internal_serializer::<String>(TypeId::STRING)?;
+ self.register_internal_serializer::<NaiveDateTime>(TypeId::TIMESTAMP)?;
+ self.register_internal_serializer::<NaiveDate>(TypeId::LOCAL_DATE)?;
self.register_internal_serializer::<Vec<bool>>(TypeId::BOOL_ARRAY)?;
self.register_internal_serializer::<Vec<i8>>(TypeId::INT8_ARRAY)?;
@@ -464,6 +472,10 @@ impl TypeResolver {
self.register_internal_serializer::<Vec<i64>>(TypeId::INT64_ARRAY)?;
self.register_internal_serializer::<Vec<f32>>(TypeId::FLOAT32_ARRAY)?;
self.register_internal_serializer::<Vec<f64>>(TypeId::FLOAT64_ARRAY)?;
+ self.register_internal_serializer::<Vec<u8>>(TypeId::BINARY)?;
+ self.register_internal_serializer::<Vec<u16>>(TypeId::U16_ARRAY)?;
+ self.register_internal_serializer::<Vec<u32>>(TypeId::U32_ARRAY)?;
+ self.register_internal_serializer::<Vec<u64>>(TypeId::U64_ARRAY)?;
self.register_generic_trait::<Vec<String>>()?;
self.register_generic_trait::<LinkedList<i32>>()?;
self.register_generic_trait::<LinkedList<String>>()?;
diff --git a/rust/fory-core/src/serializer/box_.rs
b/rust/fory-core/src/serializer/box_.rs
index 79bd3c729..17c2bf0de 100644
--- a/rust/fory-core/src/serializer/box_.rs
+++ b/rust/fory-core/src/serializer/box_.rs
@@ -23,6 +23,7 @@ use crate::serializer::{ForyDefault, Serializer};
use crate::types::TypeId;
impl<T: Serializer + ForyDefault> Serializer for Box<T> {
+ #[inline(always)]
fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error>
where
Self: Sized + ForyDefault,
@@ -30,34 +31,49 @@ impl<T: Serializer + ForyDefault> Serializer for Box<T> {
Ok(Box::new(T::fory_read_data(context)?))
}
+ #[inline(always)]
fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
T::fory_read_type_info(context)
}
+ #[inline(always)]
fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error>
{
T::fory_write_data(self.as_ref(), context)
}
+ #[inline(always)]
fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
T::fory_write_type_info(context)
}
+ #[inline(always)]
fn fory_reserved_space() -> usize {
T::fory_reserved_space()
}
+ #[inline(always)]
fn fory_get_type_id(type_resolver: &TypeResolver) -> Result<u32, Error> {
T::fory_get_type_id(type_resolver)
}
+ #[inline(always)]
fn fory_type_id_dyn(&self, type_resolver: &TypeResolver) -> Result<u32,
Error> {
(**self).fory_type_id_dyn(type_resolver)
}
+ #[inline(always)]
fn fory_static_type_id() -> TypeId {
T::fory_static_type_id()
}
+ fn fory_is_wrapper_type() -> bool
+ where
+ Self: Sized,
+ {
+ true
+ }
+
+ #[inline(always)]
fn as_any(&self) -> &dyn std::any::Any {
self
}
diff --git a/rust/fory-core/src/serializer/core.rs
b/rust/fory-core/src/serializer/core.rs
index a8888ada8..9e17b6d04 100644
--- a/rust/fory-core/src/serializer/core.rs
+++ b/rust/fory-core/src/serializer/core.rs
@@ -1052,6 +1052,14 @@ pub trait Serializer: 'static {
false
}
+ #[inline(always)]
+ fn fory_is_wrapper_type() -> bool
+ where
+ Self: Sized,
+ {
+ Self::fory_is_shared_ref()
+ }
+
/// Get the static Fory type ID for this type.
///
/// Type IDs are Fory's internal type identification system, separate from
diff --git a/rust/fory-core/src/serializer/list.rs
b/rust/fory-core/src/serializer/list.rs
index b562e5323..504a5b992 100644
--- a/rust/fory-core/src/serializer/list.rs
+++ b/rust/fory-core/src/serializer/list.rs
@@ -22,7 +22,6 @@ use crate::resolver::type_resolver::TypeResolver;
use crate::serializer::primitive_list;
use crate::serializer::{ForyDefault, Serializer};
use crate::types::TypeId;
-use std::any::TypeId as RsTypeId;
use std::collections::{LinkedList, VecDeque};
use std::mem;
@@ -31,109 +30,162 @@ use super::collection::{
write_collection_type_info,
};
-fn check_primitive<T: 'static>() -> Option<TypeId> {
- Some(match RsTypeId::of::<T>() {
- id if id == RsTypeId::of::<bool>() => TypeId::BOOL_ARRAY,
- id if id == RsTypeId::of::<i8>() => TypeId::INT8_ARRAY,
- id if id == RsTypeId::of::<i16>() => TypeId::INT16_ARRAY,
- id if id == RsTypeId::of::<i32>() => TypeId::INT32_ARRAY,
- id if id == RsTypeId::of::<i64>() => TypeId::INT64_ARRAY,
- id if id == RsTypeId::of::<f32>() => TypeId::FLOAT32_ARRAY,
- id if id == RsTypeId::of::<f64>() => TypeId::FLOAT64_ARRAY,
- _ => return None,
- })
+#[inline(always)]
+fn get_primitive_type_id<T: Serializer>() -> TypeId {
+ if T::fory_is_wrapper_type() {
+ return TypeId::UNKNOWN;
+ }
+ match T::fory_static_type_id() {
+ TypeId::BOOL => TypeId::BOOL_ARRAY,
+ TypeId::INT8 => TypeId::INT8_ARRAY,
+ TypeId::INT16 => TypeId::INT16_ARRAY,
+ TypeId::INT32 => TypeId::INT32_ARRAY,
+ TypeId::INT64 => TypeId::INT64_ARRAY,
+ TypeId::FLOAT32 => TypeId::FLOAT32_ARRAY,
+ TypeId::FLOAT64 => TypeId::FLOAT64_ARRAY,
+ TypeId::U16 => TypeId::U16_ARRAY,
+ TypeId::U32 => TypeId::U32_ARRAY,
+ TypeId::U64 => TypeId::U64_ARRAY,
+ _ => TypeId::UNKNOWN,
+ }
+}
+
+#[inline(always)]
+pub fn is_primitive_type<T: Serializer>() -> bool {
+ if T::fory_is_wrapper_type() {
+ return false;
+ }
+ matches!(
+ T::fory_static_type_id(),
+ TypeId::BOOL
+ | TypeId::INT8
+ | TypeId::INT16
+ | TypeId::INT32
+ | TypeId::INT64
+ | TypeId::FLOAT32
+ | TypeId::FLOAT64
+ | TypeId::U8
+ | TypeId::U16
+ | TypeId::U32
+ | TypeId::U64
+ )
}
impl<T: Serializer + ForyDefault> Serializer for Vec<T> {
+ #[inline(always)]
fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error>
{
- match check_primitive::<T>() {
- Some(_) => primitive_list::fory_write_data(self, context),
- None => write_collection_data(self, context, false),
+ if is_primitive_type::<T>() {
+ primitive_list::fory_write_data(self, context)
+ } else {
+ write_collection_data(self, context, false)
}
}
+ #[inline(always)]
fn fory_write_data_generic(
&self,
context: &mut WriteContext,
has_generics: bool,
) -> Result<(), Error> {
- match check_primitive::<T>() {
- Some(_) => primitive_list::fory_write_data(self, context),
- None => write_collection_data(self, context, has_generics),
+ if is_primitive_type::<T>() {
+ primitive_list::fory_write_data(self, context)
+ } else {
+ write_collection_data(self, context, has_generics)
}
}
+ #[inline(always)]
fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
- match check_primitive::<T>() {
- Some(type_id) => primitive_list::fory_write_type_info(context,
type_id),
- None => write_collection_type_info(context, TypeId::LIST as u32),
+ let id = get_primitive_type_id::<T>();
+ if id != TypeId::UNKNOWN {
+ primitive_list::fory_write_type_info(context, id)
+ } else {
+ write_collection_type_info(context, TypeId::LIST as u32)
}
}
+ #[inline(always)]
fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
- match check_primitive::<T>() {
- Some(_) => primitive_list::fory_read_data(context),
- None => read_collection_data(context),
+ if is_primitive_type::<T>() {
+ primitive_list::fory_read_data(context)
+ } else {
+ read_collection_data(context)
}
}
+ #[inline(always)]
fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
- match check_primitive::<T>() {
- Some(type_id) => primitive_list::fory_read_type_info(context,
type_id),
- None => read_collection_type_info(context, TypeId::LIST as u32),
+ let id = get_primitive_type_id::<T>();
+ if id != TypeId::UNKNOWN {
+ primitive_list::fory_read_type_info(context, id)
+ } else {
+ read_collection_type_info(context, TypeId::LIST as u32)
}
}
+ #[inline(always)]
fn fory_reserved_space() -> usize {
- match check_primitive::<T>() {
- Some(_) => primitive_list::fory_reserved_space::<T>(),
- None => {
- // size of the vec
- mem::size_of::<u32>()
- }
+ if is_primitive_type::<T>() {
+ primitive_list::fory_reserved_space::<T>()
+ } else {
+ // size of the vec
+ mem::size_of::<u32>()
}
}
+ #[inline(always)]
fn fory_get_type_id(_: &TypeResolver) -> Result<u32, Error> {
- Ok(match check_primitive::<T>() {
- Some(type_id) => type_id as u32,
- None => TypeId::LIST as u32,
- })
+ let id = get_primitive_type_id::<T>();
+ if id != TypeId::UNKNOWN {
+ Ok(id as u32)
+ } else {
+ Ok(TypeId::LIST as u32)
+ }
}
+ #[inline(always)]
fn fory_type_id_dyn(&self, _: &TypeResolver) -> Result<u32, Error> {
- Ok(match check_primitive::<T>() {
- Some(type_id) => type_id as u32,
- None => TypeId::LIST as u32,
- })
+ let id = get_primitive_type_id::<T>();
+ if id != TypeId::UNKNOWN {
+ Ok(id as u32)
+ } else {
+ Ok(TypeId::LIST as u32)
+ }
}
+ #[inline(always)]
fn fory_static_type_id() -> TypeId
where
Self: Sized,
{
- match check_primitive::<T>() {
- Some(type_id) => type_id,
- None => TypeId::LIST,
+ let id = get_primitive_type_id::<T>();
+ if id != TypeId::UNKNOWN {
+ id
+ } else {
+ TypeId::LIST
}
}
+ #[inline(always)]
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
impl<T> ForyDefault for Vec<T> {
+ #[inline(always)]
fn fory_default() -> Self {
Vec::new()
}
}
impl<T: Serializer + ForyDefault> Serializer for VecDeque<T> {
+ #[inline(always)]
fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error>
{
write_collection_data(self, context, false)
}
+ #[inline(always)]
fn fory_write_data_generic(
&self,
context: &mut WriteContext,
@@ -142,50 +194,61 @@ impl<T: Serializer + ForyDefault> Serializer for
VecDeque<T> {
write_collection_data(self, context, has_generics)
}
+ #[inline(always)]
fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
write_collection_type_info(context, TypeId::LIST as u32)
}
+ #[inline(always)]
fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
read_collection_data(context)
}
+ #[inline(always)]
fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
read_collection_type_info(context, TypeId::LIST as u32)
}
+ #[inline(always)]
fn fory_reserved_space() -> usize {
mem::size_of::<u32>()
}
+ #[inline(always)]
fn fory_get_type_id(_: &TypeResolver) -> Result<u32, Error> {
Ok(TypeId::LIST as u32)
}
+ #[inline(always)]
fn fory_type_id_dyn(&self, _: &TypeResolver) -> Result<u32, Error> {
Ok(TypeId::LIST as u32)
}
+ #[inline(always)]
fn fory_static_type_id() -> TypeId {
TypeId::LIST
}
+ #[inline(always)]
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
impl<T> ForyDefault for VecDeque<T> {
+ #[inline(always)]
fn fory_default() -> Self {
VecDeque::new()
}
}
impl<T: Serializer + ForyDefault> Serializer for LinkedList<T> {
+ #[inline(always)]
fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error>
{
write_collection_data(self, context, false)
}
+ #[inline(always)]
fn fory_write_data_generic(
&self,
context: &mut WriteContext,
@@ -194,40 +257,49 @@ impl<T: Serializer + ForyDefault> Serializer for
LinkedList<T> {
write_collection_data(self, context, has_generics)
}
+ #[inline(always)]
fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
write_collection_type_info(context, TypeId::LIST as u32)
}
+ #[inline(always)]
fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
read_collection_data(context)
}
+ #[inline(always)]
fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
read_collection_type_info(context, TypeId::LIST as u32)
}
+ #[inline(always)]
fn fory_reserved_space() -> usize {
mem::size_of::<u32>()
}
+ #[inline(always)]
fn fory_get_type_id(_: &TypeResolver) -> Result<u32, Error> {
Ok(TypeId::LIST as u32)
}
+ #[inline(always)]
fn fory_type_id_dyn(&self, _: &TypeResolver) -> Result<u32, Error> {
Ok(TypeId::LIST as u32)
}
+ #[inline(always)]
fn fory_static_type_id() -> TypeId {
TypeId::LIST
}
+ #[inline(always)]
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
impl<T> ForyDefault for LinkedList<T> {
+ #[inline(always)]
fn fory_default() -> Self {
LinkedList::new()
}
diff --git a/rust/fory-core/src/serializer/mod.rs
b/rust/fory-core/src/serializer/mod.rs
index b173355a4..af07b8674 100644
--- a/rust/fory-core/src/serializer/mod.rs
+++ b/rust/fory-core/src/serializer/mod.rs
@@ -36,6 +36,7 @@ pub mod skip;
mod string;
pub mod struct_;
pub mod trait_object;
+mod unsigned_number;
pub mod util;
pub mod weak;
diff --git a/rust/fory-core/src/serializer/mutex.rs
b/rust/fory-core/src/serializer/mutex.rs
index fd9c7e788..0b1281ab6 100644
--- a/rust/fory-core/src/serializer/mutex.rs
+++ b/rust/fory-core/src/serializer/mutex.rs
@@ -54,6 +54,7 @@ use std::sync::Mutex;
/// Simply delegates to the serializer for `T`, allowing thread-safe interior
mutable
/// containers to be included in serialized graphs.
impl<T: Serializer + ForyDefault> Serializer for Mutex<T> {
+ #[inline(always)]
fn fory_write(
&self,
context: &mut WriteContext,
@@ -73,6 +74,7 @@ impl<T: Serializer + ForyDefault> Serializer for Mutex<T> {
)
}
+ #[inline(always)]
fn fory_write_data_generic(
&self,
context: &mut WriteContext,
@@ -81,21 +83,25 @@ impl<T: Serializer + ForyDefault> Serializer for Mutex<T> {
T::fory_write_data_generic(&*self.lock().unwrap(), context,
has_generics)
}
+ #[inline(always)]
fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error>
{
// When called from Rc/Arc, just delegate to inner type's data
serialization
let guard = self.lock().unwrap();
T::fory_write_data(&*guard, context)
}
+ #[inline(always)]
fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
T::fory_write_type_info(context)
}
+ #[inline(always)]
fn fory_reserved_space() -> usize {
// Mutex is transparent, delegate to inner type
T::fory_reserved_space()
}
+ #[inline(always)]
fn fory_read(
context: &mut ReadContext,
read_ref_info: bool,
@@ -111,6 +117,7 @@ impl<T: Serializer + ForyDefault> Serializer for Mutex<T> {
)?))
}
+ #[inline(always)]
fn fory_read_with_type_info(
context: &mut ReadContext,
read_ref_info: bool,
@@ -126,27 +133,41 @@ impl<T: Serializer + ForyDefault> Serializer for Mutex<T>
{
)?))
}
+ #[inline(always)]
fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
Ok(Mutex::new(T::fory_read_data(context)?))
}
+ #[inline(always)]
fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
T::fory_read_type_info(context)
}
+ #[inline(always)]
fn fory_get_type_id(type_resolver: &TypeResolver) -> Result<u32, Error> {
T::fory_get_type_id(type_resolver)
}
+ #[inline(always)]
fn fory_type_id_dyn(&self, type_resolver: &TypeResolver) -> Result<u32,
Error> {
let guard = self.lock().unwrap();
(*guard).fory_type_id_dyn(type_resolver)
}
+ #[inline(always)]
fn fory_static_type_id() -> TypeId {
T::fory_static_type_id()
}
+ #[inline(always)]
+ fn fory_is_wrapper_type() -> bool
+ where
+ Self: Sized,
+ {
+ true
+ }
+
+ #[inline(always)]
fn as_any(&self) -> &dyn std::any::Any {
self
}
diff --git a/rust/fory-core/src/serializer/option.rs
b/rust/fory-core/src/serializer/option.rs
index ea888e8e8..01495011d 100644
--- a/rust/fory-core/src/serializer/option.rs
+++ b/rust/fory-core/src/serializer/option.rs
@@ -152,6 +152,13 @@ impl<T: Serializer + ForyDefault> Serializer for Option<T>
{
T::fory_static_type_id()
}
+ fn fory_is_wrapper_type() -> bool
+ where
+ Self: Sized,
+ {
+ true
+ }
+
#[inline(always)]
fn as_any(&self) -> &dyn std::any::Any {
self
diff --git a/rust/fory-core/src/serializer/primitive_list.rs
b/rust/fory-core/src/serializer/primitive_list.rs
index 997df44e1..fc31ed748 100644
--- a/rust/fory-core/src/serializer/primitive_list.rs
+++ b/rust/fory-core/src/serializer/primitive_list.rs
@@ -19,9 +19,20 @@ use crate::ensure;
use crate::error::Error;
use crate::resolver::context::ReadContext;
use crate::resolver::context::WriteContext;
+use crate::serializer::Serializer;
use crate::types::TypeId;
-pub fn fory_write_data<T>(this: &[T], context: &mut WriteContext) ->
Result<(), Error> {
+pub fn fory_write_data<T: Serializer>(this: &[T], context: &mut WriteContext)
-> Result<(), Error> {
+ if context.is_xlang()
+ && matches!(
+ T::fory_static_type_id(),
+ TypeId::U16 | TypeId::U32 | TypeId::U64
+ )
+ {
+ return Err(Error::not_allowed(
+ "Unsigned types are not supported in cross-language mode",
+ ));
+ }
let len_bytes = std::mem::size_of_val(this);
context.writer.write_varuint32(len_bytes as u32);
diff --git a/rust/fory-core/src/serializer/refcell.rs
b/rust/fory-core/src/serializer/refcell.rs
index 0012fffe8..b2a5d6c2d 100644
--- a/rust/fory-core/src/serializer/refcell.rs
+++ b/rust/fory-core/src/serializer/refcell.rs
@@ -45,6 +45,7 @@ use std::rc::Rc;
/// Simply delegates to the serializer for `T`, allowing interior mutable
/// containers to be included in serialized graphs.
impl<T: Serializer + ForyDefault> Serializer for RefCell<T> {
+ #[inline(always)]
fn fory_read(
context: &mut ReadContext,
read_ref_info: bool,
@@ -60,6 +61,7 @@ impl<T: Serializer + ForyDefault> Serializer for RefCell<T> {
)?))
}
+ #[inline(always)]
fn fory_read_with_type_info(
context: &mut ReadContext,
read_ref_info: bool,
@@ -75,14 +77,17 @@ impl<T: Serializer + ForyDefault> Serializer for RefCell<T>
{
)?))
}
+ #[inline(always)]
fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
Ok(RefCell::new(T::fory_read_data(context)?))
}
+ #[inline(always)]
fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
T::fory_read_type_info(context)
}
+ #[inline(always)]
fn fory_write(
&self,
context: &mut WriteContext,
@@ -101,6 +106,7 @@ impl<T: Serializer + ForyDefault> Serializer for RefCell<T>
{
)
}
+ #[inline(always)]
fn fory_write_data_generic(
&self,
context: &mut WriteContext,
@@ -109,27 +115,33 @@ impl<T: Serializer + ForyDefault> Serializer for
RefCell<T> {
T::fory_write_data_generic(&*self.borrow(), context, has_generics)
}
+ #[inline(always)]
fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error>
{
T::fory_write_data(&*self.borrow(), context)
}
+ #[inline(always)]
fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
T::fory_write_type_info(context)
}
+ #[inline(always)]
fn fory_reserved_space() -> usize {
// RefCell is transparent, delegate to inner type
T::fory_reserved_space()
}
+ #[inline(always)]
fn fory_get_type_id(type_resolver: &TypeResolver) -> Result<u32, Error> {
T::fory_get_type_id(type_resolver)
}
+ #[inline(always)]
fn fory_type_id_dyn(&self, type_resolver: &TypeResolver) -> Result<u32,
Error> {
(*self.borrow()).fory_type_id_dyn(type_resolver)
}
+ #[inline(always)]
fn fory_static_type_id() -> TypeId
where
Self: Sized,
@@ -137,6 +149,15 @@ impl<T: Serializer + ForyDefault> Serializer for
RefCell<T> {
T::fory_static_type_id()
}
+ #[inline(always)]
+ fn fory_is_wrapper_type() -> bool
+ where
+ Self: Sized,
+ {
+ true
+ }
+
+ #[inline(always)]
fn as_any(&self) -> &dyn std::any::Any {
self
}
diff --git a/rust/fory-core/src/serializer/skip.rs
b/rust/fory-core/src/serializer/skip.rs
index 524d0ab26..c63df3218 100644
--- a/rust/fory-core/src/serializer/skip.rs
+++ b/rust/fory-core/src/serializer/skip.rs
@@ -76,6 +76,7 @@ pub fn skip_value(
(String, STRING),
(NaiveDate, LOCAL_DATE),
(NaiveDateTime, TIMESTAMP),
+ (Vec<u8>, BINARY),
(Vec<bool> , BOOL_ARRAY),
(Vec<i8> , INT8_ARRAY),
(Vec<i16> , INT16_ARRAY),
@@ -83,6 +84,13 @@ pub fn skip_value(
(Vec<i64> , INT64_ARRAY),
(Vec<f32>, FLOAT32_ARRAY),
(Vec<f64> , FLOAT64_ARRAY),
+ (u8, U8),
+ (u16, U16),
+ (u32, U32),
+ (u64, U64),
+ (Vec<u16> , U16_ARRAY),
+ (Vec<u32> , U32_ARRAY),
+ (Vec<u64> , U64_ARRAY),
);
} else if CONTAINER_TYPES.contains(&type_id) {
if type_id == TypeId::LIST || type_id == TypeId::SET {
diff --git a/rust/fory-core/src/serializer/trait_object.rs
b/rust/fory-core/src/serializer/trait_object.rs
index b9dc28f25..7a70e2345 100644
--- a/rust/fory-core/src/serializer/trait_object.rs
+++ b/rust/fory-core/src/serializer/trait_object.rs
@@ -159,21 +159,25 @@ macro_rules! register_trait_type {
// 4. Serializer implementation for Box<dyn Trait> (existing
functionality)
impl fory_core::Serializer for Box<dyn $trait_name> {
+ #[inline(always)]
fn fory_write(&self, context: &mut fory_core::WriteContext,
write_ref_info: bool, write_type_info: bool, has_generics: bool) -> Result<(),
fory_core::Error> {
let any_ref = <dyn $trait_name as
fory_core::Serializer>::as_any(&**self);
fory_core::serializer::write_box_any(any_ref, context,
write_ref_info, write_type_info, has_generics)
}
+ #[inline(always)]
fn fory_write_data(&self, context: &mut fory_core::WriteContext)
-> Result<(), fory_core::Error> {
let any_ref = <dyn $trait_name as
fory_core::Serializer>::as_any(&**self);
fory_core::serializer::write_box_any(any_ref, context, false,
false, false)
}
+ #[inline(always)]
fn fory_write_data_generic(&self, context: &mut
fory_core::WriteContext, has_generics: bool) -> Result<(), fory_core::Error> {
let any_ref = <dyn $trait_name as
fory_core::Serializer>::as_any(&**self);
fory_core::serializer::write_box_any(any_ref, context, false,
false, has_generics)
}
+ #[inline(always)]
fn fory_type_id_dyn(&self, type_resolver:
&fory_core::TypeResolver) -> Result<u32, fory_core::Error> {
let any_ref = <dyn $trait_name as
fory_core::Serializer>::as_any(&**self);
let concrete_type_id = any_ref.type_id();
@@ -182,6 +186,7 @@ macro_rules! register_trait_type {
.ok_or_else(|| fory_core::Error::type_error("Type not
registered for trait object"))
}
+ #[inline(always)]
fn fory_is_polymorphic() -> bool {
true
}
@@ -241,18 +246,22 @@ macro_rules! register_trait_type {
$crate::not_allowed!("fory_get_type_id should not be called
directly on polymorphic Box<dyn {}> trait object", stringify!($trait_name))
}
+ #[inline(always)]
fn fory_static_type_id() -> fory_core::TypeId {
fory_core::TypeId::UNKNOWN
}
+ #[inline(always)]
fn fory_reserved_space() -> usize {
$crate::types::SIZE_OF_REF_AND_TYPE
}
+ #[inline(always)]
fn fory_concrete_type_id(&self) -> std::any::TypeId {
<dyn $trait_name as
fory_core::Serializer>::as_any(&**self).type_id()
}
+ #[inline(always)]
fn as_any(&self) -> &dyn std::any::Any {
<dyn $trait_name as fory_core::Serializer>::as_any(&**self)
}
@@ -486,30 +495,37 @@ macro_rules! impl_smart_pointer_serializer {
$crate::not_allowed!("fory_read_data should not be called
directly on polymorphic {}<dyn {}> trait object", stringify!($ptr_path),
stringify!($trait_name))
}
+ #[inline(always)]
fn fory_get_type_id(_type_resolver: &fory_core::TypeResolver) ->
Result<u32, fory_core::Error> {
Ok(fory_core::TypeId::STRUCT as u32)
}
+ #[inline(always)]
fn fory_static_type_id() -> fory_core::TypeId {
fory_core::TypeId::UNKNOWN
}
+ #[inline(always)]
fn fory_write_type_info(_context: &mut fory_core::WriteContext) ->
Result<(), fory_core::Error> {
Ok(())
}
+ #[inline(always)]
fn fory_read_type_info(_context: &mut fory_core::ReadContext) ->
Result<(), fory_core::Error> {
Ok(())
}
+ #[inline(always)]
fn fory_is_polymorphic() -> bool {
true
}
+ #[inline(always)]
fn fory_is_shared_ref() -> bool {
true
}
+ #[inline(always)]
fn fory_type_id_dyn(&self, type_resolver:
&fory_core::TypeResolver) -> Result<u32, fory_core::Error> {
let any_obj = <dyn $trait_name as
fory_core::Serializer>::as_any(&*self.0);
let concrete_type_id = any_obj.type_id();
@@ -518,10 +534,12 @@ macro_rules! impl_smart_pointer_serializer {
.ok_or_else(|| fory_core::Error::type_error("Type not
registered for trait object"))
}
+ #[inline(always)]
fn fory_concrete_type_id(&self) -> std::any::TypeId {
<dyn $trait_name as
fory_core::Serializer>::as_any(&*self.0).type_id()
}
+ #[inline(always)]
fn as_any(&self) -> &dyn std::any::Any {
<dyn $trait_name as fory_core::Serializer>::as_any(&*self.0)
}
@@ -583,6 +601,7 @@ impl ForyDefault for Box<dyn Serializer> {
}
impl Serializer for Box<dyn Serializer> {
+ #[inline(always)]
fn fory_concrete_type_id(&self) -> std::any::TypeId {
(**self).fory_concrete_type_id()
}
@@ -605,10 +624,12 @@ impl Serializer for Box<dyn Serializer> {
self.fory_write_data_generic(context, has_generics)
}
+ #[inline(always)]
fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error>
{
self.fory_write_data_generic(context, false)
}
+ #[inline(always)]
fn fory_write_data_generic(
&self,
context: &mut WriteContext,
@@ -617,14 +638,17 @@ impl Serializer for Box<dyn Serializer> {
(**self).fory_write_data_generic(context, has_generics)
}
+ #[inline(always)]
fn fory_type_id_dyn(&self, type_resolver: &TypeResolver) -> Result<u32,
Error> {
(**self).fory_type_id_dyn(type_resolver)
}
+ #[inline(always)]
fn as_any(&self) -> &dyn std::any::Any {
(**self).as_any()
}
+ #[inline(always)]
fn fory_is_polymorphic() -> bool {
true
}
@@ -635,11 +659,13 @@ impl Serializer for Box<dyn Serializer> {
))
}
+ #[inline(always)]
fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
context.read_any_typeinfo()?;
Ok(())
}
+ #[inline(always)]
fn fory_read(
context: &mut ReadContext,
read_ref_info: bool,
@@ -648,6 +674,7 @@ impl Serializer for Box<dyn Serializer> {
read_box_seralizer(context, read_ref_info, read_type_info, None)
}
+ #[inline(always)]
fn fory_read_with_type_info(
context: &mut ReadContext,
read_ref_info: bool,
diff --git a/rust/fory-core/src/serializer/unsigned_number.rs
b/rust/fory-core/src/serializer/unsigned_number.rs
new file mode 100644
index 000000000..4ac8089da
--- /dev/null
+++ b/rust/fory-core/src/serializer/unsigned_number.rs
@@ -0,0 +1,94 @@
+// 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.
+
+use crate::buffer::{Reader, Writer};
+use crate::error::Error;
+use crate::resolver::context::ReadContext;
+use crate::resolver::context::WriteContext;
+use crate::resolver::type_resolver::TypeResolver;
+use crate::serializer::util::read_basic_type_info;
+use crate::serializer::{ForyDefault, Serializer};
+use crate::types::TypeId;
+
+macro_rules! impl_unsigned_num_serializer {
+ ($ty:ty, $writer:expr, $reader:expr, $field_type:expr) => {
+ impl Serializer for $ty {
+ #[inline(always)]
+ fn fory_write_data(&self, context: &mut WriteContext) ->
Result<(), Error> {
+ if context.is_xlang() {
+ return Err(Error::not_allowed(
+ "Unsigned types are not supported in cross-language
mode",
+ ));
+ }
+ $writer(&mut context.writer, *self);
+ Ok(())
+ }
+
+ #[inline(always)]
+ fn fory_read_data(context: &mut ReadContext) -> Result<Self,
Error> {
+ $reader(&mut context.reader)
+ }
+
+ #[inline(always)]
+ fn fory_reserved_space() -> usize {
+ std::mem::size_of::<$ty>()
+ }
+
+ #[inline(always)]
+ fn fory_get_type_id(_: &TypeResolver) -> Result<u32, Error> {
+ Ok($field_type as u32)
+ }
+
+ #[inline(always)]
+ fn fory_type_id_dyn(&self, _: &TypeResolver) -> Result<u32, Error>
{
+ Ok($field_type as u32)
+ }
+
+ #[inline(always)]
+ fn fory_static_type_id() -> TypeId {
+ $field_type
+ }
+
+ #[inline(always)]
+ fn as_any(&self) -> &dyn std::any::Any {
+ self
+ }
+
+ #[inline(always)]
+ fn fory_write_type_info(context: &mut WriteContext) -> Result<(),
Error> {
+ context.writer.write_varuint32($field_type as u32);
+ Ok(())
+ }
+
+ #[inline(always)]
+ fn fory_read_type_info(context: &mut ReadContext) -> Result<(),
Error> {
+ read_basic_type_info::<Self>(context)
+ }
+ }
+ impl ForyDefault for $ty {
+ #[inline(always)]
+ fn fory_default() -> Self {
+ 0 as $ty
+ }
+ }
+ };
+}
+
+impl_unsigned_num_serializer!(u8, Writer::write_u8, Reader::read_u8,
TypeId::U8);
+impl_unsigned_num_serializer!(u16, Writer::write_u16, Reader::read_u16,
TypeId::U16);
+impl_unsigned_num_serializer!(u32, Writer::write_u32, Reader::read_u32,
TypeId::U32);
+impl_unsigned_num_serializer!(u64, Writer::write_u64, Reader::read_u64,
TypeId::U64);
diff --git a/rust/fory-core/src/serializer/util.rs
b/rust/fory-core/src/serializer/util.rs
index a4adca7b4..6f6b606a8 100644
--- a/rust/fory-core/src/serializer/util.rs
+++ b/rust/fory-core/src/serializer/util.rs
@@ -21,7 +21,7 @@ use crate::resolver::context::{ReadContext, WriteContext};
use crate::serializer::Serializer;
use crate::types::TypeId;
-const NO_REF_FLAG_TYPE_IDS: [u32; 7] = [
+const NO_REF_FLAG_TYPE_IDS: [u32; 11] = [
TypeId::BOOL as u32,
TypeId::INT8 as u32,
TypeId::INT16 as u32,
@@ -29,6 +29,10 @@ const NO_REF_FLAG_TYPE_IDS: [u32; 7] = [
TypeId::INT64 as u32,
TypeId::FLOAT32 as u32,
TypeId::FLOAT64 as u32,
+ TypeId::U8 as u32,
+ TypeId::U16 as u32,
+ TypeId::U32 as u32,
+ TypeId::U64 as u32,
];
#[inline(always)]
diff --git a/rust/fory-core/src/types.rs b/rust/fory-core/src/types.rs
index e4f177a8d..a718683a2 100644
--- a/rust/fory-core/src/types.rs
+++ b/rust/fory-core/src/types.rs
@@ -81,7 +81,17 @@ pub enum TypeId {
FLOAT64_ARRAY = 37,
ARROW_RECORD_BATCH = 38,
ARROW_TABLE = 39,
- UNKNOWN = 63,
+ U8 = 64,
+ U16 = 65,
+ U32 = 66,
+ U64 = 67,
+ VAR_U32 = 68,
+ VAR_U64 = 69,
+ SLI_U64 = 70,
+ U16_ARRAY = 71,
+ U32_ARRAY = 72,
+ U64_ARRAY = 73,
+ UNKNOWN = 74,
}
pub const BOOL: u32 = TypeId::BOOL as u32;
@@ -123,6 +133,16 @@ pub const FLOAT32_ARRAY: u32 = TypeId::FLOAT32_ARRAY as
u32;
pub const FLOAT64_ARRAY: u32 = TypeId::FLOAT64_ARRAY as u32;
pub const ARROW_RECORD_BATCH: u32 = TypeId::ARROW_RECORD_BATCH as u32;
pub const ARROW_TABLE: u32 = TypeId::ARROW_TABLE as u32;
+pub const U8: u32 = TypeId::U8 as u32;
+pub const U16: u32 = TypeId::U16 as u32;
+pub const U32: u32 = TypeId::U32 as u32;
+pub const U64: u32 = TypeId::U64 as u32;
+pub const VAR_U32: u32 = TypeId::VAR_U32 as u32;
+pub const VAR_U64: u32 = TypeId::VAR_U64 as u32;
+pub const SLI_U64: u32 = TypeId::SLI_U64 as u32;
+pub const U16_ARRAY: u32 = TypeId::U16_ARRAY as u32;
+pub const U32_ARRAY: u32 = TypeId::U32_ARRAY as u32;
+pub const U64_ARRAY: u32 = TypeId::U64_ARRAY as u32;
pub const UNKNOWN: u32 = TypeId::UNKNOWN as u32;
const MAX_UNT32: u64 = (1 << 31) - 1;
@@ -140,7 +160,7 @@ pub fn compute_string_hash(s: &str) -> u32 {
hash as u32
}
-pub static BASIC_TYPES: [TypeId; 18] = [
+pub static BASIC_TYPES: [TypeId; 25] = [
TypeId::BOOL,
TypeId::INT8,
TypeId::INT16,
@@ -159,9 +179,16 @@ pub static BASIC_TYPES: [TypeId; 18] = [
TypeId::INT64_ARRAY,
TypeId::FLOAT32_ARRAY,
TypeId::FLOAT64_ARRAY,
+ TypeId::U8,
+ TypeId::U16,
+ TypeId::U32,
+ TypeId::U64,
+ TypeId::U16_ARRAY,
+ TypeId::U32_ARRAY,
+ TypeId::U64_ARRAY,
];
-pub static PRIMITIVE_TYPES: [u32; 7] = [
+pub static PRIMITIVE_TYPES: [u32; 11] = [
TypeId::BOOL as u32,
TypeId::INT8 as u32,
TypeId::INT16 as u32,
@@ -169,9 +196,13 @@ pub static PRIMITIVE_TYPES: [u32; 7] = [
TypeId::INT64 as u32,
TypeId::FLOAT32 as u32,
TypeId::FLOAT64 as u32,
+ TypeId::U8 as u32,
+ TypeId::U16 as u32,
+ TypeId::U32 as u32,
+ TypeId::U64 as u32,
];
-pub static PRIMITIVE_ARRAY_TYPES: [u32; 8] = [
+pub static PRIMITIVE_ARRAY_TYPES: [u32; 11] = [
TypeId::BOOL_ARRAY as u32,
TypeId::BINARY as u32,
TypeId::INT8_ARRAY as u32,
@@ -180,9 +211,12 @@ pub static PRIMITIVE_ARRAY_TYPES: [u32; 8] = [
TypeId::INT64_ARRAY as u32,
TypeId::FLOAT32_ARRAY as u32,
TypeId::FLOAT64_ARRAY as u32,
+ TypeId::U16_ARRAY as u32,
+ TypeId::U32_ARRAY as u32,
+ TypeId::U64_ARRAY as u32,
];
-pub static BASIC_TYPE_NAMES: [&str; 10] = [
+pub static BASIC_TYPE_NAMES: [&str; 14] = [
"bool",
"i8",
"i16",
@@ -193,6 +227,10 @@ pub static BASIC_TYPE_NAMES: [&str; 10] = [
"String",
"NaiveDate",
"NaiveDateTime",
+ "u8",
+ "u16",
+ "u32",
+ "u64",
];
pub static CONTAINER_TYPES: [TypeId; 3] = [TypeId::LIST, TypeId::SET,
TypeId::MAP];
@@ -200,7 +238,7 @@ pub static CONTAINER_TYPES: [TypeId; 3] = [TypeId::LIST,
TypeId::SET, TypeId::MA
pub static CONTAINER_TYPE_NAMES: [&str; 3] = ["Vec", "HashSet", "HashMap"];
pub static PRIMITIVE_ARRAY_TYPE_MAP: &[(&str, u32, &str)] = &[
- // ("_binary", TypeId::BINARY as u32),
+ ("u8", TypeId::BINARY as u32, "Vec<u8>"),
("bool", TypeId::BOOL_ARRAY as u32, "Vec<bool>"),
("i8", TypeId::INT8_ARRAY as u32, "Vec<i8>"),
("i16", TypeId::INT16_ARRAY as u32, "Vec<i16>"),
@@ -208,10 +246,13 @@ pub static PRIMITIVE_ARRAY_TYPE_MAP: &[(&str, u32, &str)]
= &[
("i64", TypeId::INT64_ARRAY as u32, "Vec<i64>"),
("f32", TypeId::FLOAT32_ARRAY as u32, "Vec<f32>"),
("f64", TypeId::FLOAT64_ARRAY as u32, "Vec<f64>"),
+ ("u16", TypeId::U16_ARRAY as u32, "Vec<u16>"),
+ ("u32", TypeId::U32_ARRAY as u32, "Vec<u32>"),
+ ("u64", TypeId::U64_ARRAY as u32, "Vec<u64>"),
];
#[inline(always)]
-pub fn is_primitive_type(type_id: TypeId) -> bool {
+pub fn is_primitive_type_id(type_id: TypeId) -> bool {
matches!(
type_id,
TypeId::BOOL
@@ -221,9 +262,10 @@ pub fn is_primitive_type(type_id: TypeId) -> bool {
| TypeId::INT64
| TypeId::FLOAT32
| TypeId::FLOAT64
- | TypeId::STRING
- | TypeId::LOCAL_DATE
- | TypeId::TIMESTAMP
+ | TypeId::U8
+ | TypeId::U16
+ | TypeId::U32
+ | TypeId::U64
)
}
diff --git a/rust/fory-derive/Cargo.toml b/rust/fory-derive/Cargo.toml
index fca232160..8e354cc21 100644
--- a/rust/fory-derive/Cargo.toml
+++ b/rust/fory-derive/Cargo.toml
@@ -21,7 +21,6 @@ version.workspace = true
edition.workspace = true
rust-version.workspace = true
description = "Apache Fory: Blazingly fast multi-language serialization
framework with trait objects and reference support."
-license = "Apache-2.0"
license-file = "../../LICENSE"
readme = "../README.md"
repository = "https://github.com/apache/fory"
diff --git a/rust/fory-derive/src/object/util.rs
b/rust/fory-derive/src/object/util.rs
index a2c4bfc07..0c8b34066 100644
--- a/rust/fory-derive/src/object/util.rs
+++ b/rust/fory-derive/src/object/util.rs
@@ -422,7 +422,9 @@ fn extract_option_inner(s: &str) -> Option<&str> {
s.strip_prefix("Option<")?.strip_suffix(">")
}
-const PRIMITIVE_TYPE_NAMES: [&str; 7] = ["bool", "i8", "i16", "i32", "i64",
"f32", "f64"];
+const PRIMITIVE_TYPE_NAMES: [&str; 11] = [
+ "bool", "i8", "i16", "i32", "i64", "f32", "f64", "u8", "u16", "u32", "u64",
+];
fn get_primitive_type_id(ty: &str) -> u32 {
match ty {
@@ -433,6 +435,10 @@ fn get_primitive_type_id(ty: &str) -> u32 {
"i64" => TypeId::INT64 as u32,
"f32" => TypeId::FLOAT32 as u32,
"f64" => TypeId::FLOAT64 as u32,
+ "u8" => TypeId::U8 as u32,
+ "u16" => TypeId::U16 as u32,
+ "u32" => TypeId::U32 as u32,
+ "u64" => TypeId::U64 as u32,
_ => unreachable!("Unknown primitive type: {}", ty),
}
}
@@ -484,6 +490,9 @@ pub(crate) fn get_type_id_by_name(ty: &str) -> u32 {
"Vec<f16>" => return TypeId::FLOAT16_ARRAY as u32,
"Vec<f32>" => return TypeId::FLOAT32_ARRAY as u32,
"Vec<f64>" => return TypeId::FLOAT64_ARRAY as u32,
+ "Vec<u16>" => return TypeId::U16_ARRAY as u32,
+ "Vec<u32>" => return TypeId::U32_ARRAY as u32,
+ "Vec<u64>" => return TypeId::U64_ARRAY as u32,
_ => {}
}
@@ -521,6 +530,10 @@ fn get_primitive_type_size(type_id_num: u32) -> i32 {
TypeId::FLOAT16 => 2,
TypeId::FLOAT32 => 4,
TypeId::FLOAT64 => 8,
+ TypeId::U8 => 1,
+ TypeId::U16 => 2,
+ TypeId::U32 => 4,
+ TypeId::U64 => 8,
_ => unreachable!(),
}
}
diff --git a/rust/tests/tests/compatible/test_struct_enum.rs
b/rust/tests/tests/compatible/test_struct_enum.rs
index c9ba13869..411556a4d 100644
--- a/rust/tests/tests/compatible/test_struct_enum.rs
+++ b/rust/tests/tests/compatible/test_struct_enum.rs
@@ -101,7 +101,7 @@ fn simple_write_continuous() {
let animal1: Animal1 = fory.deserialize_from(reader).unwrap();
let animal2: Animal1 = fory.deserialize_from(reader).unwrap();
let animal3: Animal1 = fory.deserialize_from(reader).unwrap();
- let result = vec![animal1, animal2, animal3];
+ let result = [animal1, animal2, animal3];
result.iter().for_each(|x| {
assert_eq!(animal.f1, x.f1);
assert_eq!(animal.f2, x.f2);
diff --git a/rust/tests/tests/test_helpers.rs b/rust/tests/tests/test_helpers.rs
new file mode 100644
index 000000000..c3afe5dbf
--- /dev/null
+++ b/rust/tests/tests/test_helpers.rs
@@ -0,0 +1,65 @@
+// 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.
+
+use fory_core::fory::Fory;
+use fory_core::{ForyDefault, Serializer};
+use std::any::Any;
+use std::rc::Rc;
+use std::sync::Arc;
+
+/// Generic helper function for roundtrip serialization testing
+pub fn test_roundtrip<T>(fory: &Fory, value: T)
+where
+ T: Serializer + ForyDefault + PartialEq + std::fmt::Debug,
+{
+ let bytes = fory.serialize(&value).unwrap();
+ let result: T = fory.deserialize(&bytes).unwrap();
+ assert_eq!(value, result);
+}
+
+/// Generic helper for testing Box<dyn Any> serialization
+pub fn test_box_any<T>(fory: &Fory, value: T)
+where
+ T: 'static + PartialEq + std::fmt::Debug + Clone,
+{
+ let wrapped: Box<dyn Any> = Box::new(value.clone());
+ let bytes = fory.serialize(&wrapped).unwrap();
+ let result: Box<dyn Any> = fory.deserialize(&bytes).unwrap();
+ assert_eq!(result.downcast_ref::<T>().unwrap(), &value);
+}
+
+/// Generic helper for testing Rc<dyn Any> serialization
+pub fn test_rc_any<T>(fory: &Fory, value: T)
+where
+ T: 'static + PartialEq + std::fmt::Debug + Clone,
+{
+ let wrapped: Rc<dyn Any> = Rc::new(value.clone());
+ let bytes = fory.serialize(&wrapped).unwrap();
+ let result: Rc<dyn Any> = fory.deserialize(&bytes).unwrap();
+ assert_eq!(result.downcast_ref::<T>().unwrap(), &value);
+}
+
+/// Generic helper for testing Arc<dyn Any> serialization
+pub fn test_arc_any<T>(fory: &Fory, value: T)
+where
+ T: 'static + PartialEq + std::fmt::Debug + Clone,
+{
+ let wrapped: Arc<dyn Any> = Arc::new(value.clone());
+ let bytes = fory.serialize(&wrapped).unwrap();
+ let result: Arc<dyn Any> = fory.deserialize(&bytes).unwrap();
+ assert_eq!(result.downcast_ref::<T>().unwrap(), &value);
+}
diff --git a/rust/tests/tests/test_unsigned.rs
b/rust/tests/tests/test_unsigned.rs
new file mode 100644
index 000000000..d667c12f5
--- /dev/null
+++ b/rust/tests/tests/test_unsigned.rs
@@ -0,0 +1,339 @@
+// 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.
+
+mod test_helpers;
+
+use fory_core::fory::Fory;
+use fory_derive::ForyObject;
+use test_helpers::{test_arc_any, test_box_any, test_rc_any, test_roundtrip};
+
+#[test]
+fn test_unsigned_numbers() {
+ let fory = Fory::default();
+ test_roundtrip(&fory, 255u8);
+ test_roundtrip(&fory, 65535u16);
+ test_roundtrip(&fory, 4294967295u32);
+ test_roundtrip(&fory, 18446744073709551615u64);
+}
+
+#[test]
+fn test_unsigned_arrays() {
+ let fory = Fory::default();
+ test_roundtrip(&fory, vec![0u8, 1, 2, 255]);
+ test_roundtrip(&fory, vec![0u16, 100, 1000, 65535]);
+ test_roundtrip(&fory, vec![0u32, 1000, 1000000, 4294967295]);
+ test_roundtrip(
+ &fory,
+ vec![0u64, 1000000, 1000000000000, 18446744073709551615],
+ );
+}
+
+#[test]
+fn test_unsigned_struct_non_compatible() {
+ #[derive(ForyObject, Debug, PartialEq)]
+ struct UnsignedData {
+ a: u8,
+ b: u16,
+ c: u32,
+ d: u64,
+ vec_u16: Vec<u16>,
+ vec_u32: Vec<u32>,
+ vec_u64: Vec<u64>,
+ }
+
+ let mut fory = Fory::default();
+ fory.register::<UnsignedData>(100).unwrap();
+
+ let data = UnsignedData {
+ a: 255,
+ b: 65535,
+ c: 4294967295,
+ d: 18446744073709551615,
+ vec_u16: vec![0, 100, 1000, 65535],
+ vec_u32: vec![0, 1000, 1000000, 4294967295],
+ vec_u64: vec![0, 1000000, 1000000000000, 18446744073709551615],
+ };
+
+ let bytes = fory.serialize(&data).unwrap();
+ let result: UnsignedData = fory.deserialize(&bytes).unwrap();
+ assert_eq!(data, result);
+}
+
+#[test]
+fn test_unsigned_struct_compatible() {
+ #[derive(ForyObject, Debug, PartialEq)]
+ struct UnsignedData {
+ a: u8,
+ b: u16,
+ c: u32,
+ d: u64,
+ vec_u16: Vec<u16>,
+ vec_u32: Vec<u32>,
+ vec_u64: Vec<u64>,
+ }
+
+ let mut fory = Fory::default().compatible(true);
+ fory.register::<UnsignedData>(100).unwrap();
+
+ let data = UnsignedData {
+ a: 255,
+ b: 65535,
+ c: 4294967295,
+ d: 18446744073709551615,
+ vec_u16: vec![0, 100, 1000, 65535],
+ vec_u32: vec![0, 1000, 1000000, 4294967295],
+ vec_u64: vec![0, 1000000, 1000000000000, 18446744073709551615],
+ };
+
+ let bytes = fory.serialize(&data).unwrap();
+ let result: UnsignedData = fory.deserialize(&bytes).unwrap();
+ assert_eq!(data, result);
+}
+
+#[test]
+fn test_unsigned_struct_compatible_add_field() {
+ #[derive(ForyObject, Debug)]
+ struct UnsignedDataV1 {
+ a: u8,
+ b: u16,
+ }
+
+ #[derive(ForyObject, Debug)]
+ struct UnsignedDataV2 {
+ a: u8,
+ b: u16,
+ c: u32,
+ }
+
+ let mut fory1 = Fory::default().compatible(true);
+ let mut fory2 = Fory::default().compatible(true);
+ fory1.register::<UnsignedDataV1>(101).unwrap();
+ fory2.register::<UnsignedDataV2>(101).unwrap();
+
+ let data_v1 = UnsignedDataV1 { a: 255, b: 65535 };
+ let bytes = fory1.serialize(&data_v1).unwrap();
+ let result: UnsignedDataV2 = fory2.deserialize(&bytes).unwrap();
+ assert_eq!(result.a, 255);
+ assert_eq!(result.b, 65535);
+ assert_eq!(result.c, 0); // Default value for missing field
+}
+
+#[test]
+fn test_unsigned_struct_compatible_remove_field() {
+ #[derive(ForyObject, Debug)]
+ struct UnsignedDataV1 {
+ a: u8,
+ b: u16,
+ c: u32,
+ }
+
+ #[derive(ForyObject, Debug)]
+ struct UnsignedDataV2 {
+ a: u8,
+ b: u16,
+ }
+
+ let mut fory1 = Fory::default().compatible(true);
+ let mut fory2 = Fory::default().compatible(true);
+ fory1.register::<UnsignedDataV1>(102).unwrap();
+ fory2.register::<UnsignedDataV2>(102).unwrap();
+
+ let data_v1 = UnsignedDataV1 {
+ a: 255,
+ b: 65535,
+ c: 4294967295,
+ };
+ let bytes = fory1.serialize(&data_v1).unwrap();
+ let result: UnsignedDataV2 = fory2.deserialize(&bytes).unwrap();
+ assert_eq!(result.a, 255);
+ assert_eq!(result.b, 65535);
+ // Field c is ignored during deserialization
+}
+
+#[test]
+fn test_unsigned_edge_cases() {
+ let fory = Fory::default();
+
+ // Test minimum values
+ test_roundtrip(&fory, 0u8);
+ test_roundtrip(&fory, 0u16);
+ test_roundtrip(&fory, 0u32);
+ test_roundtrip(&fory, 0u64);
+
+ // Test maximum values
+ test_roundtrip(&fory, u8::MAX);
+ test_roundtrip(&fory, u16::MAX);
+ test_roundtrip(&fory, u32::MAX);
+ test_roundtrip(&fory, u64::MAX);
+
+ // Test empty arrays
+ test_roundtrip(&fory, Vec::<u8>::new());
+ test_roundtrip(&fory, Vec::<u16>::new());
+ test_roundtrip(&fory, Vec::<u32>::new());
+ test_roundtrip(&fory, Vec::<u64>::new());
+}
+
+#[test]
+fn test_unsigned_with_option_non_compatible() {
+ #[derive(ForyObject, Debug, PartialEq)]
+ struct OptionalUnsigned {
+ opt_u8: Option<u8>,
+ opt_u16: Option<u16>,
+ opt_u32: Option<u32>,
+ opt_u64: Option<u64>,
+ }
+
+ let mut fory = Fory::default();
+ fory.register::<OptionalUnsigned>(103).unwrap();
+
+ // Test with Some values
+ let data_some = OptionalUnsigned {
+ opt_u8: Some(255),
+ opt_u16: Some(65535),
+ opt_u32: Some(4294967295),
+ opt_u64: Some(18446744073709551615),
+ };
+
+ let bytes = fory.serialize(&data_some).unwrap();
+ let result: OptionalUnsigned = fory.deserialize(&bytes).unwrap();
+ assert_eq!(data_some, result);
+
+ // Test with None values
+ let data_none = OptionalUnsigned {
+ opt_u8: None,
+ opt_u16: None,
+ opt_u32: None,
+ opt_u64: None,
+ };
+
+ let bytes = fory.serialize(&data_none).unwrap();
+ let result: OptionalUnsigned = fory.deserialize(&bytes).unwrap();
+ assert_eq!(data_none, result);
+}
+
+#[test]
+fn test_unsigned_with_option_compatible() {
+ #[derive(ForyObject, Debug, PartialEq)]
+ struct OptionalUnsigned {
+ opt_u8: Option<u8>,
+ opt_u16: Option<u16>,
+ opt_u32: Option<u32>,
+ opt_u64: Option<u64>,
+ }
+
+ let mut fory = Fory::default().compatible(true);
+ fory.register::<OptionalUnsigned>(104).unwrap();
+
+ // Test with Some values
+ let data_some = OptionalUnsigned {
+ opt_u8: Some(255),
+ opt_u16: Some(65535),
+ opt_u32: Some(4294967295),
+ opt_u64: Some(18446744073709551615),
+ };
+
+ let bytes = fory.serialize(&data_some).unwrap();
+ let result: OptionalUnsigned = fory.deserialize(&bytes).unwrap();
+ assert_eq!(data_some, result);
+
+ // Test with None values
+ let data_none = OptionalUnsigned {
+ opt_u8: None,
+ opt_u16: None,
+ opt_u32: None,
+ opt_u64: None,
+ };
+
+ let bytes = fory.serialize(&data_none).unwrap();
+ let result: OptionalUnsigned = fory.deserialize(&bytes).unwrap();
+ assert_eq!(data_none, result);
+}
+
+#[test]
+fn test_unsigned_mixed_fields_compatible() {
+ #[derive(ForyObject, Debug)]
+ struct MixedDataV1 {
+ required_u8: u8,
+ optional_u16: Option<u16>,
+ vec_u32: Vec<u32>,
+ }
+
+ #[derive(ForyObject, Debug)]
+ struct MixedDataV2 {
+ required_u8: u8,
+ optional_u16: Option<u16>,
+ vec_u32: Vec<u32>,
+ new_u64: u64,
+ new_opt_u32: Option<u32>,
+ }
+
+ let mut fory1 = Fory::default().compatible(true);
+ let mut fory2 = Fory::default().compatible(true);
+ fory1.register::<MixedDataV1>(105).unwrap();
+ fory2.register::<MixedDataV2>(105).unwrap();
+
+ let data_v1 = MixedDataV1 {
+ required_u8: 255,
+ optional_u16: Some(65535),
+ vec_u32: vec![1000, 2000, 3000],
+ };
+
+ let bytes = fory1.serialize(&data_v1).unwrap();
+ let result: MixedDataV2 = fory2.deserialize(&bytes).unwrap();
+ assert_eq!(result.required_u8, 255);
+ assert_eq!(result.optional_u16, Some(65535));
+ assert_eq!(result.vec_u32, vec![1000, 2000, 3000]);
+ assert_eq!(result.new_u64, 0); // Default value
+ assert_eq!(result.new_opt_u32, None); // Default value
+}
+
+#[test]
+fn test_unsigned_with_smart_pointers() {
+ let fory = Fory::default();
+
+ // Test Box<dyn Any> with unsigned types
+ test_box_any(&fory, 255u8);
+ test_box_any(&fory, 65535u16);
+ test_box_any(&fory, 4294967295u32);
+ test_box_any(&fory, 18446744073709551615u64);
+
+ // Test Rc<dyn Any> with unsigned types
+ test_rc_any(&fory, 255u8);
+ test_rc_any(&fory, 65535u16);
+ test_rc_any(&fory, 4294967295u32);
+ test_rc_any(&fory, 18446744073709551615u64);
+
+ // Test Arc<dyn Any> with unsigned types
+ test_arc_any(&fory, 255u8);
+ test_arc_any(&fory, 65535u16);
+ test_arc_any(&fory, 4294967295u32);
+ test_arc_any(&fory, 18446744073709551615u64);
+
+ // Test Box<dyn Any> with unsigned arrays
+ test_box_any(&fory, vec![0u8, 127, 255]);
+ test_box_any(&fory, vec![0u16, 1000, 65535]);
+ test_box_any(&fory, vec![0u32, 1000000, 4294967295]);
+ test_box_any(&fory, vec![0u64, 1000000000000, 18446744073709551615]);
+
+ // Test Rc<dyn Any> with unsigned arrays
+ test_rc_any(&fory, vec![100u16, 200, 300, 65535]);
+ test_rc_any(&fory, vec![1000u32, 2000, 3000, 4294967295]);
+
+ // Test Arc<dyn Any> with unsigned arrays
+ test_arc_any(&fory, vec![999u32, 888, 777, 4294967295]);
+ test_arc_any(&fory, vec![123u64, 456789, 987654321, 18446744073709551615]);
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]