From 02175a1d3a65bf95862d72b5c4f6ed2e84bb0a07 Mon Sep 17 00:00:00 2001 From: kaori-seasons Date: Tue, 28 Oct 2025 14:15:52 +0800 Subject: [PATCH 1/5] refactor: support xlang ref --- .../java/org/apache/fory/RustXlangTest.java | 77 ++++++++++++++++++ rust/fory-core/src/serializer/core.rs | 81 ++++++++++++++++++- rust/fory-core/src/serializer/list.rs | 24 ++++++ rust/fory-core/src/serializer/map.rs | 16 ++++ rust/fory-core/src/serializer/set.rs | 16 ++++ rust/fory-core/src/serializer/string.rs | 9 +++ rust/tests/tests/test_cross_language.rs | 68 ++++++++++++++++ 7 files changed, 289 insertions(+), 2 deletions(-) diff --git a/java/fory-core/src/test/java/org/apache/fory/RustXlangTest.java b/java/fory-core/src/test/java/org/apache/fory/RustXlangTest.java index 4e0332b7a7..54753c654d 100644 --- a/java/fory-core/src/test/java/org/apache/fory/RustXlangTest.java +++ b/java/fory-core/src/test/java/org/apache/fory/RustXlangTest.java @@ -127,6 +127,8 @@ public void testRust() throws Exception { testStructVersionCheck(Language.RUST, command); command.set(RUST_TESTCASE_INDEX, "test_consistent_named"); testConsistentNamed(Language.RUST, command); + command.set(RUST_TESTCASE_INDEX, "test_reference_alignment"); + testReferenceAlignment(Language.RUST, command); } private void testBuffer(Language language, List command) throws IOException { @@ -941,4 +943,79 @@ private void assertStringEquals(Object actual, Object expected, boolean useToStr Assert.assertEquals(actual, expected); } } + + /** + * Test reference type alignment between Java and Rust in xlang mode. + * + *

This test verifies that: + *

+ */ + private void testReferenceAlignment(Language language, List command) + throws IOException { + Fory fory = Fory.builder() + .withLanguage(Language.XLANG) + .withCompatibleMode(CompatibleMode.COMPATIBLE) + .build(); + + // Serialize test data from Java + MemoryBuffer buffer = MemoryBuffer.newHeapBuffer(256); + + // 1. Primitive int (no RefFlag) + fory.serialize(buffer, 42); + + // 2. Boxed Integer (with RefFlag for null handling) + fory.serialize(buffer, Integer.valueOf(100)); + + // 3. String (reference type, with RefFlag) + fory.serialize(buffer, "hello"); + + // 4. List (reference type, with RefFlag) + fory.serialize(buffer, Arrays.asList("a", "b")); + + // 5. Map (reference type, with RefFlag) + Map map = new HashMap<>(); + map.put("key1", 10); + map.put("key2", 20); + fory.serialize(buffer, map); + + // 6. Double (primitive, no RefFlag) + fory.serialize(buffer, 3.14); + + // 7. Boolean (primitive, no RefFlag) + fory.serialize(buffer, true); + + byte[] bytes = buffer.getBytes(0, buffer.writerIndex()); + LOG.info("Java serialized {} bytes for reference alignment test", bytes.length); + + // Send to Rust for verification + Path dataFile = Files.createTempFile("test_reference_alignment", "data"); + Pair, File> env_workdir = setFilePath(language, command, dataFile, bytes); + Assert.assertTrue( + executeCommand(command, 30, env_workdir.getLeft(), env_workdir.getRight()), + "Rust test failed"); + + // Read back Rust's serialization and verify + MemoryBuffer buffer2 = MemoryUtils.wrap(Files.readAllBytes(dataFile)); + + Assert.assertEquals(fory.deserialize(buffer2), 42, "i32 value mismatch"); + Assert.assertEquals(fory.deserialize(buffer2), Integer.valueOf(100), "Option value mismatch"); + Assert.assertEquals(fory.deserialize(buffer2), "hello", "String value mismatch"); + Assert.assertEquals( + fory.deserialize(buffer2), Arrays.asList("a", "b"), "Vec value mismatch"); + + @SuppressWarnings("unchecked") + Map deserializedMap = (Map) fory.deserialize(buffer2); + Assert.assertEquals(deserializedMap.get("key1"), Integer.valueOf(10), "HashMap key1 mismatch"); + Assert.assertEquals(deserializedMap.get("key2"), Integer.valueOf(20), "HashMap key2 mismatch"); + + Assert.assertEquals(fory.deserialize(buffer2), 3.14, "f64 value mismatch"); + Assert.assertEquals(fory.deserialize(buffer2), true, "bool value mismatch"); + + LOG.info("Reference alignment test passed!"); + } } diff --git a/rust/fory-core/src/serializer/core.rs b/rust/fory-core/src/serializer/core.rs index a8888ada8e..8e90629471 100644 --- a/rust/fory-core/src/serializer/core.rs +++ b/rust/fory-core/src/serializer/core.rs @@ -258,8 +258,21 @@ pub trait Serializer: 'static { Self: Sized, { if write_ref_info { - // skip check option/pointer, the Serializer for such types will override `fory_write`. - context.writer.write_i8(RefFlag::NotNullValue as i8); + // In xlang mode, determine RefFlag based on type characteristics + let should_write_ref = if context.is_xlang() { + Self::fory_is_xlang_ref_type() + } else { + // In non-xlang mode, use original logic + true + }; + + if should_write_ref { + // This is a reference type in xlang context - write RefValue + context.writer.write_i8(RefFlag::RefValue as i8); + } else { + // This is a value type - write NotNullValue + context.writer.write_i8(RefFlag::NotNullValue as i8); + } } if write_type_info { // Serializer for dynamic types should override `fory_write` to write actual typeinfo. @@ -1217,6 +1230,70 @@ pub trait Serializer: 'static { std::mem::size_of::() } + /// Indicate whether this type should be treated as a reference type in cross-language (xlang) serialization. + /// + /// In cross-language scenarios, type systems differ between languages. For example: + /// - In Java: `String`, `List`, `Map` are reference types (need RefFlag) + /// - In Rust: `String`, `Vec`, `HashMap` are value types (by default, no RefFlag) + /// + /// This method bridges the gap by allowing Rust types to declare their cross-language reference semantics. + /// + /// # Returns + /// + /// - `true` if this type should be treated as a reference type in xlang mode + /// (will write RefFlag during serialization) + /// - `false` if this type should be treated as a value type in xlang mode + /// (will not write RefFlag, default) + /// + /// # Type Mapping Guidelines + /// + /// | Rust Type | Java Type | Should Return | + /// |-----------|-----------|---------------| + /// | `i32`, `f64`, `bool` | `int`, `double`, `boolean` | `false` | + /// | `Option` | `Integer` | `false` (Option handles null) | + /// | `String` | `String` | `true` | + /// | `Vec` | `List` | `true` | + /// | `HashMap` | `Map` | `true` | + /// | User struct | Java object | `true` | + /// + /// # Default Implementation + /// + /// Returns `false` for all types. Override for types that correspond to reference types in other languages. + /// + /// # Examples + /// + /// ```rust,ignore + /// // String should be treated as reference type in Java + /// impl Serializer for String { + /// fn fory_is_xlang_ref_type() -> bool { + /// true + /// } + /// } + /// + /// // i32 is primitive in Java (int) + /// impl Serializer for i32 { + /// fn fory_is_xlang_ref_type() -> bool { + /// false // default + /// } + /// } + /// ``` + /// + /// # Implementation Notes + /// + /// - Only affects behavior when `context.is_xlang()` is true + /// - Used in [`fory_write`] to determine RefFlag behavior + /// - Fory implements this for all built-in types + /// - User types should override this for proper xlang interop + /// + /// [`fory_write`]: Serializer::fory_write + #[inline(always)] + fn fory_is_xlang_ref_type() -> bool + where + Self: Sized, + { + false + } + /// **[USER IMPLEMENTATION REQUIRED]** Downcast to `&dyn Any` for dynamic type checking. /// /// This method enables runtime type checking and downcasting, required for diff --git a/rust/fory-core/src/serializer/list.rs b/rust/fory-core/src/serializer/list.rs index b562e5323a..3fb1efe942 100644 --- a/rust/fory-core/src/serializer/list.rs +++ b/rust/fory-core/src/serializer/list.rs @@ -121,6 +121,14 @@ impl Serializer for Vec { fn as_any(&self) -> &dyn std::any::Any { self } + + fn fory_is_xlang_ref_type() -> bool + where + Self: Sized, + { + // Vec corresponds to Java List, which is a reference type + true + } } impl ForyDefault for Vec { @@ -173,6 +181,14 @@ impl Serializer for VecDeque { fn as_any(&self) -> &dyn std::any::Any { self } + + fn fory_is_xlang_ref_type() -> bool + where + Self: Sized, + { + // VecDeque corresponds to Java List, which is a reference type + true + } } impl ForyDefault for VecDeque { @@ -225,6 +241,14 @@ impl Serializer for LinkedList { fn as_any(&self) -> &dyn std::any::Any { self } + + fn fory_is_xlang_ref_type() -> bool + where + Self: Sized, + { + // LinkedList corresponds to Java List, which is a reference type + true + } } impl ForyDefault for LinkedList { diff --git a/rust/fory-core/src/serializer/map.rs b/rust/fory-core/src/serializer/map.rs index f3b2fd8187..b589fd457e 100644 --- a/rust/fory-core/src/serializer/map.rs +++ b/rust/fory-core/src/serializer/map.rs @@ -638,6 +638,14 @@ impl Result<(), Error> { read_basic_type_info::(context) } + + fn fory_is_xlang_ref_type() -> bool + where + Self: Sized, + { + // HashMap corresponds to Java Map, which is a reference type + true + } } impl ForyDefault for HashMap { @@ -766,6 +774,14 @@ impl Result<(), Error> { read_basic_type_info::(context) } + + fn fory_is_xlang_ref_type() -> bool + where + Self: Sized, + { + // BTreeMap corresponds to Java Map, which is a reference type + true + } } impl ForyDefault for BTreeMap { diff --git a/rust/fory-core/src/serializer/set.rs b/rust/fory-core/src/serializer/set.rs index a317f0b362..b201f98696 100644 --- a/rust/fory-core/src/serializer/set.rs +++ b/rust/fory-core/src/serializer/set.rs @@ -68,6 +68,14 @@ impl Serializer for HashSet< fn as_any(&self) -> &dyn std::any::Any { self } + + fn fory_is_xlang_ref_type() -> bool + where + Self: Sized, + { + // HashSet corresponds to Java Set, which is a reference type + true + } } impl ForyDefault for HashSet { @@ -115,6 +123,14 @@ impl Serializer for BTreeSet { fn as_any(&self) -> &dyn std::any::Any { self } + + fn fory_is_xlang_ref_type() -> bool + where + Self: Sized, + { + // BTreeSet corresponds to Java Set, which is a reference type + true + } } impl ForyDefault for BTreeSet { diff --git a/rust/fory-core/src/serializer/string.rs b/rust/fory-core/src/serializer/string.rs index 256ed41b6f..56eeb03a8d 100644 --- a/rust/fory-core/src/serializer/string.rs +++ b/rust/fory-core/src/serializer/string.rs @@ -98,6 +98,15 @@ impl Serializer for String { fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> { read_basic_type_info::(context) } + + #[inline(always)] + fn fory_is_xlang_ref_type() -> bool + where + Self: Sized, + { + // String is a reference type in Java, should write RefFlag in xlang mode + true + } } impl ForyDefault for String { diff --git a/rust/tests/tests/test_cross_language.rs b/rust/tests/tests/test_cross_language.rs index d3957f8449..b5280e7134 100644 --- a/rust/tests/tests/test_cross_language.rs +++ b/rust/tests/tests/test_cross_language.rs @@ -734,3 +734,71 @@ fn test_struct_version_check() { assert_eq!(new_local_obj, local_obj); fs::write(&data_file_path, new_bytes).unwrap(); } + +/// Test reference type alignment between Java and Rust in xlang mode. +/// +/// This test verifies that: +/// 1. Primitive types (i32, f64, bool) don't write RefFlag +/// 2. Reference types (String, Vec, HashMap) write RefFlag in xlang mode +/// 3. Java-serialized data can be correctly deserialized in Rust +/// 4. Rust-serialized data can be correctly deserialized in Java +#[test] +#[ignore] +fn test_reference_alignment() { + let data_file_path = get_data_file(); + + // Read data serialized by Java + let bytes = fs::read(&data_file_path).unwrap(); + let mut fory = Fory::default().xlang(true).compatible(true); + + let reader = Reader::new(bytes.as_slice()); + let mut context = ReadContext::new_from_fory(reader, &fory); + + // Deserialize values in the same order as Java wrote them + // 1. Primitive int (no RefFlag) + let v1: i32 = fory.deserialize_with_context(&mut context).unwrap(); + assert_eq!(v1, 42, "i32 value mismatch"); + + // 2. Boxed Integer (with RefFlag for null handling) + let v2: Option = fory.deserialize_with_context(&mut context).unwrap(); + assert_eq!(v2, Some(100), "Option value mismatch"); + + // 3. String (reference type, with RefFlag) + let v3: String = fory.deserialize_with_context(&mut context).unwrap(); + assert_eq!(v3, "hello", "String value mismatch"); + + // 4. List (reference type, with RefFlag) + let v4: Vec = fory.deserialize_with_context(&mut context).unwrap(); + assert_eq!(v4, vec!["a".to_string(), "b".to_string()], "Vec value mismatch"); + + // 5. Map (reference type, with RefFlag) + let v5: HashMap = fory.deserialize_with_context(&mut context).unwrap(); + let mut expected_map = HashMap::new(); + expected_map.insert("key1".to_string(), 10); + expected_map.insert("key2".to_string(), 20); + assert_eq!(v5, expected_map, "HashMap value mismatch"); + + // 6. Double (primitive, no RefFlag) + let v6: f64 = fory.deserialize_with_context(&mut context).unwrap(); + assert_eq!(v6, 3.14, "f64 value mismatch"); + + // 7. Boolean (primitive, no RefFlag) + let v7: bool = fory.deserialize_with_context(&mut context).unwrap(); + assert_eq!(v7, true, "bool value mismatch"); + + // Now serialize data back to Java + let writer = Writer::default(); + let mut context = WriteContext::new_from_fory(writer, &fory); + + // Serialize in the same order + fory.serialize_with_context(&42i32, &mut context).unwrap(); + fory.serialize_with_context(&Some(100i32), &mut context).unwrap(); + fory.serialize_with_context(&"hello".to_string(), &mut context).unwrap(); + fory.serialize_with_context(&vec!["a".to_string(), "b".to_string()], &mut context).unwrap(); + fory.serialize_with_context(&expected_map, &mut context).unwrap(); + fory.serialize_with_context(&3.14f64, &mut context).unwrap(); + fory.serialize_with_context(&true, &mut context).unwrap(); + + // Write back to file for Java to verify + fs::write(&data_file_path, context.writer.dump()).unwrap(); +} From 37be2f8a86b3c87b565b7fb8f51e21d0c9da0465 Mon Sep 17 00:00:00 2001 From: kaori-seasons Date: Tue, 28 Oct 2025 14:34:03 +0800 Subject: [PATCH 2/5] style: format code with cargo fmt --- rust/fory-core/src/serializer/core.rs | 2 +- rust/tests/tests/test_cross_language.rs | 44 +++++++++++++++---------- 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/rust/fory-core/src/serializer/core.rs b/rust/fory-core/src/serializer/core.rs index 8e90629471..efa6190177 100644 --- a/rust/fory-core/src/serializer/core.rs +++ b/rust/fory-core/src/serializer/core.rs @@ -265,7 +265,7 @@ pub trait Serializer: 'static { // In non-xlang mode, use original logic true }; - + if should_write_ref { // This is a reference type in xlang context - write RefValue context.writer.write_i8(RefFlag::RefValue as i8); diff --git a/rust/tests/tests/test_cross_language.rs b/rust/tests/tests/test_cross_language.rs index b5280e7134..c8db9a8ccd 100644 --- a/rust/tests/tests/test_cross_language.rs +++ b/rust/tests/tests/test_cross_language.rs @@ -736,7 +736,7 @@ fn test_struct_version_check() { } /// Test reference type alignment between Java and Rust in xlang mode. -/// +/// /// This test verifies that: /// 1. Primitive types (i32, f64, bool) don't write RefFlag /// 2. Reference types (String, Vec, HashMap) write RefFlag in xlang mode @@ -746,59 +746,67 @@ fn test_struct_version_check() { #[ignore] fn test_reference_alignment() { let data_file_path = get_data_file(); - + // Read data serialized by Java let bytes = fs::read(&data_file_path).unwrap(); let mut fory = Fory::default().xlang(true).compatible(true); - + let reader = Reader::new(bytes.as_slice()); let mut context = ReadContext::new_from_fory(reader, &fory); - + // Deserialize values in the same order as Java wrote them // 1. Primitive int (no RefFlag) let v1: i32 = fory.deserialize_with_context(&mut context).unwrap(); assert_eq!(v1, 42, "i32 value mismatch"); - + // 2. Boxed Integer (with RefFlag for null handling) let v2: Option = fory.deserialize_with_context(&mut context).unwrap(); assert_eq!(v2, Some(100), "Option value mismatch"); - + // 3. String (reference type, with RefFlag) let v3: String = fory.deserialize_with_context(&mut context).unwrap(); assert_eq!(v3, "hello", "String value mismatch"); - + // 4. List (reference type, with RefFlag) let v4: Vec = fory.deserialize_with_context(&mut context).unwrap(); - assert_eq!(v4, vec!["a".to_string(), "b".to_string()], "Vec value mismatch"); - + assert_eq!( + v4, + vec!["a".to_string(), "b".to_string()], + "Vec value mismatch" + ); + // 5. Map (reference type, with RefFlag) let v5: HashMap = fory.deserialize_with_context(&mut context).unwrap(); let mut expected_map = HashMap::new(); expected_map.insert("key1".to_string(), 10); expected_map.insert("key2".to_string(), 20); assert_eq!(v5, expected_map, "HashMap value mismatch"); - + // 6. Double (primitive, no RefFlag) let v6: f64 = fory.deserialize_with_context(&mut context).unwrap(); assert_eq!(v6, 3.14, "f64 value mismatch"); - + // 7. Boolean (primitive, no RefFlag) let v7: bool = fory.deserialize_with_context(&mut context).unwrap(); assert_eq!(v7, true, "bool value mismatch"); - + // Now serialize data back to Java let writer = Writer::default(); let mut context = WriteContext::new_from_fory(writer, &fory); - + // Serialize in the same order fory.serialize_with_context(&42i32, &mut context).unwrap(); - fory.serialize_with_context(&Some(100i32), &mut context).unwrap(); - fory.serialize_with_context(&"hello".to_string(), &mut context).unwrap(); - fory.serialize_with_context(&vec!["a".to_string(), "b".to_string()], &mut context).unwrap(); - fory.serialize_with_context(&expected_map, &mut context).unwrap(); + fory.serialize_with_context(&Some(100i32), &mut context) + .unwrap(); + fory.serialize_with_context(&"hello".to_string(), &mut context) + .unwrap(); + fory.serialize_with_context(&vec!["a".to_string(), "b".to_string()], &mut context) + .unwrap(); + fory.serialize_with_context(&expected_map, &mut context) + .unwrap(); fory.serialize_with_context(&3.14f64, &mut context).unwrap(); fory.serialize_with_context(&true, &mut context).unwrap(); - + // Write back to file for Java to verify fs::write(&data_file_path, context.writer.dump()).unwrap(); } From 437accebbe0cd7a9b10be65e30730d026168352b Mon Sep 17 00:00:00 2001 From: kaori-seasons Date: Tue, 28 Oct 2025 14:40:11 +0800 Subject: [PATCH 3/5] fix: update reference alignment test to use public Fory API - Replace private deserialize_with_context() with public deserialize_from() - Replace private serialize_with_context() with public serialize_to() - Remove non-existent ReadContext::new_from_fory() and WriteContext::new_from_fory() - Use Vec buffer instead of Reader/Writer context directly - Add #[allow(clippy::approx_constant)] for 3.14f64 test value - Fix assert_eq!(bool) to assert!(bool) to pass clippy - All tests now pass clippy with -D warnings --- rust/tests/tests/test_cross_language.rs | 45 +++++++++++-------------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/rust/tests/tests/test_cross_language.rs b/rust/tests/tests/test_cross_language.rs index c8db9a8ccd..ab4246c202 100644 --- a/rust/tests/tests/test_cross_language.rs +++ b/rust/tests/tests/test_cross_language.rs @@ -744,31 +744,30 @@ fn test_struct_version_check() { /// 4. Rust-serialized data can be correctly deserialized in Java #[test] #[ignore] +#[allow(clippy::approx_constant)] fn test_reference_alignment() { let data_file_path = get_data_file(); // Read data serialized by Java let bytes = fs::read(&data_file_path).unwrap(); - let mut fory = Fory::default().xlang(true).compatible(true); - - let reader = Reader::new(bytes.as_slice()); - let mut context = ReadContext::new_from_fory(reader, &fory); + let fory = Fory::default().xlang(true).compatible(true); + let mut reader = Reader::new(bytes.as_slice()); // Deserialize values in the same order as Java wrote them // 1. Primitive int (no RefFlag) - let v1: i32 = fory.deserialize_with_context(&mut context).unwrap(); + let v1: i32 = fory.deserialize_from(&mut reader).unwrap(); assert_eq!(v1, 42, "i32 value mismatch"); // 2. Boxed Integer (with RefFlag for null handling) - let v2: Option = fory.deserialize_with_context(&mut context).unwrap(); + let v2: Option = fory.deserialize_from(&mut reader).unwrap(); assert_eq!(v2, Some(100), "Option value mismatch"); // 3. String (reference type, with RefFlag) - let v3: String = fory.deserialize_with_context(&mut context).unwrap(); + let v3: String = fory.deserialize_from(&mut reader).unwrap(); assert_eq!(v3, "hello", "String value mismatch"); // 4. List (reference type, with RefFlag) - let v4: Vec = fory.deserialize_with_context(&mut context).unwrap(); + let v4: Vec = fory.deserialize_from(&mut reader).unwrap(); assert_eq!( v4, vec!["a".to_string(), "b".to_string()], @@ -776,37 +775,33 @@ fn test_reference_alignment() { ); // 5. Map (reference type, with RefFlag) - let v5: HashMap = fory.deserialize_with_context(&mut context).unwrap(); + let v5: HashMap = fory.deserialize_from(&mut reader).unwrap(); let mut expected_map = HashMap::new(); expected_map.insert("key1".to_string(), 10); expected_map.insert("key2".to_string(), 20); assert_eq!(v5, expected_map, "HashMap value mismatch"); // 6. Double (primitive, no RefFlag) - let v6: f64 = fory.deserialize_with_context(&mut context).unwrap(); + let v6: f64 = fory.deserialize_from(&mut reader).unwrap(); assert_eq!(v6, 3.14, "f64 value mismatch"); // 7. Boolean (primitive, no RefFlag) - let v7: bool = fory.deserialize_with_context(&mut context).unwrap(); - assert_eq!(v7, true, "bool value mismatch"); + let v7: bool = fory.deserialize_from(&mut reader).unwrap(); + assert!(v7, "bool value mismatch"); // Now serialize data back to Java - let writer = Writer::default(); - let mut context = WriteContext::new_from_fory(writer, &fory); + let mut buf = Vec::new(); // Serialize in the same order - fory.serialize_with_context(&42i32, &mut context).unwrap(); - fory.serialize_with_context(&Some(100i32), &mut context) - .unwrap(); - fory.serialize_with_context(&"hello".to_string(), &mut context) + fory.serialize_to(&42i32, &mut buf).unwrap(); + fory.serialize_to(&Some(100i32), &mut buf).unwrap(); + fory.serialize_to(&"hello".to_string(), &mut buf).unwrap(); + fory.serialize_to(&vec!["a".to_string(), "b".to_string()], &mut buf) .unwrap(); - fory.serialize_with_context(&vec!["a".to_string(), "b".to_string()], &mut context) - .unwrap(); - fory.serialize_with_context(&expected_map, &mut context) - .unwrap(); - fory.serialize_with_context(&3.14f64, &mut context).unwrap(); - fory.serialize_with_context(&true, &mut context).unwrap(); + fory.serialize_to(&expected_map, &mut buf).unwrap(); + fory.serialize_to(&3.14f64, &mut buf).unwrap(); + fory.serialize_to(&true, &mut buf).unwrap(); // Write back to file for Java to verify - fs::write(&data_file_path, context.writer.dump()).unwrap(); + fs::write(&data_file_path, buf).unwrap(); } From 4237c898deecfd498c190f33b408ffe0e4d17e16 Mon Sep 17 00:00:00 2001 From: kaori-seasons Date: Tue, 28 Oct 2025 15:01:49 +0800 Subject: [PATCH 4/5] recover code --- rust/fory-core/src/serializer/core.rs | 49 +------------------------ rust/fory-core/src/serializer/list.rs | 24 ------------ rust/fory-core/src/serializer/map.rs | 35 ------------------ rust/fory-core/src/serializer/set.rs | 16 -------- rust/fory-core/src/serializer/string.rs | 9 ----- 5 files changed, 2 insertions(+), 131 deletions(-) diff --git a/rust/fory-core/src/serializer/core.rs b/rust/fory-core/src/serializer/core.rs index efa6190177..cc7311a395 100644 --- a/rust/fory-core/src/serializer/core.rs +++ b/rust/fory-core/src/serializer/core.rs @@ -258,21 +258,8 @@ pub trait Serializer: 'static { Self: Sized, { if write_ref_info { - // In xlang mode, determine RefFlag based on type characteristics - let should_write_ref = if context.is_xlang() { - Self::fory_is_xlang_ref_type() - } else { - // In non-xlang mode, use original logic - true - }; - - if should_write_ref { - // This is a reference type in xlang context - write RefValue - context.writer.write_i8(RefFlag::RefValue as i8); - } else { - // This is a value type - write NotNullValue - context.writer.write_i8(RefFlag::NotNullValue as i8); - } + // skip check option/pointer, the Serializer for such types will override `fory_write`. + context.writer.write_i8(RefFlag::NotNullValue as i8); } if write_type_info { // Serializer for dynamic types should override `fory_write` to write actual typeinfo. @@ -1286,38 +1273,6 @@ pub trait Serializer: 'static { /// - User types should override this for proper xlang interop /// /// [`fory_write`]: Serializer::fory_write - #[inline(always)] - fn fory_is_xlang_ref_type() -> bool - where - Self: Sized, - { - false - } - - /// **[USER IMPLEMENTATION REQUIRED]** Downcast to `&dyn Any` for dynamic type checking. - /// - /// This method enables runtime type checking and downcasting, required for - /// Fory's type system integration. - /// - /// # Returns - /// - /// A reference to this instance as `&dyn Any`. - /// - /// # Implementation Pattern - /// - /// Always implement this by returning `self`: - /// - /// ```rust,ignore - /// fn as_any(&self) -> &dyn Any { - /// self - /// } - /// ``` - /// - /// # Implementation Notes - /// - /// - Required for all types implementing `Serializer` - /// - Enables `downcast_ref::()` on serialized values - /// - Used by Fory's polymorphic deserialization fn as_any(&self) -> &dyn Any; } diff --git a/rust/fory-core/src/serializer/list.rs b/rust/fory-core/src/serializer/list.rs index 3fb1efe942..b562e5323a 100644 --- a/rust/fory-core/src/serializer/list.rs +++ b/rust/fory-core/src/serializer/list.rs @@ -121,14 +121,6 @@ impl Serializer for Vec { fn as_any(&self) -> &dyn std::any::Any { self } - - fn fory_is_xlang_ref_type() -> bool - where - Self: Sized, - { - // Vec corresponds to Java List, which is a reference type - true - } } impl ForyDefault for Vec { @@ -181,14 +173,6 @@ impl Serializer for VecDeque { fn as_any(&self) -> &dyn std::any::Any { self } - - fn fory_is_xlang_ref_type() -> bool - where - Self: Sized, - { - // VecDeque corresponds to Java List, which is a reference type - true - } } impl ForyDefault for VecDeque { @@ -241,14 +225,6 @@ impl Serializer for LinkedList { fn as_any(&self) -> &dyn std::any::Any { self } - - fn fory_is_xlang_ref_type() -> bool - where - Self: Sized, - { - // LinkedList corresponds to Java List, which is a reference type - true - } } impl ForyDefault for LinkedList { diff --git a/rust/fory-core/src/serializer/map.rs b/rust/fory-core/src/serializer/map.rs index b589fd457e..71aee36604 100644 --- a/rust/fory-core/src/serializer/map.rs +++ b/rust/fory-core/src/serializer/map.rs @@ -19,7 +19,6 @@ use crate::ensure; use crate::error::Error; use crate::resolver::context::{ReadContext, WriteContext}; use crate::resolver::type_resolver::{TypeInfo, TypeResolver}; -use crate::serializer::util::read_basic_type_info; use crate::serializer::{ForyDefault, Serializer}; use crate::types::{need_to_write_type_for_field, TypeId, SIZE_OF_REF_AND_TYPE}; use std::collections::{BTreeMap, HashMap}; @@ -629,23 +628,6 @@ impl &dyn std::any::Any { self } - - fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> { - context.writer.write_varuint32(TypeId::MAP as u32); - Ok(()) - } - - fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> { - read_basic_type_info::(context) - } - - fn fory_is_xlang_ref_type() -> bool - where - Self: Sized, - { - // HashMap corresponds to Java Map, which is a reference type - true - } } impl ForyDefault for HashMap { @@ -765,23 +747,6 @@ impl &dyn std::any::Any { self } - - fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> { - context.writer.write_varuint32(TypeId::MAP as u32); - Ok(()) - } - - fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> { - read_basic_type_info::(context) - } - - fn fory_is_xlang_ref_type() -> bool - where - Self: Sized, - { - // BTreeMap corresponds to Java Map, which is a reference type - true - } } impl ForyDefault for BTreeMap { diff --git a/rust/fory-core/src/serializer/set.rs b/rust/fory-core/src/serializer/set.rs index b201f98696..a317f0b362 100644 --- a/rust/fory-core/src/serializer/set.rs +++ b/rust/fory-core/src/serializer/set.rs @@ -68,14 +68,6 @@ impl Serializer for HashSet< fn as_any(&self) -> &dyn std::any::Any { self } - - fn fory_is_xlang_ref_type() -> bool - where - Self: Sized, - { - // HashSet corresponds to Java Set, which is a reference type - true - } } impl ForyDefault for HashSet { @@ -123,14 +115,6 @@ impl Serializer for BTreeSet { fn as_any(&self) -> &dyn std::any::Any { self } - - fn fory_is_xlang_ref_type() -> bool - where - Self: Sized, - { - // BTreeSet corresponds to Java Set, which is a reference type - true - } } impl ForyDefault for BTreeSet { diff --git a/rust/fory-core/src/serializer/string.rs b/rust/fory-core/src/serializer/string.rs index 56eeb03a8d..256ed41b6f 100644 --- a/rust/fory-core/src/serializer/string.rs +++ b/rust/fory-core/src/serializer/string.rs @@ -98,15 +98,6 @@ impl Serializer for String { fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> { read_basic_type_info::(context) } - - #[inline(always)] - fn fory_is_xlang_ref_type() -> bool - where - Self: Sized, - { - // String is a reference type in Java, should write RefFlag in xlang mode - true - } } impl ForyDefault for String { From e9eeba949337a07d3c0e3cd4d4f6399047fa2042 Mon Sep 17 00:00:00 2001 From: kaori-seasons Date: Tue, 28 Oct 2025 15:09:30 +0800 Subject: [PATCH 5/5] recover code --- rust/fory-core/src/serializer/map.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/rust/fory-core/src/serializer/map.rs b/rust/fory-core/src/serializer/map.rs index 71aee36604..f3b2fd8187 100644 --- a/rust/fory-core/src/serializer/map.rs +++ b/rust/fory-core/src/serializer/map.rs @@ -19,6 +19,7 @@ use crate::ensure; use crate::error::Error; use crate::resolver::context::{ReadContext, WriteContext}; use crate::resolver::type_resolver::{TypeInfo, TypeResolver}; +use crate::serializer::util::read_basic_type_info; use crate::serializer::{ForyDefault, Serializer}; use crate::types::{need_to_write_type_for_field, TypeId, SIZE_OF_REF_AND_TYPE}; use std::collections::{BTreeMap, HashMap}; @@ -628,6 +629,15 @@ impl &dyn std::any::Any { self } + + fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> { + context.writer.write_varuint32(TypeId::MAP as u32); + Ok(()) + } + + fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> { + read_basic_type_info::(context) + } } impl ForyDefault for HashMap { @@ -747,6 +757,15 @@ impl &dyn std::any::Any { self } + + fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> { + context.writer.write_varuint32(TypeId::MAP as u32); + Ok(()) + } + + fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> { + read_basic_type_info::(context) + } } impl ForyDefault for BTreeMap {