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

chaokunyang pushed a commit to tag v0.13.2-rc1
in repository https://gitbox.apache.org/repos/asf/fory.git

commit f70fb18b3fb148176c9dd5f24a2263b36d0de117
Author: Shawn Yang <[email protected]>
AuthorDate: Tue Nov 4 13:03:44 2025 +0800

    feat(rust): direct derive primitve write/read (#2890)
    
    ## Why?
    
    <!-- Describe the purpose of this PR. -->
    
    ## What does this PR do?
    
    direct derive primitve write/read for smaller code size and beffer
    compiler optimization
    
    ## 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.
    -->
---
 rust/fory-core/src/buffer.rs         |  5 ++++
 rust/fory-derive/src/object/read.rs  | 16 +++++++++--
 rust/fory-derive/src/object/util.rs  | 53 ++++++++++++++++++++++++++++++++++++
 rust/fory-derive/src/object/write.rs | 24 ++++++++++++++--
 4 files changed, 92 insertions(+), 6 deletions(-)

diff --git a/rust/fory-core/src/buffer.rs b/rust/fory-core/src/buffer.rs
index b91d9617b..6d214710b 100644
--- a/rust/fory-core/src/buffer.rs
+++ b/rust/fory-core/src/buffer.rs
@@ -79,6 +79,11 @@ impl<'a> Writer<'a> {
         v.len()
     }
 
+    #[inline(always)]
+    pub fn write_bool(&mut self, value: bool) {
+        self.bf.write_u8(if value { 1 } else { 0 }).unwrap();
+    }
+
     #[inline(always)]
     pub fn write_u8(&mut self, value: u8) {
         self.bf.write_u8(value).unwrap();
diff --git a/rust/fory-derive/src/object/read.rs 
b/rust/fory-derive/src/object/read.rs
index cc76199d2..015f2736c 100644
--- a/rust/fory-derive/src/object/read.rs
+++ b/rust/fory-derive/src/object/read.rs
@@ -21,8 +21,9 @@ use syn::Field;
 
 use super::util::{
     classify_trait_object_field, compute_struct_version_hash, 
create_wrapper_types_arc,
-    create_wrapper_types_rc, extract_type_name, get_struct_name, 
is_debug_enabled,
-    is_primitive_type, is_skip_field, should_skip_type_info_for_field, 
skip_ref_flag, StructField,
+    create_wrapper_types_rc, extract_type_name, get_primitive_reader_method, 
get_struct_name,
+    is_debug_enabled, is_direct_primitive_numeric_type, is_primitive_type, 
is_skip_field,
+    should_skip_type_info_for_field, skip_ref_flag, StructField,
 };
 
 pub(crate) fn create_private_field_name(field: &Field) -> Ident {
@@ -185,7 +186,16 @@ pub fn gen_read_field(field: &Field, private_ident: 
&Ident) -> TokenStream {
         _ => {
             let skip_ref_flag = skip_ref_flag(ty);
             let skip_type_info = should_skip_type_info_for_field(ty);
-            if skip_type_info {
+
+            // Check if this is a direct primitive numeric type that can use 
direct reader calls
+            if is_direct_primitive_numeric_type(ty) {
+                let type_name = extract_type_name(ty);
+                let reader_method = get_primitive_reader_method(&type_name);
+                let reader_ident = syn::Ident::new(reader_method, 
proc_macro2::Span::call_site());
+                quote! {
+                    let #private_ident = context.reader.#reader_ident()?;
+                }
+            } else if skip_type_info {
                 // Known types (primitives, strings, collections) - skip type 
info at compile time
                 if skip_ref_flag {
                     quote! {
diff --git a/rust/fory-derive/src/object/util.rs 
b/rust/fory-derive/src/object/util.rs
index 578d38d0c..b9d8bd2e8 100644
--- a/rust/fory-derive/src/object/util.rs
+++ b/rust/fory-derive/src/object/util.rs
@@ -567,6 +567,59 @@ pub(super) fn is_primitive_type(ty: &str) -> bool {
     PRIMITIVE_TYPE_NAMES.contains(&ty)
 }
 
+/// Mapping of primitive type names to their writer and reader method names
+/// Order: (type_name, writer_method, reader_method)
+static PRIMITIVE_IO_METHODS: &[(&str, &str, &str)] = &[
+    ("bool", "write_bool", "read_bool"),
+    ("i8", "write_i8", "read_i8"),
+    ("i16", "write_i16", "read_i16"),
+    ("i32", "write_varint32", "read_varint32"),
+    ("i64", "write_varint64", "read_varint64"),
+    ("f32", "write_f32", "read_f32"),
+    ("f64", "write_f64", "read_f64"),
+    ("u8", "write_u8", "read_u8"),
+    ("u16", "write_u16", "read_u16"),
+    ("u32", "write_u32", "read_u32"),
+    ("u64", "write_u64", "read_u64"),
+    ("usize", "write_usize", "read_usize"),
+];
+
+/// Check if a type is a direct primitive numeric type (not wrapped in Option, 
Vec, etc.)
+pub(super) fn is_direct_primitive_numeric_type(ty: &Type) -> bool {
+    if let Type::Path(type_path) = ty {
+        if let Some(seg) = type_path.path.segments.last() {
+            // Check if it's a simple type path without generics
+            if matches!(seg.arguments, PathArguments::None) {
+                let type_name = seg.ident.to_string();
+                return PRIMITIVE_IO_METHODS
+                    .iter()
+                    .any(|(name, _, _)| *name == type_name.as_str());
+            }
+        }
+    }
+    false
+}
+
+/// Get the writer method name for a primitive numeric type
+/// Panics if type_name is not a primitive type
+pub(super) fn get_primitive_writer_method(type_name: &str) -> &'static str {
+    PRIMITIVE_IO_METHODS
+        .iter()
+        .find(|(name, _, _)| *name == type_name)
+        .map(|(_, writer, _)| *writer)
+        .unwrap_or_else(|| panic!("type_name '{}' must be a primitive type", 
type_name))
+}
+
+/// Get the reader method name for a primitive numeric type
+/// Panics if type_name is not a primitive type
+pub(super) fn get_primitive_reader_method(type_name: &str) -> &'static str {
+    PRIMITIVE_IO_METHODS
+        .iter()
+        .find(|(name, _, _)| *name == type_name)
+        .map(|(_, _, reader)| *reader)
+        .unwrap_or_else(|| panic!("type_name '{}' must be a primitive type", 
type_name))
+}
+
 pub(crate) fn get_type_id_by_type_ast(ty: &Type) -> u32 {
     let ty_str: String = ty
         .to_token_stream()
diff --git a/rust/fory-derive/src/object/write.rs 
b/rust/fory-derive/src/object/write.rs
index fd9981bb5..4f95f766e 100644
--- a/rust/fory-derive/src/object/write.rs
+++ b/rust/fory-derive/src/object/write.rs
@@ -17,8 +17,9 @@
 
 use super::util::{
     classify_trait_object_field, compute_struct_version_hash, 
create_wrapper_types_arc,
-    create_wrapper_types_rc, get_filtered_fields_iter, get_struct_name, 
get_type_id_by_type_ast,
-    is_debug_enabled, should_skip_type_info_for_field, skip_ref_flag, 
StructField,
+    create_wrapper_types_rc, extract_type_name, get_filtered_fields_iter,
+    get_primitive_writer_method, get_struct_name, get_type_id_by_type_ast, 
is_debug_enabled,
+    is_direct_primitive_numeric_type, should_skip_type_info_for_field, 
skip_ref_flag, StructField,
 };
 use fory_core::types::TypeId;
 use proc_macro2::{Ident, TokenStream};
@@ -185,7 +186,24 @@ pub fn gen_write_field(field: &Field, ident: &Ident, 
use_self: bool) -> TokenStr
             let skip_ref_flag = skip_ref_flag(ty);
             let skip_type_info = should_skip_type_info_for_field(ty);
             let type_id = get_type_id_by_type_ast(ty);
-            if type_id == TypeId::LIST as u32
+
+            // Check if this is a direct primitive numeric type that can use 
direct writer calls
+            if is_direct_primitive_numeric_type(ty) {
+                let type_name = extract_type_name(ty);
+                let writer_method = get_primitive_writer_method(&type_name);
+                let writer_ident = syn::Ident::new(writer_method, 
proc_macro2::Span::call_site());
+                // For primitives:
+                // - use_self=true: #value_ts is `self.field`, which is T 
(copy happens automatically)
+                // - use_self=false: #value_ts is `field` from pattern match 
on &self, which is &T
+                let value_expr = if use_self {
+                    quote! { #value_ts }
+                } else {
+                    quote! { *#value_ts }
+                };
+                quote! {
+                    context.writer.#writer_ident(#value_expr);
+                }
+            } else if type_id == TypeId::LIST as u32
                 || type_id == TypeId::SET as u32
                 || type_id == TypeId::MAP as u32
             {


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

Reply via email to