Skip to content

Commit e17bfcd

Browse files
committed
use DeriveObject.
Signed-off-by: yuchuan <yuchuan.7streams@gmail.com>
1 parent 686fe95 commit e17bfcd

4 files changed

Lines changed: 59 additions & 94 deletions

File tree

examples/rust_stubgen/rust/src/generated/rust_stubgen/mod.rs

Lines changed: 14 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -22,33 +22,16 @@
2222
//! FFI bindings for `rust_stubgen` (generated by tvm-ffi-stubgen).
2323
2424
// tvm-ffi-stubgen(begin): helpers
25-
fn lookup_type_index(type_key: &'static str) -> i32 {
26-
static CACHE: std::sync::OnceLock<
27-
std::sync::Mutex<std::collections::HashMap<&'static str, i32>>,
28-
> = std::sync::OnceLock::new();
29-
let cache = CACHE.get_or_init(|| std::sync::Mutex::new(std::collections::HashMap::new()));
30-
if let Some(v) = cache.lock().unwrap().get(type_key) {
31-
return *v;
32-
}
33-
let arg = unsafe { tvm_ffi::tvm_ffi_sys::TVMFFIByteArray::from_str(type_key) };
34-
let mut tindex = 0;
35-
let ret = unsafe { tvm_ffi::tvm_ffi_sys::TVMFFITypeKeyToIndex(&arg, &mut tindex) };
36-
assert_eq!(ret, 0, "type key `{type_key}` is not registered");
37-
cache.lock().unwrap().insert(type_key, tindex);
38-
tindex
39-
}
40-
4125
fn get_type_method(
42-
type_key: &'static str,
26+
type_index: i32,
4327
method_name: &str,
4428
) -> tvm_ffi::Result<tvm_ffi::Function> {
45-
let type_index = lookup_type_index(type_key);
4629
unsafe {
4730
let info = tvm_ffi::tvm_ffi_sys::TVMFFIGetTypeInfo(type_index);
4831
if info.is_null() {
4932
return Err(tvm_ffi::Error::new(
5033
tvm_ffi::TYPE_ERROR,
51-
&format!("no type info for `{type_key}`"),
34+
&format!("no type info for type_index `{type_index}`"),
5235
"",
5336
));
5437
}
@@ -61,7 +44,9 @@ fn get_type_method(
6144
) {
6245
return Err(tvm_ffi::Error::new(
6346
tvm_ffi::TYPE_ERROR,
64-
&format!("method `{method_name}` on `{type_key}` is not a Function"),
47+
&format!(
48+
"method `{method_name}` on type_index `{type_index}` is not a Function"
49+
),
6550
"",
6651
));
6752
}
@@ -71,7 +56,7 @@ fn get_type_method(
7156
}
7257
Err(tvm_ffi::Error::new(
7358
tvm_ffi::TYPE_ERROR,
74-
&format!("method `{method_name}` not found on `{type_key}`"),
59+
&format!("method `{method_name}` not found on type_index `{type_index}`"),
7560
"",
7661
))
7762
}
@@ -82,33 +67,23 @@ use std::ops::Deref;
8267
use std::ops::DerefMut;
8368
use tvm_ffi::AnyView;
8469
use tvm_ffi::Result;
70+
use tvm_ffi::derive::Object as DeriveObject;
8571
use tvm_ffi::derive::ObjectRef as DeriveObjectRef;
8672
use tvm_ffi::object::Object;
8773
use tvm_ffi::object::ObjectArc;
8874
use tvm_ffi::object::ObjectCore;
89-
use tvm_ffi::tvm_ffi_sys::TVMFFIObject;
9075
// tvm-ffi-stubgen(end)
9176

9277
// tvm-ffi-stubgen(begin): object/rust_stubgen.IntPair
9378
#[repr(C)]
79+
#[derive(DeriveObject)]
80+
#[type_key = "rust_stubgen.IntPair"]
9481
pub struct IntPairObj {
9582
base: Object,
9683
pub a: i64,
9784
pub b: i64,
9885
}
9986

100-
unsafe impl ObjectCore for IntPairObj {
101-
const TYPE_KEY: &'static str = "rust_stubgen.IntPair";
102-
103-
fn type_index() -> i32 {
104-
lookup_type_index(Self::TYPE_KEY)
105-
}
106-
107-
unsafe fn object_header_mut(this: &mut Self) -> &mut TVMFFIObject {
108-
Object::object_header_mut(&mut this.base)
109-
}
110-
}
111-
11287
#[repr(C)]
11388
#[derive(DeriveObjectRef, Clone)]
11489
pub struct IntPair {
@@ -130,27 +105,27 @@ impl DerefMut for IntPair {
130105

131106
impl IntPair {
132107
pub fn new(_0: i64, _1: i64) -> Result<Self> {
133-
let ctor = get_type_method(IntPairObj::TYPE_KEY, "__ffi_init__")?;
108+
let ctor = get_type_method(IntPairObj::type_index(), "__ffi_init__")?;
134109
Ok(ctor.call_packed(&[AnyView::from(&_0), AnyView::from(&_1)])?.try_into()?)
135110
}
136111

137112
pub fn sum(&mut self) -> Result<i64> {
138-
let f = get_type_method(IntPairObj::TYPE_KEY, "sum")?;
113+
let f = get_type_method(IntPairObj::type_index(), "sum")?;
139114
Ok(f.call_packed(&[AnyView::from(&*self)])?.try_into()?)
140115
}
141116

142117
pub fn scale(&mut self, _0: i64) -> Result<()> {
143-
let f = get_type_method(IntPairObj::TYPE_KEY, "scale")?;
118+
let f = get_type_method(IntPairObj::type_index(), "scale")?;
144119
Ok(f.call_packed(&[AnyView::from(&*self), AnyView::from(&_0)])?.try_into()?)
145120
}
146121

147122
pub fn swapped(&mut self) -> Result<IntPair> {
148-
let f = get_type_method(IntPairObj::TYPE_KEY, "swapped")?;
123+
let f = get_type_method(IntPairObj::type_index(), "swapped")?;
149124
Ok(f.call_packed(&[AnyView::from(&*self)])?.try_into()?)
150125
}
151126

152127
pub fn checked_div(&mut self, _0: i64) -> Result<i64> {
153-
let f = get_type_method(IntPairObj::TYPE_KEY, "checked_div")?;
128+
let f = get_type_method(IntPairObj::type_index(), "checked_div")?;
154129
Ok(f.call_packed(&[AnyView::from(&*self), AnyView::from(&_0)])?.try_into()?)
155130
}
156131
}

python/tvm_ffi/stub/rust_generator/codegen.py

Lines changed: 26 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -92,35 +92,30 @@ def body(self) -> list[str]:
9292
_use(self.imports, "std::ops::Deref")
9393
_use(self.imports, "tvm_ffi::object::ObjectArc")
9494
_use(self.imports, "tvm_ffi::object::ObjectCore")
95+
_use(self.imports, "tvm_ffi::derive::Object", alias="DeriveObject")
9596
_use(self.imports, "tvm_ffi::derive::ObjectRef", alias="DeriveObjectRef")
96-
_use(self.imports, "tvm_ffi::tvm_ffi_sys::TVMFFIObject")
9797
if self.is_root:
9898
_use(self.imports, "tvm_ffi::object::Object")
9999
if self.mutable:
100100
_use(self.imports, "std::ops::DerefMut")
101101

102102
leaf, obj_struct, base_type = self.leaf, self.obj_struct, self.base_type
103103
lines: list[str] = []
104-
lines += ["#[repr(C)]", f"pub struct {obj_struct} {{", f" base: {base_type},"]
104+
# The `ObjectCore` impl (TYPE_KEY / per-class static `type_index` /
105+
# `object_header_mut`) is folded into the `#[derive(Object)]` proc macro,
106+
# which derives `object_header_mut` from the first field and caches the
107+
# type index in a per-type static -- no shared hashmap lookup.
108+
lines += [
109+
"#[repr(C)]",
110+
"#[derive(DeriveObject)]",
111+
f'#[type_key = "{self.info.type_key}"]',
112+
f"pub struct {obj_struct} {{",
113+
f" base: {base_type},",
114+
]
105115
for field in self.info.fields:
106116
lines.append(f" pub {_rust_ident(field.name)}: {self.render_field(field)},")
107117
lines += ["}", ""]
108118

109-
lines += [
110-
f"unsafe impl ObjectCore for {obj_struct} {{",
111-
f' const TYPE_KEY: &\'static str = "{self.info.type_key}";',
112-
"",
113-
" fn type_index() -> i32 {",
114-
" lookup_type_index(Self::TYPE_KEY)",
115-
" }",
116-
"",
117-
" unsafe fn object_header_mut(this: &mut Self) -> &mut TVMFFIObject {",
118-
f" {base_type}::object_header_mut(&mut this.base)",
119-
" }",
120-
"}",
121-
"",
122-
]
123-
124119
lines += [
125120
"#[repr(C)]",
126121
"#[derive(DeriveObjectRef, Clone)]",
@@ -184,7 +179,9 @@ def _new_fn(self, init_method: FuncInfo | None) -> list[str]:
184179
if params:
185180
_use(self.imports, "tvm_ffi::AnyView")
186181
packed = _packed_args_expr(params, is_member=False)
187-
getter = f' let ctor = get_type_method({self.obj_struct}::TYPE_KEY, "__ffi_init__")?;'
182+
getter = (
183+
f' let ctor = get_type_method({self.obj_struct}::type_index(), "__ffi_init__")?;'
184+
)
188185
return [
189186
f"pub fn new({sig}) -> Result<Self> {{",
190187
*_packed_call_lines("ctor", getter, packed, "Self"),
@@ -211,7 +208,7 @@ def _method_fn(self, method: FuncInfo) -> list[str]:
211208
if method.is_member or params:
212209
_use(self.imports, "tvm_ffi::AnyView")
213210
packed = _packed_args_expr(params, method.is_member)
214-
getter = f' let f = get_type_method({self.obj_struct}::TYPE_KEY, "{ffi_name}")?;'
211+
getter = f' let f = get_type_method({self.obj_struct}::type_index(), "{ffi_name}")?;'
215212
header = f"pub fn {rust_name}({', '.join(sig_parts)}) -> Result<{ret}> {{"
216213
return [header, *_packed_call_lines("f", getter, packed, ret), "}"]
217214

@@ -328,35 +325,19 @@ def generate_rust_import_section(
328325

329326
#: Shared per-file helper functions. Written fully-qualified with
330327
#: zero `use`s so they never clash with the import-section block (which carries
331-
#: every object-driven `use`). `lookup_type_index` resolves+caches a type index;
332-
#: `get_type_method` pulls a reflected method off the type's method table.
333-
_RUST_HELPERS = """fn lookup_type_index(type_key: &'static str) -> i32 {
334-
static CACHE: std::sync::OnceLock<
335-
std::sync::Mutex<std::collections::HashMap<&'static str, i32>>,
336-
> = std::sync::OnceLock::new();
337-
let cache = CACHE.get_or_init(|| std::sync::Mutex::new(std::collections::HashMap::new()));
338-
if let Some(v) = cache.lock().unwrap().get(type_key) {
339-
return *v;
340-
}
341-
let arg = unsafe { tvm_ffi::tvm_ffi_sys::TVMFFIByteArray::from_str(type_key) };
342-
let mut tindex = 0;
343-
let ret = unsafe { tvm_ffi::tvm_ffi_sys::TVMFFITypeKeyToIndex(&arg, &mut tindex) };
344-
assert_eq!(ret, 0, "type key `{type_key}` is not registered");
345-
cache.lock().unwrap().insert(type_key, tindex);
346-
tindex
347-
}
348-
349-
fn get_type_method(
350-
type_key: &'static str,
328+
#: every object-driven `use`). `get_type_method` pulls a reflected method off the
329+
#: type's method table; the type index is resolved by each object's
330+
#: `#[derive(Object)]`-generated per-class static (no shared hashmap lookup).
331+
_RUST_HELPERS = """fn get_type_method(
332+
type_index: i32,
351333
method_name: &str,
352334
) -> tvm_ffi::Result<tvm_ffi::Function> {
353-
let type_index = lookup_type_index(type_key);
354335
unsafe {
355336
let info = tvm_ffi::tvm_ffi_sys::TVMFFIGetTypeInfo(type_index);
356337
if info.is_null() {
357338
return Err(tvm_ffi::Error::new(
358339
tvm_ffi::TYPE_ERROR,
359-
&format!("no type info for `{type_key}`"),
340+
&format!("no type info for type_index `{type_index}`"),
360341
"",
361342
));
362343
}
@@ -369,7 +350,9 @@ def generate_rust_import_section(
369350
) {
370351
return Err(tvm_ffi::Error::new(
371352
tvm_ffi::TYPE_ERROR,
372-
&format!("method `{method_name}` on `{type_key}` is not a Function"),
353+
&format!(
354+
"method `{method_name}` on type_index `{type_index}` is not a Function"
355+
),
373356
"",
374357
));
375358
}
@@ -379,7 +362,7 @@ def generate_rust_import_section(
379362
}
380363
Err(tvm_ffi::Error::new(
381364
tvm_ffi::TYPE_ERROR,
382-
&format!("method `{method_name}` not found on `{type_key}`"),
365+
&format!("method `{method_name}` not found on type_index `{type_index}`"),
383366
"",
384367
))
385368
}"""

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ pub fn derive_object(input: proc_macro::TokenStream) -> TokenStream {
5858
&type_key_arg, &mut tindex
5959
);
6060
if ret != 0 {
61-
proc_macro_error::abort!("Failed to get type index for type key: {}", #type_key);
61+
panic!("Failed to get type index for type key: {}", #type_key);
6262
}
6363
tindex
6464
}

tests/python/test_stubgen.py

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1048,10 +1048,13 @@ def test_rust_object_root_struct_and_impl() -> None:
10481048
assert "struct ExprObj {" in text
10491049
assert " base: Object," in text
10501050
assert " pub value: i64," in text
1051-
# ObjectCore impl
1052-
assert 'const TYPE_KEY: &\'static str = "cpp_rust_test.Expr";' in text
1053-
assert " lookup_type_index(Self::TYPE_KEY)" in text
1054-
assert " Object::object_header_mut(&mut this.base)" in text
1051+
# ObjectCore impl is folded into the `#[derive(Object)]` proc macro: the stub
1052+
# only emits the derive + `#[type_key]` attr, not a hand-written impl.
1053+
assert "#[derive(DeriveObject)]" in text
1054+
assert '#[type_key = "cpp_rust_test.Expr"]' in text
1055+
assert "unsafe impl ObjectCore" not in text
1056+
assert "lookup_type_index" not in text
1057+
assert "object_header_mut" not in text
10551058
# ref + Deref/DerefMut (value is def_rw -> mutable class)
10561059
assert "#[derive(DeriveObjectRef, Clone)]" in text
10571060
assert "struct Expr {" in text
@@ -1065,12 +1068,12 @@ def test_rust_object_root_struct_and_impl() -> None:
10651068
assert "pub fn new(value: i64) -> Result<Self> {" in text
10661069
assert "pub fn test() -> Result<i64> {" in text
10671070
assert "fn new(value: i64) -> Result<Self> {" in text
1068-
assert 'let ctor = get_type_method(ExprObj::TYPE_KEY, "__ffi_init__")?;' in text
1071+
assert 'let ctor = get_type_method(ExprObj::type_index(), "__ffi_init__")?;' in text
10691072
# uniform packed-call convention: args -> &[AnyView], return via try_into
10701073
assert "Ok(ctor.call_packed(&[AnyView::from(&value)])?.try_into()?)" in text
10711074
# static method: no self
10721075
assert "fn test() -> Result<i64> {" in text
1073-
assert 'let f = get_type_method(ExprObj::TYPE_KEY, "test")?;' in text
1076+
assert 'let f = get_type_method(ExprObj::type_index(), "test")?;' in text
10741077
assert "Ok(f.call_packed(&[])?.try_into()?)" in text
10751078
uses = {u.as_use_line() for u in imports.items}
10761079
assert "use tvm_ffi::object::Object;" in uses
@@ -1082,7 +1085,9 @@ def test_rust_object_derived_embeds_parent() -> None:
10821085
assert "struct AddObj {" in text
10831086
assert " base: ExprObj," in text # parent Obj embedded, not Object
10841087
assert " pub a: Expr," in text
1085-
assert " ExprObj::object_header_mut(&mut this.base)" in text
1088+
# object_header_mut is derived by the `#[derive(Object)]` macro from the
1089+
# first field (`base: ExprObj`), so the stub no longer hand-writes it.
1090+
assert "object_header_mut" not in text
10861091
# derived Obj also derefs to its embedded base
10871092
assert "impl Deref for AddObj {" in text
10881093
assert " type Target = ExprObj;" in text
@@ -1297,7 +1302,7 @@ def test_rust_stage3_end_to_end(tmp_path: Path, monkeypatch: pytest.MonkeyPatch)
12971302
# object block filled
12981303
assert "struct ExprObj {" in text
12991304
assert "impl Expr {" in text
1300-
assert 'get_type_method(ExprObj::TYPE_KEY, "__ffi_init__")' in text
1305+
assert 'get_type_method(ExprObj::type_index(), "__ffi_init__")' in text
13011306
# import-section filled with the machinery `use`s
13021307
assert "use tvm_ffi::object::ObjectArc;" in text
13031308
assert "use tvm_ffi::object::ObjectCore;" in text
@@ -1389,11 +1394,13 @@ def test_rust_helpers_block_filled() -> None:
13891394
)
13901395
RustGenerator().generate_helpers_block(block, Options())
13911396
text = "\n".join(block.lines)
1392-
assert "fn lookup_type_index(type_key: &'static str) -> i32 {" in text
1393-
assert "fn get_type_method(" in text
1397+
# the type-index hashmap helper is gone; only `get_type_method` remains and it
1398+
# now takes a resolved `type_index: i32` (from each object's static).
1399+
assert "fn lookup_type_index(" not in text
1400+
assert "fn get_type_method(\n type_index: i32," in text
13941401
# idempotent re-fill keeps a single copy
13951402
RustGenerator().generate_helpers_block(block, Options())
1396-
assert "\n".join(block.lines).count("fn lookup_type_index(") == 1
1403+
assert "\n".join(block.lines).count("fn get_type_method(") == 1
13971404

13981405

13991406
def test_rust_helpers_block_scaffold_added_to_existing_file() -> None:

0 commit comments

Comments
 (0)