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>;
}