Skip to content

Commit 5c51eae

Browse files
committed
feat(rust): add ordered match_any dispatch
1 parent 3e8b2a8 commit 5c51eae

32 files changed

Lines changed: 3539 additions & 296 deletions

docs/reference/rust/index.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,4 @@ The Rust API is organized into three crates:
3737
* - 📦 `tvm-ffi-sys <generated/tvm_ffi_sys/index.html>`_
3838
- Low-level unsafe bindings to the C API.
3939
* - 📦 `tvm-ffi-macros <generated/tvm_ffi_macros/index.html>`_
40-
- Procedural macros for deriving Object and ObjectRef traits.
40+
- Procedural macros for deriving Object and ObjectRef traits and for ordered matching of erased values.

rust/README.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
(Experimental) Rust support for the `tvm-ffi` ABI.
2121
Currently, the rust support is in an experimental stage.
22+
The workspace requires Rust 1.85 or newer.
2223
This workspace contains three crates:
2324

2425
- `tvm-ffi`: Safe, ergonomic Rust bindings over the ABI.
@@ -70,3 +71,60 @@ cargo run --example load_library --features example
7071
```
7172

7273
Check out the [load_library.rs](tvm-ffi/examples/load_library.rs) for details.
74+
75+
## Ordered Type Matching
76+
77+
`match_any!` matches an erased value against `AnyPattern` implementations in
78+
source order. A matcher is evaluated before its guard, a false guard continues
79+
with the next arm, and a final `_` fallback is required. The current phase-1
80+
implementation deliberately uses ordered conditional dispatch; it does not
81+
build an index table or apply an index-space heuristic.
82+
83+
```rust
84+
use tvm_ffi::{match_any, Any, AnyPattern, AnyView};
85+
86+
struct Integer;
87+
88+
impl AnyPattern for Integer {
89+
type Bound<'a> = i64;
90+
91+
fn try_match<'a>(value: AnyView<'a>) -> Option<Self::Bound<'a>> {
92+
value.try_as::<i64>()
93+
}
94+
}
95+
96+
let value = Any::from(42_i64);
97+
let result = match_any! {
98+
value {
99+
Integer(integer) if integer > 0 => integer,
100+
_ => 0,
101+
}
102+
};
103+
assert_eq!(result, 42);
104+
```
105+
106+
## Object Layout Contracts
107+
108+
Types using `#[derive(Object)]` must use `#[repr(C)]` and place their registered
109+
base object in the first field. The declared type key and type index must
110+
identify a registered TVM-FFI object whose direct parent is that base type. The
111+
derive validates these properties when its type index is first used and rejects
112+
conflicting Rust layout claims for the same runtime index.
113+
114+
Because registry metadata cannot prove every foreign field offset and Rust
115+
validity invariant, deriving also requires a separate
116+
`unsafe impl ObjectLayout for MyObject`. That explicit implementation asserts
117+
that the complete Rust field ABI matches every foreign allocation registered
118+
under the type key; it must be reviewed like any other unsafe FFI declaration.
119+
120+
Registration and type lookup use the process-wide TVM-FFI type table. Type
121+
registration must finish before concurrent lookup begins, unless the caller
122+
provides external synchronization. Manual `unsafe impl ObjectCore`
123+
implementations remain responsible for the same header, prefix-layout,
124+
registration, and foreign-ABI compatibility requirements.
125+
126+
Rust-owned `ObjectArc` allocations do not currently support foreign weak
127+
owners. Releasing the final strong owner through Rust or C++ while a foreign
128+
weak owner remains aborts the process rather than permitting access to an
129+
already-dropped embedded reference-count header. Cloning an `ObjectArc` also
130+
aborts before the ABI's 32-bit strong-count field can overflow.

rust/tvm-ffi-macros/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ description = "Procedural macro crate for tvm-ffi"
2121

2222
version = "0.1.0-alpha.0"
2323
edition = "2021"
24+
rust-version = "1.85"
2425
license = "Apache-2.0"
2526

2627

@@ -32,3 +33,4 @@ proc-macro2 = "^1.0"
3233
quote = "^1.0"
3334
syn = { version = "1.0.48", features = ["full", "parsing", "extra-traits"] }
3435
proc-macro-error = "^1.0"
36+
proc-macro-crate = "=3.1.0"

rust/tvm-ffi-macros/src/lib.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,30 @@
2020
use proc_macro::TokenStream;
2121
use proc_macro_error::proc_macro_error;
2222

23+
mod match_any;
2324
mod object_macros;
2425
mod utils;
2526

27+
/// Match an erased TVM-FFI value against ordered typed patterns.
28+
///
29+
/// A pattern is a type that implements `tvm_ffi::AnyPattern`. Patterns are
30+
/// attempted in source order, and a false guard continues with the next arm.
31+
/// A final `_` fallback arm is required. Shared-reference and `AnyView`
32+
/// lifetimes are preserved in borrowed bindings. A mutable-reference
33+
/// scrutinee is only shared-reborrowed for the invocation, so a binding cannot
34+
/// use that mutable reference's longer lifetime after the macro returns.
2635
#[proc_macro_error]
36+
#[proc_macro]
37+
pub fn match_any(input: TokenStream) -> TokenStream {
38+
match_any::expand(input)
39+
}
40+
41+
#[proc_macro_error]
42+
/// Derive the checked `ObjectCore` boilerplate for a registered object struct.
43+
///
44+
/// The generated implementation is conditional on a separate manual
45+
/// `unsafe impl tvm_ffi::ObjectLayout for MyObject`, which is the caller's
46+
/// explicit assertion that the complete Rust fields match the foreign ABI.
2747
#[proc_macro_derive(Object, attributes(type_key, type_index))]
2848
pub fn derive_object(input: TokenStream) -> TokenStream {
2949
TokenStream::from(object_macros::derive_object(input))

0 commit comments

Comments
 (0)