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 4d1679205 fix(rust): output original registered ID in type mismatch 
error log (#3067)
4d1679205 is described below

commit 4d167920521da97ad4d6d3b8d2e1b9c578a42989
Author: userzhy <[email protected]>
AuthorDate: Sun Dec 21 00:55:28 2025 +0800

    fix(rust): output original registered ID in type mismatch error log (#3067)
    
    ## Why?
    
    Current Fory Rust's error messages display the combined type ID (after
    left-shifting) which is confusing for users. For example:
    
    ```text
    FORY_PANIC_ON_ERROR: Type mismatch: type_a = 787, type_b = 6
    ```
    
    Here `787` is the internal combined type ID `(3 << 8) + 19`, but users
    registered using `ID=3`. This makes debugging difficult as users cannot
    easily correlate the error with their registration code.
    
    ## What does this PR do?
    
    This PR improves the type mismatch error message to show the original
    registered ID along with the internal type name:
    
    ```text
    Type mismatch: local registered_id=3(EXT) vs remote INT64
    ```
    
    **Changes:**
    - Added `format_type_id()` function in `types.rs` to parse combined type
    IDs and format them into human-readable strings.
    - Modified `TypeMismatch` error variant to use the formatted string
    message.
    - Added test case to verify the new error message format.
    
    ## Related issues
    
    Closes #3054
    
    ## 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?
    
    The error message format is changed but it only affects the display of
    error messages, not the API or binary protocol.
    
    ## Benchmark
    
    Not applicable. This change only affects error message formatting in the
    error path, which has no impact on serialization/deserialization
    performance.
---
 rust/fory-core/src/error.rs   | 15 ++++++--
 rust/fory-core/src/types.rs   | 87 +++++++++++++++++++++++++++++++++++++++++++
 rust/tests/tests/test_fory.rs | 42 +++++++++++++++++++++
 3 files changed, 141 insertions(+), 3 deletions(-)

diff --git a/rust/fory-core/src/error.rs b/rust/fory-core/src/error.rs
index a27fb4d85..d4c5ec488 100644
--- a/rust/fory-core/src/error.rs
+++ b/rust/fory-core/src/error.rs
@@ -29,6 +29,7 @@
 
 use std::borrow::Cow;
 
+use crate::types::format_type_id;
 use thiserror::Error;
 
 /// Global flag to check if FORY_PANIC_ON_ERROR environment variable is set at 
compile time.
@@ -108,8 +109,8 @@ pub enum Error {
     /// Type mismatch between local and remote type IDs.
     ///
     /// Do not construct this variant directly; use [`Error::type_mismatch`] 
instead.
-    #[error("Type mismatch: type_a = {0}, type_b = {1}")]
-    TypeMismatch(u32, u32),
+    #[error("{0}")]
+    TypeMismatch(Cow<'static, str>),
 
     /// Buffer boundary violation during read/write operations.
     ///
@@ -187,6 +188,9 @@ pub enum Error {
 impl Error {
     /// Creates a new [`Error::TypeMismatch`] with the given type IDs.
     ///
+    /// The error message will display both the original registered ID and the 
internal type name
+    /// for user-registered types, making debugging easier.
+    ///
     /// If `FORY_PANIC_ON_ERROR` environment variable is set, this will panic 
with the error message.
     ///
     /// # Example
@@ -199,7 +203,12 @@ impl Error {
     #[cold]
     #[track_caller]
     pub fn type_mismatch(type_a: u32, type_b: u32) -> Self {
-        let err = Error::TypeMismatch(type_a, type_b);
+        let msg = format!(
+            "Type mismatch: local {} vs remote {}",
+            format_type_id(type_a),
+            format_type_id(type_b)
+        );
+        let err = Error::TypeMismatch(Cow::Owned(msg));
         if PANIC_ON_ERROR {
             panic!("FORY_PANIC_ON_ERROR: {}", err);
         }
diff --git a/rust/fory-core/src/types.rs b/rust/fory-core/src/types.rs
index 6090a493e..dfec7d3ed 100644
--- a/rust/fory-core/src/types.rs
+++ b/rust/fory-core/src/types.rs
@@ -400,3 +400,90 @@ impl TryFrom<u8> for Language {
 pub const SIZE_OF_REF_AND_TYPE: usize = mem::size_of::<i8>() + 
mem::size_of::<i16>();
 
 pub const MAGIC_NUMBER: u16 = 0x62d4;
+
+/// Formats a combined type ID into a human-readable string.
+///
+/// Combined type IDs have the format: `(registered_id << 8) + 
internal_type_id`.
+/// This function extracts both parts and formats them for debugging.
+///
+/// For internal types (type_id < BOUND), returns just the type name.
+/// For user-registered types, returns format like "registered_id=3(STRUCT)".
+///
+/// # Examples
+/// ```
+/// use fory_core::types::format_type_id;
+///
+/// // Internal type (e.g., BOOL = 1)
+/// assert_eq!(format_type_id(1), "BOOL");
+///
+/// // User registered struct with id=3: (3 << 8) + 15 = 783
+/// assert_eq!(format_type_id(783), "registered_id=3(STRUCT)");
+/// ```
+pub fn format_type_id(type_id: u32) -> String {
+    let internal_type_id = type_id & 0xff;
+    let registered_id = type_id >> 8;
+
+    let type_name = match internal_type_id {
+        0 => "UNKNOWN",
+        1 => "BOOL",
+        2 => "INT8",
+        3 => "INT16",
+        4 => "INT32",
+        5 => "VAR_INT32",
+        6 => "INT64",
+        7 => "VAR_INT64",
+        8 => "SLI_INT64",
+        9 => "FLOAT16",
+        10 => "FLOAT32",
+        11 => "FLOAT64",
+        12 => "STRING",
+        13 => "ENUM",
+        14 => "NAMED_ENUM",
+        15 => "STRUCT",
+        16 => "COMPATIBLE_STRUCT",
+        17 => "NAMED_STRUCT",
+        18 => "NAMED_COMPATIBLE_STRUCT",
+        19 => "EXT",
+        20 => "NAMED_EXT",
+        21 => "LIST",
+        22 => "SET",
+        23 => "MAP",
+        24 => "DURATION",
+        25 => "TIMESTAMP",
+        26 => "LOCAL_DATE",
+        27 => "DECIMAL",
+        28 => "BINARY",
+        29 => "ARRAY",
+        30 => "BOOL_ARRAY",
+        31 => "INT8_ARRAY",
+        32 => "INT16_ARRAY",
+        33 => "INT32_ARRAY",
+        34 => "INT64_ARRAY",
+        35 => "FLOAT16_ARRAY",
+        36 => "FLOAT32_ARRAY",
+        37 => "FLOAT64_ARRAY",
+        64 => "U8",
+        65 => "U16",
+        66 => "U32",
+        67 => "U64",
+        68 => "USIZE",
+        69 => "U128",
+        70 => "VAR_U32",
+        71 => "VAR_U64",
+        72 => "SLI_U64",
+        73 => "U16_ARRAY",
+        74 => "U32_ARRAY",
+        75 => "U64_ARRAY",
+        76 => "USIZE_ARRAY",
+        77 => "U128_ARRAY",
+        _ => "UNKNOWN_TYPE",
+    };
+
+    // If it's a pure internal type (no registered_id), just return the type 
name
+    if registered_id == 0 {
+        type_name.to_string()
+    } else {
+        // For user-registered types, show both the registered ID and internal 
type
+        format!("registered_id={}({})", registered_id, type_name)
+    }
+}
diff --git a/rust/tests/tests/test_fory.rs b/rust/tests/tests/test_fory.rs
index fc7096c35..6ad5df6ed 100644
--- a/rust/tests/tests/test_fory.rs
+++ b/rust/tests/tests/test_fory.rs
@@ -286,3 +286,45 @@ fn test_unregistered_type_error_message() {
         err_str
     );
 }
+
+#[test]
+fn test_type_mismatch_error_shows_registered_id() {
+    use fory_core::error::Error;
+    use fory_core::types::format_type_id;
+
+    // Test internal type (BOOL = 1), no registered_id
+    let formatted = format_type_id(1);
+    assert_eq!(formatted, "BOOL");
+
+    // Test user registered struct with id=3: (3 << 8) + 15(STRUCT) = 783
+    let formatted = format_type_id(783);
+    assert_eq!(formatted, "registered_id=3(STRUCT)");
+
+    // Test user registered enum with id=1: (1 << 8) + 13(ENUM) = 269
+    let formatted = format_type_id(269);
+    assert_eq!(formatted, "registered_id=1(ENUM)");
+
+    // Test user registered EXT with id=3: (3 << 8) + 19(EXT) = 787
+    let formatted = format_type_id(787);
+    assert_eq!(formatted, "registered_id=3(EXT)");
+
+    // Test error message format
+    let err = Error::type_mismatch(783, 269);
+    let err_str = format!("{}", err);
+    assert!(
+        err_str.contains("registered_id=3(STRUCT)"),
+        "error should contain registered_id=3(STRUCT), got: {}",
+        err_str
+    );
+    assert!(
+        err_str.contains("registered_id=1(ENUM)"),
+        "error should contain registered_id=1(ENUM), got: {}",
+        err_str
+    );
+    // Check the message contains "local" and "remote" for clarity
+    assert!(
+        err_str.contains("local") && err_str.contains("remote"),
+        "error should indicate local vs remote types, got: {}",
+        err_str
+    );
+}


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

Reply via email to