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

tlopex 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 f4c947e8 [FIX][RUST] Seal structural callback result traits and update 
return-value docs (#724)
f4c947e8 is described below

commit f4c947e806bc0749debf3794bb397ad6635d87c6
Author: Linzhang Li <[email protected]>
AuthorDate: Tue Sep 1 00:03:48 2026 -0400

    [FIX][RUST] Seal structural callback result traits and update return-value 
docs (#724)
    
    ## Summary
    
    - Seal the structural map/mutate callback-result conversion traits so
    their
    blanket implementations do not define an open downstream extension
    point.
    - Update the Rust language guide to document and demonstrate callbacks
    that
      return `T: Into<Any>` or `Result<T>`.
    
    ## Trait sealing
    
    `IntoMapResult` and `IntoMutateResult` now share a private
    `callback_result_sealed::Sealed` supertrait. `IntoMapResult` is also
    hidden from
    the generated API documentation and explicitly documented as a
    non-extension
    point.
    
    The traits remain public because `#[dispatch(map)]` and
    `#[dispatch(mutate)]`
    expansions in downstream crates need to reference their paths. Their
    implementations remain owned by `tvm-ffi`.
    
    ## Rust guide
    
    The structural mapping and mutation guide now describes callback return
    values
    as any value convertible into `Any`, either directly or wrapped in
    `Result`.
    The examples cover both forms:
    
    - a `#[dispatch(map)]` handler returning `Result<i64>`;
    - callback-based mutation returning `i64` directly;
    - a `#[dispatch(mutate)]` handler returning `i64` directly.
    
    The error-handling section now uses `Result<T>` and `Result<i64>`.
    Existing
    `Result<Any>` examples for packed functions and the low-level
    `StructuralMutator` interface remain unchanged because those signatures
    are
    fixed.
    
    ## Testing
    
    - `cargo fmt --all -- --check`
    - `uv run cargo test --workspace`
    - `uv run cargo doc -p tvm-ffi --no-deps`
    - `uv run --group docs sphinx-build -M html docs docs/_build`
    - `git diff --check`
    
    Signed-off-by: yuchuan <[email protected]>
---
 docs/guides/rust_lang_guide.md              | 36 +++++++++++++++--------------
 rust/tvm-ffi/src/extra/structural_mutate.rs | 16 +++++++++++--
 2 files changed, 33 insertions(+), 19 deletions(-)

diff --git a/docs/guides/rust_lang_guide.md b/docs/guides/rust_lang_guide.md
index 92f2d059..f63a07e2 100644
--- a/docs/guides/rust_lang_guide.md
+++ b/docs/guides/rust_lang_guide.md
@@ -416,11 +416,11 @@ explicitly from a `StructuralVisitor`, or skip it with a 
pre-order
 ### Structural Mapping and Mutation
 
 `structural_map` is the transforming counterpart to `structural_walk`. Put
-`#[dispatch(map)]` on an impl whose `map_*` methods return `Any` or
-`Result<Any>`. Methods are tested in source order, the first matching argument
-type wins, and an unmatched value is preserved. A method may take an optional
-trailing `DefRegionKind`; a `&MapValue` method is a catch-all and should
-therefore come last:
+`#[dispatch(map)]` on an impl whose `map_*` methods return any value 
convertible
+into `Any`, directly or in `Result`. Methods are tested in source order, the
+first matching argument type wins, and an unmatched value is preserved. A
+method may take an optional trailing `DefRegionKind`; a `&MapValue` method is a
+catch-all and should therefore come last:
 
 ```rust
 use tvm_ffi::{
@@ -434,13 +434,13 @@ struct Increment {
 
 #[dispatch(map)]
 impl Increment {
-    fn map_integer(&mut self, value: i64, _kind: DefRegionKind) -> Any {
+    fn map_integer(&mut self, value: i64, _kind: DefRegionKind) -> Result<i64> 
{
         self.integers += 1;
-        Any::from(value + 1)
+        Ok(value + 1)
     }
 
-    fn map_other(&mut self, value: &MapValue) -> Result<Any> {
-        Ok(value.to_owned())
+    fn map_other(&mut self, value: &MapValue) -> Any {
+        value.to_owned()
     }
 }
 
@@ -489,9 +489,11 @@ mutator and can recurse through its language-independent 
vtable. This lets the
 implementation that registered the type own its storage and mutation rules.
 When a type has no hook, object-backed values use reflected fields.
 
-Callbacks may return `Result<Any>` to report failures. Errors propagate with
-object or reflected-field context. In-place changes completed before a later
-error are not rolled back, and the consumed root is not returned on error.
+Callbacks may return `Result<T>` for any `T` convertible into `Any`; for
+example, an integer handler can return `Result<i64>` to report failures and use
+`?`. Errors propagate with object or reflected-field context. In-place changes
+completed before a later error are not rolled back, and the consumed root is
+not returned on error.
 
 `structural_mutate` accepts typed callbacks in addition to a
 `StructuralMutator`. Callbacks receive `MutateContext`; `MutateCallbacks` adds
@@ -499,7 +501,7 @@ state shared by the callback chain:
 
 ```rust
 use tvm_ffi::{
-    structural_mutate, Any, Array, MapValue, MutateCallbacks, MutateContext,
+    structural_mutate, Array, MapValue, MutateCallbacks, MutateContext,
 };
 
 #[derive(Default)]
@@ -512,7 +514,7 @@ let mut mutator = MutateCallbacks::new(
     (
         |value: i64, mutator: &mut MutateContext<'_, Stats>| {
             mutator.state_mut().integers += 1;
-            Any::from(value + 1)
+            value + 1
         },
         |_value: &MapValue, mutator: &mut MutateContext<'_, Stats>| {
             mutator.default_mutate()
@@ -535,7 +537,7 @@ current value's final result and may recursively call 
`self.mutate()`;
 an unmatched value follows default mutation with its current in-place permit:
 
 ```rust
-use tvm_ffi::{dispatch, structural_mutate, Any, Array, DefRegionKind};
+use tvm_ffi::{dispatch, structural_mutate, Array, DefRegionKind};
 
 #[derive(Default)]
 struct Increment {
@@ -544,9 +546,9 @@ struct Increment {
 
 #[dispatch(mutate)]
 impl Increment {
-    fn mutate_integer(&mut self, value: i64, _kind: DefRegionKind) -> Any {
+    fn mutate_integer(&mut self, value: i64, _kind: DefRegionKind) -> i64 {
         self.integers += 1;
-        Any::from(value + 1)
+        value + 1
     }
 }
 
diff --git a/rust/tvm-ffi/src/extra/structural_mutate.rs 
b/rust/tvm-ffi/src/extra/structural_mutate.rs
index e7088bd4..ecd62ae0 100644
--- a/rust/tvm-ffi/src/extra/structural_mutate.rs
+++ b/rust/tvm-ffi/src/extra/structural_mutate.rs
@@ -70,11 +70,23 @@ pub use super::structural_common::StructuralValue as 
MapValue;
 #[doc(hidden)]
 pub type MapResult = Result<Any>;
 
+mod callback_result_sealed {
+    use super::{Any, Result};
+
+    pub trait Sealed {}
+
+    impl<T: Into<Any>> Sealed for T {}
+    impl<T: Into<Any>> Sealed for Result<T> {}
+}
+
 /// 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 {
+///
+/// This trait is sealed and is not an extension point.
+#[doc(hidden)]
+pub trait IntoMapResult: callback_result_sealed::Sealed {
     fn into_map_result(self) -> MapResult;
 }
 
@@ -223,7 +235,7 @@ impl<U: StructuralMutator> IntoMutator<U> for &mut U {
 /// A callback may return any value convertible into [`Any`], or wrap it in
 /// [`Result`] to use `?`.
 #[doc(hidden)]
-pub trait IntoMutateResult {
+pub trait IntoMutateResult: callback_result_sealed::Sealed {
     fn into_mutate_result(self) -> Result<Any>;
 }
 

Reply via email to