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;