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

tqchen pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tvm-ffi.git


The following commit(s) were added to refs/heads/main by this push:
     new a23adc53 [FEAT][RUST] Accept any Into<Any> return value in structural 
map/mutate callbacks (#722)
a23adc53 is described below

commit a23adc53b24092278007c23636b3156f097bee6b
Author: Linzhang Li <[email protected]>
AuthorDate: Mon Aug 31 18:31:40 2026 -0400

    [FEAT][RUST] Accept any Into<Any> return value in structural map/mutate 
callbacks (#722)
    
    Previously, structural_map / structural_mutate callbacks (closures,
    tuple chains, and #[dispatch(map)] / #[dispatch(mutate)] handlers) had
    to return Any or Result<Any>, forcing Any::from(...) wrapping at every
    return site.
    
    This PR relaxes IntoMapResult / IntoMutateResult into blanket impls over
    T: Into<Any>:
    
    impl<T: Into<Any>> IntoMapResult for T         { /* Ok(self.into()) */ }
    impl<T: Into<Any>> IntoMapResult for Result<T> { /* self.map(Into::into)
    */ }
    
    A callback can now return any FFI-compatible value directly (i64,
    String, Array<T>, …) or Result<T> to use ?; the conversion to Any
    happens inside
    
    - Backward compatible: Any: Into<Any> holds reflexively, so existing
    callbacks are unchanged; the two blanket impls are disjoint (Result<T>
    - Tests: new callbacks_return_values_convertible_into_any covers bare
    i64, Result<i64>, and a mutate-context callback; several existing
    callbacks switched to explicit return types (Result<i64>,
    Result<Array<i64>>) to exercise the new path. visit / walk are untouched
    — their ca flow (WalkResult / VisitInterrupt), not values.
    
    Signed-off-by: yuchuan <[email protected]>
---
 rust/tvm-ffi/src/extra/structural_mutate.rs  | 22 +++++++++------
 rust/tvm-ffi/tests/test_structural_mutate.rs | 40 ++++++++++++++++++++++++----
 2 files changed, 49 insertions(+), 13 deletions(-)

diff --git a/rust/tvm-ffi/src/extra/structural_mutate.rs 
b/rust/tvm-ffi/src/extra/structural_mutate.rs
index 5fc7da44..e7088bd4 100644
--- a/rust/tvm-ffi/src/extra/structural_mutate.rs
+++ b/rust/tvm-ffi/src/extra/structural_mutate.rs
@@ -71,21 +71,24 @@ pub use super::structural_common::StructuralValue as 
MapValue;
 pub type MapResult = Result<Any>;
 
 /// Convert an infallible or fallible callback result into [`MapResult`].
+///
+/// A callback may return any value convertible into [`Any`], or wrap it in
+/// [`Result`] to use `?`.
 pub trait IntoMapResult {
     fn into_map_result(self) -> MapResult;
 }
 
-impl IntoMapResult for Any {
+impl<T: Into<Any>> IntoMapResult for T {
     #[inline]
     fn into_map_result(self) -> MapResult {
-        Ok(self)
+        Ok(self.into())
     }
 }
 
-impl IntoMapResult for Result<Any> {
+impl<T: Into<Any>> IntoMapResult for Result<T> {
     #[inline]
     fn into_map_result(self) -> MapResult {
-        self
+        self.map(Into::into)
     }
 }
 
@@ -216,22 +219,25 @@ impl<U: StructuralMutator> IntoMutator<U> for &mut U {
 }
 
 /// Convert a mutation callback result into [`Result<Any>`].
+///
+/// A callback may return any value convertible into [`Any`], or wrap it in
+/// [`Result`] to use `?`.
 #[doc(hidden)]
 pub trait IntoMutateResult {
     fn into_mutate_result(self) -> Result<Any>;
 }
 
-impl IntoMutateResult for Any {
+impl<T: Into<Any>> IntoMutateResult for T {
     #[inline]
     fn into_mutate_result(self) -> Result<Any> {
-        Ok(self)
+        Ok(self.into())
     }
 }
 
-impl IntoMutateResult for Result<Any> {
+impl<T: Into<Any>> IntoMutateResult for Result<T> {
     #[inline]
     fn into_mutate_result(self) -> Result<Any> {
-        self
+        self.map(Into::into)
     }
 }
 
diff --git a/rust/tvm-ffi/tests/test_structural_mutate.rs 
b/rust/tvm-ffi/tests/test_structural_mutate.rs
index 11934875..cf364a56 100644
--- a/rust/tvm-ffi/tests/test_structural_mutate.rs
+++ b/rust/tvm-ffi/tests/test_structural_mutate.rs
@@ -1072,7 +1072,7 @@ fn 
callback_errors_preserve_message_and_add_object_context() {
     ensure_test_types_registered();
     let error = match structural_map(
         Array::new(vec![1i64]),
-        |_integer: i64| -> Result<Any> {
+        |_integer: i64| -> Result<i64> {
             Err(Error::new(RUNTIME_ERROR, "mapper failed", "origin"))
         },
         WalkOrder::PostOrder,
@@ -1087,7 +1087,7 @@ fn 
callback_errors_preserve_message_and_add_object_context() {
 
     let error = match structural_mutate(
         Array::new(vec![1i64]),
-        |_integer: i64, _mutator: &mut MutateContext<'_, ()>| -> Result<Any> {
+        |_integer: i64, _mutator: &mut MutateContext<'_, ()>| -> Result<i64> {
             Err(Error::new(
                 RUNTIME_ERROR,
                 "callback mutator failed",
@@ -1293,7 +1293,7 @@ fn 
shared_map_callback_error_preserves_source_and_reports_object_context() {
     let source: Map<i64, i64> = [(1, 10), (2, 20)].into_iter().collect();
     let error = match structural_map(
         source.clone(),
-        |_integer: i64| -> Result<Any> {
+        |_integer: i64| -> Result<i64> {
             Err(Error::new(RUNTIME_ERROR, "map mapper failed", "origin"))
         },
         WalkOrder::PostOrder,
@@ -1432,12 +1432,12 @@ struct GeneratedRecursiveMutator {
 
 #[dispatch(mutate)]
 impl GeneratedRecursiveMutator {
-    fn mutate_array(&mut self, array: Array<i64>, kind: DefRegionKind) -> 
Result<Any> {
+    fn mutate_array(&mut self, array: Array<i64>, kind: DefRegionKind) -> 
Result<Array<i64>> {
         let mut mutated = Vec::with_capacity(array.len());
         for value in array.iter() {
             mutated.push(i64::try_from(self.mutate(&value, kind)?)?);
         }
-        Ok(Any::from(Array::new(mutated)))
+        Ok(Array::new(mutated))
     }
 
     fn mutate_integer(&mut self, value: i64) -> Any {
@@ -1599,6 +1599,36 @@ fn closures_and_tuples_use_ordered_first_match() {
     assert_eq!(later_calls, 0);
 }
 
+#[test]
+fn callbacks_return_values_convertible_into_any() {
+    ensure_test_types_registered();
+    let mapped = structural_map(
+        Array::new(vec![1i64, 2]),
+        |integer: i64| integer + 10,
+        WalkOrder::PostOrder,
+    )
+    .and_then(Array::<i64>::try_from)
+    .unwrap();
+    assert_eq!(mapped.iter().collect::<Vec<_>>(), vec![11, 12]);
+
+    let mapped = structural_map(
+        Array::new(vec![1i64, 2]),
+        |integer: i64| -> Result<i64> { Ok(integer + 20) },
+        WalkOrder::PostOrder,
+    )
+    .and_then(Array::<i64>::try_from)
+    .unwrap();
+    assert_eq!(mapped.iter().collect::<Vec<_>>(), vec![21, 22]);
+
+    let mutated = structural_mutate(
+        Array::new(vec![1i64, 2]),
+        |integer: i64, _mutator: &mut MutateContext<'_, ()>| integer * 2,
+    )
+    .and_then(Array::<i64>::try_from)
+    .unwrap();
+    assert_eq!(mutated.iter().collect::<Vec<_>>(), vec![2, 4]);
+}
+
 #[test]
 fn twelve_link_tuple_reaches_final_map_dispatch() {
     let mut final_dispatch = IncrementIntegers;

Reply via email to