Mark a ``@py_class`` method for FFI TypeMethod registration. Decorate any staticmethod or plain instance method on a ``@py_class`` body to have it land in the C-level ``TVMFFITypeInfo.methods[]`` table. Once registered, the method is resolvable by name from any FFI consumer — Python
(fn: Any)
| 238 | |
| 239 | |
| 240 | def method(fn: Any) -> Any: |
| 241 | """Mark a ``@py_class`` method for FFI TypeMethod registration. |
| 242 | |
| 243 | Decorate any staticmethod or plain instance method on a ``@py_class`` |
| 244 | body to have it land in the C-level ``TVMFFITypeInfo.methods[]`` |
| 245 | table. Once registered, the method is resolvable by name from any |
| 246 | FFI consumer — Python-side reflection via ``TypeInfo.methods``, |
| 247 | C++, Rust — through the same path already used by C++-defined |
| 248 | methods declared via ``refl::ObjectDef<T>().def(...)``. |
| 249 | |
| 250 | Example:: |
| 251 | |
| 252 | from tvm_ffi import Object, method |
| 253 | from tvm_ffi.dataclasses import py_class |
| 254 | |
| 255 | |
| 256 | @py_class("example.Node") |
| 257 | class Node(Object): |
| 258 | x: int |
| 259 | |
| 260 | @method |
| 261 | def label(self) -> str: |
| 262 | return f"N({self.x})" |
| 263 | |
| 264 | |
| 265 | # The method is now in ``TypeInfo.methods`` and FFI-callable: |
| 266 | info = Node.__tvm_ffi_type_info__ |
| 267 | fn = next(m.func for m in info.methods if m.name == "label") |
| 268 | fn(Node(x=7)) # -> "N(7)" |
| 269 | |
| 270 | ``staticmethod`` is supported: the marker is written onto the |
| 271 | underlying function and unwrapped at registration time. Plain |
| 272 | functions are also accepted — the marker lives on the function |
| 273 | object directly. ``classmethod`` is rejected at decoration time |
| 274 | because its ``cls``-first dispatch does not match the |
| 275 | packed-call convention. |
| 276 | """ |
| 277 | if isinstance(fn, staticmethod): |
| 278 | fn.__func__.__ffi_method__ = True |
| 279 | return fn |
| 280 | if isinstance(fn, classmethod): |
| 281 | raise TypeError( |
| 282 | "@tvm_ffi.method: @classmethod is not supported for FFI " |
| 283 | "TypeMethod registration — the classmethod's ``cls`` first " |
| 284 | "arg does not match the packed-call convention. Use " |
| 285 | "@staticmethod or a plain instance method instead.", |
| 286 | ) |
| 287 | if not callable(fn): |
| 288 | raise TypeError( |
| 289 | f"@tvm_ffi.method: expected a callable, got {type(fn).__name__}.", |
| 290 | ) |
| 291 | fn.__ffi_method__ = True |
| 292 | return fn |
| 293 | |
| 294 | |
| 295 | def _is_method_marked(value: Any) -> bool: |
no outgoing calls