This is an automated email from the ASF dual-hosted git repository.
tqchen 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 c3424d0b [Rust] IntoArg, IntoPackedArg(s), Map key lookup by IntoArg
(#963)
c3424d0b is described below
commit c3424d0b318a84468c5556ff72b4466067865a82
Author: Tianqi Chen <[email protected]>
AuthorDate: Sun Nov 8 09:28:40 2026 -0500
[Rust] IntoArg, IntoPackedArg(s), Map key lookup by IntoArg (#963)
- `IntoArg<T>` replaces `IntoObjectRef<T>`: a `T`, a `&T` or a subtype
where a `T` is expected, for every container element rather than object
references only, plus `&str` -> `String` and `&[u8]` -> `Bytes`.
`into_arg` returns `T` or `&T`; `into_owned` moves or clones as
`Cow::into_owned`. The stub generator emits `impl IntoArg<T>` /
`.into_owned()`.
- The packed-call argument traits (`IntoArgHolder`,
`IntoArgHolderTuple`, `ArgIntoRef`, `PackedArg`, `TupleAsPackedArgs`)
collapse into `function::PackedCallArg` and `function::PackedCallArgs`.
`call_tuple` and `into_typed_fn!` share one path, so `call_tuple` also
takes `&str` and `&[u8]`; `call_tuple_with_len` is removed.
- `Map::get` and `Map::contains_key` take `impl IntoArg<K>`: `get(&k)`,
`get(k)`, `get(&sub)` and `get("key")` all work.
- `type_traits.rs` orders its traits by dependency, each followed by its
impls, and the trait docs are tightened.
---
docs/guides/rust_lang_guide.rst | 2 +-
python/tvm_ffi/stub/rust_generator/codegen.py | 14 +-
python/tvm_ffi/stub/rust_generator/consts.py | 4 +-
rust/tvm-ffi-macros/src/object_macros.rs | 16 -
rust/tvm-ffi-macros/src/rs_object.rs | 2 +-
rust/tvm-ffi/src/any.rs | 2 +
rust/tvm-ffi/src/collections/array.rs | 25 +-
rust/tvm-ffi/src/collections/list.rs | 2 +
rust/tvm-ffi/src/collections/map.rs | 43 +-
rust/tvm-ffi/src/collections/tensor.rs | 38 +-
rust/tvm-ffi/src/extra/module.rs | 18 +-
rust/tvm-ffi/src/extra/unchanged.rs | 3 +
rust/tvm-ffi/src/function.rs | 66 +--
rust/tvm-ffi/src/function_internal.rs | 297 ++--------
rust/tvm-ffi/src/lib.rs | 6 +-
rust/tvm-ffi/src/macros.rs | 150 ++---
rust/tvm-ffi/src/object.rs | 72 ---
rust/tvm-ffi/src/optional.rs | 2 +
rust/tvm-ffi/src/type_traits.rs | 812 ++++++++++++++------------
rust/tvm-ffi/tests/test_big_int.rs | 2 +-
rust/tvm-ffi/tests/test_function.rs | 2 +-
rust/tvm-ffi/tests/test_function_metadata.rs | 6 +-
rust/tvm-ffi/tests/test_map.rs | 64 +-
rust/tvm-ffi/tests/test_match_any.rs | 2 +-
rust/tvm-ffi/tests/test_module.rs | 4 +-
rust/tvm-ffi/tests/test_rs_object.rs | 22 +-
rust/tvm-ffi/tests/test_structural_mutate.rs | 16 +-
tests/python/test_stubgen_rust.py | 72 +--
28 files changed, 765 insertions(+), 999 deletions(-)
diff --git a/docs/guides/rust_lang_guide.rst b/docs/guides/rust_lang_guide.rst
index 4f476985..3fa3a679 100644
--- a/docs/guides/rust_lang_guide.rst
+++ b/docs/guides/rust_lang_guide.rst
@@ -417,7 +417,7 @@ names the reference to the parent's object:
``Point3Obj::new``, which takes the parent's object, then the fields: a scalar
(``bool``, an integer or a float) as its own type, so that a literal infers as
it,
and any other field as ``impl Into<T>``. A constructor on the reference takes
an
-object reference as ``impl IntoObjectRef<T>``, as the ones ``tvm-ffi-stubgen``
+object reference as ``impl IntoArg<T>``, as the ones ``tvm-ffi-stubgen``
generates do. The reference dereferences to the object
(``#[object_ref(skip_deref)]`` opts out), and its private ``from_object``
wraps a new
object for the type's constructors. The reference also converts into
``parent``,
diff --git a/python/tvm_ffi/stub/rust_generator/codegen.py
b/python/tvm_ffi/stub/rust_generator/codegen.py
index b8eb3f46..a7f9acd9 100644
--- a/python/tvm_ffi/stub/rust_generator/codegen.py
+++ b/python/tvm_ffi/stub/rust_generator/codegen.py
@@ -25,7 +25,7 @@ the verdict of :mod:`tvm_ffi.stub.layout`:
width, pinned by a ``const`` size/alignment assertion. ``<Leaf>Obj::new``
and the wrapper's ``new`` take every field root to leaf: the former each as
its own type, the latter a scalar as its own type, an object reference as
- ``impl IntoObjectRef`` and anything else as ``impl Into``. ``custom-new``
+ ``impl IntoArg`` and anything else as ``impl Into``. ``custom-new``
leaves the wrapper's ``new`` to hand-written code and names the generated
one ``from_fields``. A type that is not final
can be the parent of a type defined in Rust (``tvm_ffi::rs_object``): its
@@ -140,13 +140,13 @@ def _is_object_ref(schema: TypeSchema) -> bool:
def _param_type(param: _Param, imports: RustImports) -> str:
"""Type a parameter of the wrapper's allocator.
- A scalar as itself, an object reference as ``impl IntoObjectRef``
(recording its ``use``,
- which also brings ``into_owned_object_ref`` into scope), anything else as
``impl Into``.
+ A scalar as itself, an object reference as ``impl IntoArg`` (recording its
``use``,
+ which also brings ``into_owned`` into scope), anything else as ``impl
Into``.
"""
if param.rust_type in C_RUST.RUST_EXACT_PARAMS:
return param.rust_type
if param.is_object:
- return f"impl
{imports.record('tvm_ffi::IntoObjectRef')}<{param.rust_type}>"
+ return f"impl {imports.record('tvm_ffi::IntoArg')}<{param.rust_type}>"
return f"impl Into<{param.rust_type}>"
@@ -155,7 +155,7 @@ def _forward(param: _Param) -> str:
ident = rust_ident(param.name)
if param.rust_type in C_RUST.RUST_EXACT_PARAMS:
return ident
- return f"{ident}.into_owned_object_ref()" if param.is_object else
f"{ident}.into()"
+ return f"{ident}.into_owned()" if param.is_object else f"{ident}.into()"
def _check_width(target: str, field: NamedTypeSchema, rust_type: str, width:
int) -> None:
@@ -694,7 +694,7 @@ class _ObjectRenderer:
) -> list[str]:
"""Render ``<head>(<params>) -> Self { let <call>; Self { <init> } }``
in an ``impl`` block.
- ``generic`` takes a parameter that is not a scalar as ``impl
IntoObjectRef`` or
+ ``generic`` takes a parameter that is not a scalar as ``impl IntoArg``
or
``impl Into`` (:func:`_param_type`).
"""
plist = [
@@ -716,7 +716,7 @@ class _ObjectRenderer:
``<Leaf>Obj::new`` takes every field as its own type, so the parent's,
generated
or hand-written, takes what it hands on. The wrapper's ``new`` takes a
scalar
field as its own type, as ``#[rs_object]``'s ``new`` does, an object
reference as
- ``impl IntoObjectRef`` and any other as ``impl Into``
(:func:`_param_type`), and
+ ``impl IntoArg`` and any other as ``impl Into`` (:func:`_param_type`),
and
converts it on the way to ``<Leaf>Obj::new``.
``custom-new`` names the wrapper's allocator ``from_fields`` instead.
``<Leaf>Obj::new`` of a type that is not final is public: a subtype
defined in Rust
diff --git a/python/tvm_ffi/stub/rust_generator/consts.py
b/python/tvm_ffi/stub/rust_generator/consts.py
index 557e4ae2..4c341890 100644
--- a/python/tvm_ffi/stub/rust_generator/consts.py
+++ b/python/tvm_ffi/stub/rust_generator/consts.py
@@ -112,13 +112,13 @@ RUST_SCALAR_WIDTHS = {
#: Parameters of the wrapper's allocator taken as their own type, as
``#[rs_object]``'s
#: ``new`` takes them: a literal infers only from its exact type. An object
reference is
-#: ``impl IntoObjectRef<T>`` and any other parameter ``impl Into<T>``;
``<Leaf>Obj::new``
+#: ``impl IntoArg<T>`` and any other parameter ``impl Into<T>``;
``<Leaf>Obj::new``
#: takes every one as its own type.
RUST_EXACT_PARAMS = frozenset(
{"bool", "i8", "i16", "i32", "i64", "isize", "u8", "u16", "u32", "u64",
"usize", "f32", "f64"}
)
-#: Builtin origins whose Rust type is an object reference, taken as ``impl
IntoObjectRef<T>``.
+#: Builtin origins whose Rust type is an object reference, taken as ``impl
IntoArg<T>``.
#: A type key outside ``ffi.*`` is one too: a generated or ``ty-map``'d
binding. ``Shape``,
#: like ``Array`` / ``List`` / ``Map``, is a container taken as ``impl
Into<T>``, which also
#: accepts what it is built from (``From<impl AsRef<[i64]>>``).
diff --git a/rust/tvm-ffi-macros/src/object_macros.rs
b/rust/tvm-ffi-macros/src/object_macros.rs
index 58eef552..2ba50aca 100644
--- a/rust/tvm-ffi-macros/src/object_macros.rs
+++ b/rust/tvm-ffi-macros/src/object_macros.rs
@@ -725,22 +725,6 @@ pub(crate) fn expand_object_ref(
}
}
- impl #tvm_ffi_crate::object::IntoObjectRef<#struct_name> for
#struct_name {
- type Output = Self;
- #[inline(always)]
- fn into_object_ref(self) -> Self {
- self
- }
- }
-
- impl<'a> #tvm_ffi_crate::object::IntoObjectRef<#struct_name> for &'a
#struct_name {
- type Output = &'a #struct_name;
- #[inline(always)]
- fn into_object_ref(self) -> &'a #struct_name {
- self
- }
- }
-
impl ::std::convert::From<&#struct_name> for #struct_name {
#[inline]
fn from(value: &#struct_name) -> Self {
diff --git a/rust/tvm-ffi-macros/src/rs_object.rs
b/rust/tvm-ffi-macros/src/rs_object.rs
index da53a2e3..26f32f19 100644
--- a/rust/tvm-ffi-macros/src/rs_object.rs
+++ b/rust/tvm-ffi-macros/src/rs_object.rs
@@ -160,7 +160,7 @@ fn expand(args: &RsObjectArgs, item: &DeriveInput) ->
syn::Result<TokenStream2>
let base_ty = &base.ty;
// `new` takes a scalar as its own type, so that a literal infers as it,
and any
// other field as `impl Into`. Tokens alone do not tell an object
reference from a
- // value, so this object-level allocator does not take `impl
IntoObjectRef` as a
+ // value, so this object-level allocator does not take `impl IntoArg` as a
// reference's constructor does.
let params = fields.iter().map(|field| {
let (name, ty) = (&field.ident, &field.ty);
diff --git a/rust/tvm-ffi/src/any.rs b/rust/tvm-ffi/src/any.rs
index a5f05243..54f6498f 100644
--- a/rust/tvm-ffi/src/any.rs
+++ b/rust/tvm-ffi/src/any.rs
@@ -605,8 +605,10 @@ crate::impl_any_compatible_conversions!(
);
// Only out of `Any`: a raw pointer and the root reference are not call
arguments.
crate::impl_try_from_any!(*mut core::ffi::c_void, crate::object::ObjectRef);
+crate::impl_into_arg!(Any, *mut core::ffi::c_void, crate::object::ObjectRef);
crate::impl_try_from_any_for_parametric!(Option<T>);
+crate::impl_into_arg!(impl[T: AnyCompatible + Clone] Option<T>);
/// The conversion of a typed function argument, whose error names the
/// argument's index.
diff --git a/rust/tvm-ffi/src/collections/array.rs
b/rust/tvm-ffi/src/collections/array.rs
index 8d28473b..891e7af6 100644
--- a/rust/tvm-ffi/src/collections/array.rs
+++ b/rust/tvm-ffi/src/collections/array.rs
@@ -25,8 +25,9 @@ use crate::any::TryFromTemp;
use crate::collections::list::seq_cells;
use crate::derive::Object;
use crate::object::ObjectCoreWithExtraItems;
-use crate::object::{IntoObjectRef, Object, ObjectArc};
+use crate::object::{Object, ObjectArc};
use crate::type_traits::{ContainerElement, RefFromAnyUnchecked, TypeSubsumes};
+use crate::IntoArg;
use crate::{Any, AnyCompatible, AnyView, ObjectRefCore};
use tvm_ffi_sys::TVMFFITypeIndex as TypeIndex;
use tvm_ffi_sys::{TVMFFIAny, TVMFFIObject};
@@ -161,22 +162,28 @@ impl<T: ContainerElement + Clone> From<&Array<T>> for
Array<T> {
}
}
-impl<T, U: TypeSubsumes<T>> IntoObjectRef<Array<U>> for Array<T> {
+impl<T, U: TypeSubsumes<T>> IntoArg<Array<U>> for Array<T> {
type Output = Array<U>;
#[inline(always)]
- fn into_object_ref(self) -> Array<U> {
+ fn into_arg(self) -> Array<U> {
+ self.upcast()
+ }
+ #[inline(always)]
+ fn into_owned(self) -> Array<U> {
self.upcast()
}
}
-impl<'a, T, U: TypeSubsumes<T> + ContainerElement + Clone + 'a>
IntoObjectRef<Array<U>>
- for &'a Array<T>
-{
+impl<'a, T, U: TypeSubsumes<T> + ContainerElement + Clone + 'a>
IntoArg<Array<U>> for &'a Array<T> {
type Output = &'a Array<U>;
#[inline(always)]
- fn into_object_ref(self) -> &'a Array<U> {
+ fn into_arg(self) -> &'a Array<U> {
self.upcast_ref()
}
+ #[inline(always)]
+ fn into_owned(self) -> Array<U> {
+ self.upcast_ref().clone()
+ }
}
/// An array upcasts to the root [`ObjectRef`](crate::object::ObjectRef).
@@ -220,7 +227,7 @@ impl<T> Array<T> {
/// let objects: Array<ObjectRef> = shapes.clone().upcast();
/// assert!(objects[0].same_as(&shapes[0]));
/// ```
- #[inline]
+ #[inline(always)]
pub fn upcast<U: TypeSubsumes<T>>(self) -> Array<U> {
Array {
data: self.data,
@@ -229,7 +236,7 @@ impl<T> Array<T> {
}
/// Borrow this array as an `Array<U>`, as [`upcast`](Self::upcast) does.
- #[inline]
+ #[inline(always)]
pub fn upcast_ref<U: TypeSubsumes<T>>(&self) -> &Array<U> {
// SAFETY: `Array<T>` and `Array<U>` are both `repr(C)` over one
// `ObjectArc<ArrayObj>`, and every `T` cell is a valid `U` cell.
diff --git a/rust/tvm-ffi/src/collections/list.rs
b/rust/tvm-ffi/src/collections/list.rs
index 1951145f..6743c248 100644
--- a/rust/tvm-ffi/src/collections/list.rs
+++ b/rust/tvm-ffi/src/collections/list.rs
@@ -802,6 +802,8 @@ where
}
}
+crate::impl_into_arg!(impl[T: ContainerElement] List<T>);
+
impl<'b, T: ContainerElement> TryFrom<&'b Any> for List<T> {
type Error = Error;
diff --git a/rust/tvm-ffi/src/collections/map.rs
b/rust/tvm-ffi/src/collections/map.rs
index 511cf96d..04232e1c 100644
--- a/rust/tvm-ffi/src/collections/map.rs
+++ b/rust/tvm-ffi/src/collections/map.rs
@@ -29,6 +29,7 @@
// hashing (`AnyHash`/`AnyEqual`) and dense/small probing, just as the Python
// bindings also delegate.
+use std::borrow::Borrow;
use std::fmt::Debug;
use std::marker::PhantomData;
use std::ops::Deref;
@@ -37,9 +38,9 @@ use crate::any::TryFromTemp;
use crate::derive::Object;
use crate::extra::cold_init_lazy_lock::ColdInitLazyLock;
use crate::function::Function;
-use crate::object::IntoObjectRef;
use crate::object::{Object, ObjectArc};
use crate::type_traits::{ContainerElement, TypeSubsumes};
+use crate::IntoArg;
use crate::{Any, AnyCompatible, AnyView, Error, ObjectRefCore, Result};
use tvm_ffi_sys::TVMFFITypeIndex as TypeIndex;
use tvm_ffi_sys::{TVMFFIAny, TVMFFIObject};
@@ -121,8 +122,8 @@ pub struct MapObj {
/// .into_iter()
/// .collect();
/// assert_eq!(map.len(), 2);
-/// assert_eq!(map.get(&String::from("b"))?, Some(2));
-/// assert_eq!(map.get(&String::from("c"))?, None);
+/// assert_eq!(map.get("b")?, Some(2));
+/// assert_eq!(map.get("c")?, None);
/// # Ok::<(), tvm_ffi::Error>(())
/// ```
#[repr(C)]
@@ -285,9 +286,10 @@ where
/// is not hashable.
///
/// The result for a `key` of another type than the map's keys is
- /// unspecified, as for [`Map::get`].
- pub fn contains_key(&self, key: &K) -> Result<bool> {
- let present = self.try_contains_key(key)?;
+ /// unspecified, as for [`Map::get`]. Code generic over `K` that passes a
+ /// `&K` adds the bound `for<'a> &'a K: IntoArg<K>`.
+ pub fn contains_key(&self, key: impl IntoArg<K>) -> Result<bool> {
+ let present = self.try_contains_key(key.into_arg().borrow())?;
if !present {
self.debug_assert_key_type();
}
@@ -304,9 +306,14 @@ where
/// The result for a `key` of another type than the map's keys is
/// unspecified: it currently reads as absent, since a lookup hashes the
key
/// instead of reading a stored one. Debug builds assert against it.
- pub fn get(&self, key: &K) -> Result<Option<V>> {
+ ///
+ /// A `&str` key builds a temporary `String` for the runtime lookup. Code
+ /// generic over `K` that passes a `&K` adds the bound
+ /// `for<'a> &'a K: IntoArg<K>`.
+ pub fn get(&self, key: impl IntoArg<K>) -> Result<Option<V>> {
+ let key = key.into_arg();
let result = crate::cached_global_func!("ffi.MapGetItemOrMissing")
- .call_packed(&[AnyView::from(self), element_view(key)])?;
+ .call_packed(&[AnyView::from(self), element_view(key.borrow())])?;
let raw = result.as_raw_ffi_any();
if raw.type_index >= TypeIndex::kTVMFFIStaticObjectBegin as i32
&& unsafe { raw.data_union.v_obj } as usize == *MISSING_OBJECT
@@ -472,7 +479,7 @@ impl<K, V> Map<K, V> {
/// `Map<KU, VU>(const Map<K, V>&)` does for bases `KU` and `VU`.
///
/// It is a method, not `From`, for the reasons on
[`Array::upcast`](crate::Array::upcast).
- #[inline]
+ #[inline(always)]
pub fn upcast<KU: TypeSubsumes<K>, VU: TypeSubsumes<V>>(self) -> Map<KU,
VU> {
Map {
data: self.data,
@@ -481,7 +488,7 @@ impl<K, V> Map<K, V> {
}
/// Borrow this map as a `Map<KU, VU>`, as [`upcast`](Self::upcast) does.
- #[inline]
+ #[inline(always)]
pub fn upcast_ref<KU: TypeSubsumes<K>, VU: TypeSubsumes<V>>(&self) ->
&Map<KU, VU> {
// SAFETY: both are `repr(C)` over one `ObjectArc<MapObj>`, and every
// entry of `Map<K, V>` is a valid entry of `Map<KU, VU>`.
@@ -489,22 +496,30 @@ impl<K, V> Map<K, V> {
}
}
-impl<K, V, KU: TypeSubsumes<K>, VU: TypeSubsumes<V>> IntoObjectRef<Map<KU,
VU>> for Map<K, V> {
+impl<K, V, KU: TypeSubsumes<K>, VU: TypeSubsumes<V>> IntoArg<Map<KU, VU>> for
Map<K, V> {
type Output = Map<KU, VU>;
#[inline(always)]
- fn into_object_ref(self) -> Map<KU, VU> {
+ fn into_arg(self) -> Map<KU, VU> {
+ self.upcast()
+ }
+ #[inline(always)]
+ fn into_owned(self) -> Map<KU, VU> {
self.upcast()
}
}
-impl<'a, K, V, KU: TypeSubsumes<K> + 'a, VU: TypeSubsumes<V> + 'a>
IntoObjectRef<Map<KU, VU>>
+impl<'a, K, V, KU: TypeSubsumes<K> + 'a, VU: TypeSubsumes<V> + 'a>
IntoArg<Map<KU, VU>>
for &'a Map<K, V>
{
type Output = &'a Map<KU, VU>;
#[inline(always)]
- fn into_object_ref(self) -> &'a Map<KU, VU> {
+ fn into_arg(self) -> &'a Map<KU, VU> {
self.upcast_ref()
}
+ #[inline(always)]
+ fn into_owned(self) -> Map<KU, VU> {
+ self.upcast_ref().clone()
+ }
}
// --- Iterators ---
diff --git a/rust/tvm-ffi/src/collections/tensor.rs
b/rust/tvm-ffi/src/collections/tensor.rs
index 0cee1734..24ec0200 100644
--- a/rust/tvm-ffi/src/collections/tensor.rs
+++ b/rust/tvm-ffi/src/collections/tensor.rs
@@ -694,36 +694,26 @@ impl<'a> From<&TensorView<'a>> for AnyView<'a> {
}
// Passed to a function as a `DLTensor*`.
-impl<'a> crate::function_internal::IntoArgHolder for TensorView<'a> {
- type Target = TensorView<'a>;
- fn into_arg_holder(self) -> Self::Target {
+impl<'a> crate::function_internal::PackedCallArg for TensorView<'a> {
+ type Holder = Self;
+ #[inline(always)]
+ fn into_packed_arg(self) -> Self {
self
}
-}
-
-impl<'a, 'b> crate::function_internal::IntoArgHolder for &'b TensorView<'a> {
- type Target = &'b TensorView<'a>;
- fn into_arg_holder(self) -> Self::Target {
- self
+ #[inline(always)]
+ fn as_packed_arg(holder: &Self::Holder) -> AnyView<'_> {
+ AnyView::from(holder)
}
}
-impl<'a> crate::function_internal::ArgIntoRef for TensorView<'a> {
- type Target = TensorView<'a>;
- fn to_ref(&self) -> &Self::Target {
+impl<'a, 'b> crate::function_internal::PackedCallArg for &'b TensorView<'a> {
+ type Holder = Self;
+ #[inline(always)]
+ fn into_packed_arg(self) -> Self {
self
}
-}
-
-impl<'a> crate::function_internal::ArgIntoRef for &TensorView<'a> {
- type Target = TensorView<'a>;
- fn to_ref(&self) -> &Self::Target {
- self
- }
-}
-
-impl crate::function_internal::PackedArg for TensorView<'_> {
- fn as_packed_arg(&self) -> AnyView<'_> {
- AnyView::from(self)
+ #[inline(always)]
+ fn as_packed_arg(holder: &Self::Holder) -> AnyView<'_> {
+ AnyView::from(*holder)
}
}
diff --git a/rust/tvm-ffi/src/extra/module.rs b/rust/tvm-ffi/src/extra/module.rs
index fbebcc88..adee30d0 100644
--- a/rust/tvm-ffi/src/extra/module.rs
+++ b/rust/tvm-ffi/src/extra/module.rs
@@ -60,7 +60,7 @@ impl Module {
pub fn load_from_file<Str: AsRef<str>>(file_name: Str) -> Result<Module> {
let file_name = crate::string::String::from(file_name);
crate::cached_global_func!("ffi.ModuleLoadFromFile")
- .call_tuple_with_len::<1, _>((file_name,))?
+ .call_tuple((file_name,))?
.try_into()
}
@@ -81,7 +81,7 @@ impl Module {
pub fn get_function<Str: AsRef<str>>(&self, name: Str) -> Result<Function>
{
let name = crate::string::String::from(name);
crate::cached_global_func!("ffi.ModuleGetFunction")
- .call_tuple_with_len::<3, _>((self, name, false))?
+ .call_tuple((self, name, false))?
.try_into()
}
@@ -90,7 +90,7 @@ impl Module {
pub fn get_function_with_imports<Str: AsRef<str>>(&self, name: Str) ->
Result<Function> {
let name = crate::string::String::from(name);
crate::cached_global_func!("ffi.ModuleGetFunction")
- .call_tuple_with_len::<3, _>((self, name, true))?
+ .call_tuple((self, name, true))?
.try_into()
}
@@ -106,7 +106,7 @@ impl Module {
pub fn implements_function<Str: AsRef<str>>(&self, name: Str) ->
Result<bool> {
let name = String::from(name);
crate::cached_global_func!("ffi.ModuleImplementsFunction")
- .call_tuple_with_len::<3, _>((self, name, false))?
+ .call_tuple((self, name, false))?
.try_into()
}
@@ -115,7 +115,7 @@ impl Module {
pub fn implements_function_with_imports<Str: AsRef<str>>(&self, name: Str)
-> Result<bool> {
let name = String::from(name);
crate::cached_global_func!("ffi.ModuleImplementsFunction")
- .call_tuple_with_len::<3, _>((self, name, true))?
+ .call_tuple((self, name, true))?
.try_into()
}
@@ -135,7 +135,7 @@ impl Module {
pub fn get_function_metadata<Str: AsRef<str>>(&self, name: Str) ->
Result<Option<String>> {
let name = String::from(name);
crate::cached_global_func!("ffi.ModuleGetFunctionMetadata")
- .call_tuple_with_len::<3, _>((self, name, false))?
+ .call_tuple((self, name, false))?
.try_into()
}
@@ -147,7 +147,7 @@ impl Module {
) -> Result<Option<String>> {
let name = String::from(name);
crate::cached_global_func!("ffi.ModuleGetFunctionMetadata")
- .call_tuple_with_len::<3, _>((self, name, true))?
+ .call_tuple((self, name, true))?
.try_into()
}
@@ -166,7 +166,7 @@ impl Module {
pub fn get_function_doc<Str: AsRef<str>>(&self, name: Str) ->
Result<Option<String>> {
let name = String::from(name);
crate::cached_global_func!("ffi.ModuleGetFunctionDoc")
- .call_tuple_with_len::<3, _>((self, name, false))?
+ .call_tuple((self, name, false))?
.try_into()
}
@@ -178,7 +178,7 @@ impl Module {
) -> Result<Option<String>> {
let name = String::from(name);
crate::cached_global_func!("ffi.ModuleGetFunctionDoc")
- .call_tuple_with_len::<3, _>((self, name, true))?
+ .call_tuple((self, name, true))?
.try_into()
}
}
diff --git a/rust/tvm-ffi/src/extra/unchanged.rs
b/rust/tvm-ffi/src/extra/unchanged.rs
index 4a0c8182..bff097a2 100644
--- a/rust/tvm-ffi/src/extra/unchanged.rs
+++ b/rust/tvm-ffi/src/extra/unchanged.rs
@@ -322,6 +322,8 @@ impl<T: ContainerElement> Clone for UnchangedOr<T> {
}
}
+crate::impl_into_arg!(impl[T: ContainerElement] UnchangedOr<T>);
+
impl<'b, T: ContainerElement> TryFrom<&'b Any> for UnchangedOr<T> {
type Error = Error;
#[inline]
@@ -392,6 +394,7 @@ unsafe impl AnyCompatible for Unchanged {
}
crate::impl_try_from_any!(Unchanged);
+crate::impl_into_arg!(Unchanged);
// SAFETY: the carrier contains either the resource-free marker or exactly
// T's owning representation. Borrowing never acquires ownership; moving
diff --git a/rust/tvm-ffi/src/function.rs b/rust/tvm-ffi/src/function.rs
index 5f709ced..064a42a2 100644
--- a/rust/tvm-ffi/src/function.rs
+++ b/rust/tvm-ffi/src/function.rs
@@ -19,10 +19,12 @@
//! [`Function`], a callable shared with C++ and Python, and the global
function
//! registry.
+pub use crate::function_internal::{PackedCallArg, PackedCallArgs};
+
use crate::any::{Any, AnyView};
use crate::derive::{Object, ObjectRef};
use crate::error::{Error, Result};
-use crate::function_internal::{AsPackedCallable, TupleAsPackedArgs};
+use crate::function_internal::AsPackedCallable;
use crate::object::{Object, ObjectArc, ObjectCore};
use crate::type_traits::AnyCompatible;
use tvm_ffi_sys::{
@@ -194,7 +196,8 @@ impl Function {
/// Call the function with the arguments in the tuple `tuple_args`.
///
/// An element may be a value or a reference to one; a reference passes an
- /// object without retaining it.
+ /// object without retaining it, and a `&str` or `&[u8]` passes as a
+ /// `String` or `Bytes`.
///
/// # Arguments
///
@@ -209,63 +212,8 @@ impl Function {
/// Returns the error that the function raises.
///
/// See also [`Function`].
- pub fn call_tuple<TupleType>(&self, tuple_args: TupleType) -> Result<Any>
- where
- TupleType: TupleAsPackedArgs,
- {
- // This is a workaround for Rust's requirement that stack allocation
size
- // must be known at compile time for generic types.
- // While we know args_len is a constant, Rust doesn't allow us to
directly
- // declare [AnyView::new(); args_len] in generic contexts.
- //
- // We use a small vector optimization pattern:
- // 1. First allocate a small stack buffer (stack_args)
- // 2. If args_len exceeds STACK_LEN, allocate a heap buffer (heap_args)
- // 3. Use the appropriate buffer based on size
- //
- // Since args_len is a compile-time constant, the compiler should
optimize
- // away the unused branch, making this approach efficient.
- const STACK_LEN: usize = 4;
- let mut stack_args = [AnyView::new(); STACK_LEN];
- let mut heap_args = Vec::<AnyView>::new();
- let args_len = <TupleType as TupleAsPackedArgs>::LEN;
- // get packed arguments
- let packed_args: &mut [AnyView] = if args_len <= STACK_LEN {
- &mut stack_args[..args_len]
- } else {
- heap_args.resize(args_len, AnyView::new());
- &mut heap_args[..args_len]
- };
- tuple_args.fill_any_view(packed_args);
- self.call_packed(packed_args)
- }
- /// Call the function with the `LEN` arguments in `tuple_args`.
- ///
- /// This is [`call_tuple`](Self::call_tuple) for an argument count known at
- /// compile time, without its small-vector overhead.
- ///
- /// # Arguments
- ///
- /// * `tuple_args` - The `LEN` arguments, as a tuple.
- ///
- /// # Returns
- ///
- /// The function's result.
- ///
- /// # Errors
- ///
- /// Returns the error that the function raises.
- #[doc(hidden)]
- pub fn call_tuple_with_len<const LEN: usize, TupleType>(
- &self,
- tuple_args: TupleType,
- ) -> Result<Any>
- where
- TupleType: TupleAsPackedArgs,
- {
- let mut packed_args = [AnyView::new(); LEN];
- tuple_args.fill_any_view(&mut packed_args);
- self.call_packed(&packed_args)
+ pub fn call_tuple(&self, tuple_args: impl PackedCallArgs) -> Result<Any> {
+ tuple_args.with_packed_args(|packed_args|
self.call_packed(packed_args))
}
/// Look up the global function registered as `name`.
///
diff --git a/rust/tvm-ffi/src/function_internal.rs
b/rust/tvm-ffi/src/function_internal.rs
index b8fc801c..885a0a21 100644
--- a/rust/tvm-ffi/src/function_internal.rs
+++ b/rust/tvm-ffi/src/function_internal.rs
@@ -169,273 +169,88 @@ impl_as_packed_callable!(6; T0, T1, T2, T3, T4, T5);
impl_as_packed_callable!(7; T0, T1, T2, T3, T4, T5, T6);
impl_as_packed_callable!(8; T0, T1, T2, T3, T4, T5, T6, T7);
-//--------------------------------------------------------------
-// IntoArgHolder, helper to convert to canonical holding type
-//
-// This is needed sometimes for reference types that may need to
-// be converted to value types.
-//--------------------------------------------------------------
-pub trait IntoArgHolder {
- type Target;
- fn into_arg_holder(self) -> Self::Target;
+/// One argument of a packed call: held for the call, then viewed as an FFI
+/// value. `&str` and `&[u8]` are held as `String` and `Bytes`. Implemented by
+/// `#[derive(ObjectRef)]` and `impl_any_compatible_conversions!`.
+pub trait PackedCallArg {
+ /// What keeps the argument alive during the call.
+ type Holder;
+ fn into_packed_arg(self) -> Self::Holder;
+ fn as_packed_arg(holder: &Self::Holder) -> AnyView<'_>;
}
// `Any` itself is an argument; every other value type is listed in `any.rs`.
-crate::impl_into_arg_holder_default!(Any);
+crate::impl_into_packed_arg!(Any);
-// string will be converted to String for argument passing
-impl IntoArgHolder for &str {
- type Target = String;
- fn into_arg_holder(self) -> Self::Target {
- String::from(self)
- }
-}
-
-// string will be converted to String for argument passing
-impl IntoArgHolder for &[u8] {
- type Target = Bytes;
- fn into_arg_holder(self) -> Self::Target {
- Bytes::from(self)
- }
-}
-
-// helper trait to implement IntoArgHolderTuple to apply into_arg_holder to
each element
-pub trait IntoArgHolderTuple {
- type Target;
- fn into_arg_holder_tuple(self) -> Self::Target;
-}
-
-macro_rules! impl_into_arg_holder_tuple {
- ( $($T:ident),* ; $($idx:tt),* ) => {
- impl<$($T),*> $crate::function_internal::IntoArgHolderTuple for
($($T,)*)
- where
- $($T: IntoArgHolder),* {
- type Target = ($($T::Target,)*);
-
- fn into_arg_holder_tuple(self) -> Self::Target {
- ($(self.$idx.into_arg_holder(),)*)
- }
- }
- };
-}
-
-impl IntoArgHolderTuple for () {
- type Target = ();
- fn into_arg_holder_tuple(self) -> Self::Target {}
-}
-impl_into_arg_holder_tuple!(T0; 0);
-impl_into_arg_holder_tuple!(T0, T1; 0, 1);
-impl_into_arg_holder_tuple!(T0, T1, T2; 0, 1, 2);
-impl_into_arg_holder_tuple!(T0, T1, T2, T3; 0, 1, 2, 3);
-impl_into_arg_holder_tuple!(T0, T1, T2, T3, T4; 0, 1, 2, 3, 4);
-impl_into_arg_holder_tuple!(T0, T1, T2, T3, T4, T5; 0, 1, 2, 3, 4, 5);
-impl_into_arg_holder_tuple!(T0, T1, T2, T3, T4, T5, T6; 0, 1, 2, 3, 4, 5, 6);
-impl_into_arg_holder_tuple!(T0, T1, T2, T3, T4, T5, T6, T7; 0, 1, 2, 3, 4, 5,
6, 7);
-
-//------------------------------------------------------------
-// ArgIntoRef
-//
-// Helper to turn argument type to reference type
-// This is effectively AsRef<T> but removes the need of T
-//-----------------------------------------------------------
-pub trait ArgIntoRef {
- type Target;
- fn to_ref(&self) -> &Self::Target;
-}
-
-/// Convert a canonical argument holder into its packed ABI view.
-#[doc(hidden)]
-pub trait PackedArg {
- fn as_packed_arg(&self) -> AnyView<'_>;
-}
-
-impl<T: AnyCompatible> PackedArg for T {
+impl PackedCallArg for &str {
+ type Holder = String;
#[inline]
- fn as_packed_arg(&self) -> AnyView<'_> {
- AnyView::from(self)
+ fn into_packed_arg(self) -> String {
+ String::from(self)
}
-}
-
-impl PackedArg for Any {
- #[inline]
- fn as_packed_arg(&self) -> AnyView<'_> {
- AnyView::from(self)
+ #[inline(always)]
+ fn as_packed_arg(holder: &String) -> AnyView<'_> {
+ AnyView::from(holder)
}
}
-impl<T> PackedArg for RValueRef<T>
-where
- T: ObjectRefCore,
-{
+impl PackedCallArg for &[u8] {
+ type Holder = Bytes;
#[inline]
- fn as_packed_arg(&self) -> AnyView<'_> {
- AnyView::from(self)
- }
-}
-
-// `Any` itself is an argument; every other value type is listed in `any.rs`.
-crate::impl_arg_into_ref!(Any);
-
-// Generic holders require explicit implementations rather than scalar macro
entries.
-impl<T: AnyCompatible> IntoArgHolder for Option<T> {
- type Target = Self;
- fn into_arg_holder(self) -> Self::Target {
- self
- }
-}
-
-impl<'a, T: AnyCompatible> IntoArgHolder for &'a Option<T> {
- type Target = &'a Option<T>;
- fn into_arg_holder(self) -> Self::Target {
- self
- }
-}
-
-impl<T: AnyCompatible> ArgIntoRef for Option<T> {
- type Target = Self;
- fn to_ref(&self) -> &Self::Target {
- self
- }
-}
-
-impl<T: AnyCompatible> ArgIntoRef for &Option<T> {
- type Target = Option<T>;
- fn to_ref(&self) -> &Self::Target {
- self
- }
-}
-
-impl<T: ContainerElement + Clone> IntoArgHolder for crate::Array<T> {
- type Target = crate::Array<T>;
- fn into_arg_holder(self) -> Self::Target {
- self
- }
-}
-impl<'a, T: ContainerElement + Clone> IntoArgHolder for &'a crate::Array<T> {
- type Target = &'a crate::Array<T>;
- fn into_arg_holder(self) -> Self::Target {
- self
- }
-}
-impl<T: ContainerElement + Clone> ArgIntoRef for crate::Array<T> {
- type Target = crate::Array<T>;
- fn to_ref(&self) -> &Self::Target {
- self
- }
-}
-impl<T: ContainerElement + Clone> ArgIntoRef for &crate::Array<T> {
- type Target = crate::Array<T>;
- fn to_ref(&self) -> &Self::Target {
- self
- }
-}
-
-impl<T> IntoArgHolder for RValueRef<T>
-where
- T: ObjectRefCore,
-{
- type Target = Self;
- fn into_arg_holder(self) -> Self::Target {
- self
+ fn into_packed_arg(self) -> Bytes {
+ Bytes::from(self)
}
-}
-
-impl<T> ArgIntoRef for RValueRef<T>
-where
- T: ObjectRefCore,
-{
- type Target = Self;
- fn to_ref(&self) -> &Self::Target {
- self
+ #[inline(always)]
+ fn as_packed_arg(holder: &Bytes) -> AnyView<'_> {
+ AnyView::from(holder)
}
}
-impl<K: ContainerElement, V: ContainerElement> IntoArgHolder for crate::Map<K,
V> {
- type Target = crate::Map<K, V>;
- fn into_arg_holder(self) -> Self::Target {
- self
- }
-}
-impl<'a, K: ContainerElement, V: ContainerElement> IntoArgHolder for &'a
crate::Map<K, V> {
- type Target = &'a crate::Map<K, V>;
- fn into_arg_holder(self) -> Self::Target {
- self
- }
-}
-impl<K: ContainerElement, V: ContainerElement> ArgIntoRef for crate::Map<K, V>
{
- type Target = crate::Map<K, V>;
- fn to_ref(&self) -> &Self::Target {
+impl<T: ObjectRefCore> PackedCallArg for RValueRef<T> {
+ type Holder = Self;
+ #[inline(always)]
+ fn into_packed_arg(self) -> Self {
self
}
-}
-impl<K: ContainerElement, V: ContainerElement> ArgIntoRef for &crate::Map<K,
V> {
- type Target = crate::Map<K, V>;
- fn to_ref(&self) -> &Self::Target {
- self
+ #[inline(always)]
+ fn as_packed_arg(holder: &Self::Holder) -> AnyView<'_> {
+ AnyView::from(holder)
}
}
-impl<T: ContainerElement> IntoArgHolder for crate::List<T> {
- type Target = crate::List<T>;
- fn into_arg_holder(self) -> Self::Target {
- self
- }
-}
-impl<'a, T: ContainerElement> IntoArgHolder for &'a crate::List<T> {
- type Target = &'a crate::List<T>;
- fn into_arg_holder(self) -> Self::Target {
- self
- }
-}
-impl<T: ContainerElement> ArgIntoRef for crate::List<T> {
- type Target = crate::List<T>;
- fn to_ref(&self) -> &Self::Target {
- self
- }
-}
-impl<T: ContainerElement> ArgIntoRef for &crate::List<T> {
- type Target = crate::List<T>;
- fn to_ref(&self) -> &Self::Target {
- self
- }
-}
+// Generic types, which the per-type lists cannot name.
+crate::impl_into_packed_arg!(impl[T: AnyCompatible] Option<T>);
+crate::impl_into_packed_arg!(impl[T: ContainerElement + Clone]
crate::Array<T>);
+crate::impl_into_packed_arg!(impl[K: ContainerElement, V: ContainerElement]
crate::Map<K, V>);
+crate::impl_into_packed_arg!(impl[T: ContainerElement] crate::List<T>);
-//-----------------------------------------------------------
-// TupleAsPackedArgs
-//
-// Helper to turn tuple type to packed arguments
-//-----------------------------------------------------------
-pub trait TupleAsPackedArgs {
+/// The arguments of a packed call: a tuple of 0 to 8 [`PackedCallArg`] values.
+pub trait PackedCallArgs {
const LEN: usize;
- fn fill_any_view<'a>(&'a self, any_view: &mut [AnyView<'a>]);
+ /// Call `f` with the arguments as views, which live until `f` returns.
+ fn with_packed_args<R>(self, f: impl FnOnce(&[AnyView<'_>]) -> R) -> R;
}
-macro_rules! impl_tuple_as_packed_args {
- ( $len:expr; $($T:ident),* ; $($idx:tt),* ) => {
- impl<$($T),*> TupleAsPackedArgs for ($($T,)*)
- where
- $(
- $T: ArgIntoRef,
- $T::Target: PackedArg,
- )*
- {
+macro_rules! impl_into_packed_args {
+ ($len:literal; $($T:ident),*; $($idx:tt),*) => {
+ impl<$($T: PackedCallArg),*> PackedCallArgs for ($($T,)*) {
const LEN: usize = $len;
-
- fn fill_any_view<'a>(&'a self, _any_view: &mut [AnyView<'a>]) {
- $(
- _any_view[$idx] = self.$idx.to_ref().as_packed_arg();
- )*
+ #[inline(always)]
+ fn with_packed_args<R>(self, f: impl FnOnce(&[AnyView<'_>]) -> R)
-> R {
+ let _holders = ($(self.$idx.into_packed_arg(),)*);
+ let views: [AnyView<'_>; $len] =
[$($T::as_packed_arg(&_holders.$idx)),*];
+ f(&views)
}
}
};
}
-impl_tuple_as_packed_args!(0;;);
-impl_tuple_as_packed_args!(1; T0; 0);
-impl_tuple_as_packed_args!(2; T0, T1; 0, 1);
-impl_tuple_as_packed_args!(3; T0, T1, T2; 0, 1, 2);
-impl_tuple_as_packed_args!(4; T0, T1, T2, T3; 0, 1, 2, 3);
-impl_tuple_as_packed_args!(5; T0, T1, T2, T3, T4; 0, 1, 2, 3, 4);
-impl_tuple_as_packed_args!(6; T0, T1, T2, T3, T4, T5; 0, 1, 2, 3, 4, 5);
-impl_tuple_as_packed_args!(7; T0, T1, T2, T3, T4, T5, T6; 0, 1, 2, 3, 4, 5, 6);
-impl_tuple_as_packed_args!(8; T0, T1, T2, T3, T4, T5, T6, T7; 0, 1, 2, 3, 4,
5, 6, 7);
+impl_into_packed_args!(0;;);
+impl_into_packed_args!(1; T0; 0);
+impl_into_packed_args!(2; T0, T1; 0, 1);
+impl_into_packed_args!(3; T0, T1, T2; 0, 1, 2);
+impl_into_packed_args!(4; T0, T1, T2, T3; 0, 1, 2, 3);
+impl_into_packed_args!(5; T0, T1, T2, T3, T4; 0, 1, 2, 3, 4);
+impl_into_packed_args!(6; T0, T1, T2, T3, T4, T5; 0, 1, 2, 3, 4, 5);
+impl_into_packed_args!(7; T0, T1, T2, T3, T4, T5, T6; 0, 1, 2, 3, 4, 5, 6);
+impl_into_packed_args!(8; T0, T1, T2, T3, T4, T5, T6, T7; 0, 1, 2, 3, 4, 5, 6,
7);
diff --git a/rust/tvm-ffi/src/lib.rs b/rust/tvm-ffi/src/lib.rs
index 8dd0421a..41229d66 100644
--- a/rust/tvm-ffi/src/lib.rs
+++ b/rust/tvm-ffi/src/lib.rs
@@ -117,11 +117,11 @@ pub use crate::extra::structural_visit::{
pub use crate::extra::structural_walk::{structural_walk, IntoWalkResult,
WalkOrder, WalkResult};
pub use crate::extra::unchanged::{Unchanged, UnchangedOr};
pub use crate::function::Function;
-pub use crate::object::{IntoObjectRef, Object, ObjectArc, ObjectCore,
ObjectRef, ObjectRefCore};
+pub use crate::object::{Object, ObjectArc, ObjectCore, ObjectRef,
ObjectRefCore};
pub use crate::optional::Optional;
pub use crate::static_init::run_static_init_blocks;
pub use crate::string::{Bytes, String};
-pub use crate::type_traits::AnyCompatible;
+pub use crate::type_traits::{AnyCompatible, IntoArg};
/// Generate runtime type dispatch from the `prefix_*` methods of an impl.
///
/// `#[dispatch(prefix, (First, Args...), Ret)]` on an inherent impl makes its
@@ -260,7 +260,7 @@ pub use tvm_ffi_macros::match_any;
/// infers as it, and any other field as `impl Into<T>`. This is the
/// object-level allocator, which sees only tokens and so cannot tell an
/// object reference from a value; a constructor on the reference takes an
-/// object reference as [`impl IntoObjectRef<T>`](IntoObjectRef), as the
+/// object reference as [`impl IntoArg<T>`](IntoArg), as the
/// ones `tvm-ffi-stubgen` generates do.
///
/// # Arguments
diff --git a/rust/tvm-ffi/src/macros.rs b/rust/tvm-ffi/src/macros.rs
index 30fb5627..31ff2d91 100644
--- a/rust/tvm-ffi/src/macros.rs
+++ b/rust/tvm-ffi/src/macros.rs
@@ -232,7 +232,7 @@ macro_rules! attach_context {
/// its base object-reference types: `From<Source>` and `From<&Source>` into
/// `Target`, `AsRef<Target>`, which borrows a `&Source` as `&Target`
/// without touching the reference count, and
-/// [`IntoObjectRef<Target>`](crate::object::IntoObjectRef) for `Source` and
`&Source`,
+/// [`IntoArg<Target>`](crate::IntoArg) for `Source` and `&Source`,
/// and [`TypeSubsumes<Source>`](crate::type_traits::TypeSubsumes) for
`Target`, so
/// [`Array::upcast`](crate::Array::upcast) turns an `Array<Source>` into an
/// `Array<Target>`. It also implements the strict downcast back,
`TryFrom<Target>` and
@@ -290,20 +290,28 @@ macro_rules! impl_object_ref_upcast {
// `target`, and an object reference never changes its object.
unsafe impl $crate::type_traits::TypeSubsumes<$source> for $target
{}
- impl $crate::object::IntoObjectRef<$target> for $source {
+ impl $crate::IntoArg<$target> for $source {
type Output = $target;
#[inline(always)]
- fn into_object_ref(self) -> $target {
+ fn into_arg(self) -> $target {
+ ::core::convert::Into::into(self)
+ }
+ #[inline(always)]
+ fn into_owned(self) -> $target {
::core::convert::Into::into(self)
}
}
- impl<'a> $crate::object::IntoObjectRef<$target> for &'a $source {
+ impl<'a> $crate::IntoArg<$target> for &'a $source {
type Output = &'a $target;
#[inline(always)]
- fn into_object_ref(self) -> &'a $target {
+ fn into_arg(self) -> &'a $target {
::core::convert::AsRef::<$target>::as_ref(self)
}
+ #[inline(always)]
+ fn into_owned(self) -> $target {
+ ::core::convert::Into::into(self)
+ }
}
impl ::core::convert::AsRef<$target> for $source {
@@ -490,8 +498,8 @@ macro_rules! impl_object_ref_downcast_ref {
macro_rules! impl_any_compatible_conversions {
($($t:ty),* $(,)?) => {
$crate::impl_try_from_any!($($t),*);
- $crate::impl_arg_into_ref!($($t),*);
- $crate::impl_into_arg_holder_default!($($t),*);
+ $crate::impl_into_arg!($($t),*);
+ $crate::impl_into_packed_arg!($($t),*);
};
}
@@ -537,6 +545,40 @@ macro_rules! impl_try_from_any {
};
}
+/// `IntoArg<T>` for `T` and `&T`; part of
[`impl_any_compatible_conversions!`](crate::impl_any_compatible_conversions).
+#[doc(hidden)]
+#[macro_export]
+macro_rules! impl_into_arg {
+ ($($t:ty),* $(,)?) => {
+ $($crate::impl_into_arg!(impl[] $t);)*
+ };
+ (impl[$($g:tt)*] $t:ty) => {
+ impl<$($g)*> $crate::IntoArg<$t> for $t {
+ type Output = $t;
+ #[inline(always)]
+ fn into_arg(self) -> $t {
+ self
+ }
+ #[inline(always)]
+ fn into_owned(self) -> $t {
+ self
+ }
+ }
+
+ impl<'a, $($g)*> $crate::IntoArg<$t> for &'a $t {
+ type Output = &'a $t;
+ #[inline(always)]
+ fn into_arg(self) -> &'a $t {
+ self
+ }
+ #[inline(always)]
+ fn into_owned(self) -> $t {
+ ::core::clone::Clone::clone(self)
+ }
+ }
+ };
+}
+
/// Macro to implement `TryFrom<AnyView>` and `TryFrom<Any>` for generic types
like `Option<T>`
#[doc(hidden)]
#[macro_export]
@@ -582,48 +624,38 @@ macro_rules! impl_try_from_any_for_parametric {
};
}
-/// Typed-function arguments; part of
[`impl_any_compatible_conversions!`](crate::impl_any_compatible_conversions).
+/// Packed-call arguments; part of
[`impl_any_compatible_conversions!`](crate::impl_any_compatible_conversions).
#[doc(hidden)]
#[macro_export]
-macro_rules! impl_into_arg_holder_default {
- ($($t:ty),*) => {
- $(
- impl $crate::function_internal::IntoArgHolder for $t {
- type Target = $t;
- fn into_arg_holder(self) -> Self::Target {
- self
- }
+macro_rules! impl_into_packed_arg {
+ ($($t:ty),* $(,)?) => {
+ $($crate::impl_into_packed_arg!(impl[] $t);)*
+ };
+ (impl[$($g:tt)*] $t:ty) => {
+ impl<$($g)*> $crate::function_internal::PackedCallArg for $t {
+ type Holder = $t;
+ #[inline(always)]
+ fn into_packed_arg(self) -> $t {
+ self
}
- impl<'a> $crate::function_internal::IntoArgHolder for &'a $t {
- type Target = &'a $t;
- fn into_arg_holder(self) -> Self::Target {
- self
- }
+ #[inline(always)]
+ fn as_packed_arg(holder: &Self::Holder) ->
$crate::any::AnyView<'_> {
+ $crate::any::AnyView::from(holder)
}
- )*
- };
-}
+ }
-/// `call_tuple` arguments; part of
[`impl_any_compatible_conversions!`](crate::impl_any_compatible_conversions).
-#[doc(hidden)]
-#[macro_export]
-macro_rules! impl_arg_into_ref {
- ($($t:ty),*) => {
- $(
- impl $crate::function_internal::ArgIntoRef for $t {
- type Target = $t;
- fn to_ref(&self) -> &Self::Target {
- &self
- }
+ impl<'a, $($g)*> $crate::function_internal::PackedCallArg for &'a $t {
+ type Holder = &'a $t;
+ #[inline(always)]
+ fn into_packed_arg(self) -> &'a $t {
+ self
}
- impl<'a> $crate::function_internal::ArgIntoRef for &'a $t {
- type Target = $t;
- fn to_ref(&self) -> &Self::Target {
- &self
- }
+ #[inline(always)]
+ fn as_packed_arg(holder: &Self::Holder) ->
$crate::any::AnyView<'_> {
+ $crate::any::AnyView::from(*holder)
}
- )*
- }
+ }
+ };
}
// ----------------------------------------------------------------------------
@@ -821,7 +853,7 @@ macro_rules! into_typed_fn {
($f:expr, $trait:ident() -> $ret_ty:ty) => {{
let _f = $f;
move || -> $ret_ty {
- ::core::convert::TryInto::try_into(_f.call_tuple_with_len::<0,
_>(())?)
+ ::core::convert::TryInto::try_into(_f.call_tuple(())?)
.map_err(::core::convert::Into::into)
}
}};
@@ -829,9 +861,7 @@ macro_rules! into_typed_fn {
($f:expr, $trait:ident($t0:ty) -> $ret_ty:ty) => {{
let _f = $f;
move |a0: $t0| -> $ret_ty {
- use $crate::function_internal::IntoArgHolderTuple;
- let tuple_args = (a0,).into_arg_holder_tuple();
- ::core::convert::TryInto::try_into(_f.call_tuple_with_len::<1,
_>(tuple_args)?)
+ ::core::convert::TryInto::try_into(_f.call_tuple((a0,))?)
.map_err(::core::convert::Into::into)
}
}};
@@ -839,9 +869,7 @@ macro_rules! into_typed_fn {
($f:expr, $trait:ident($t0:ty, $t1:ty) -> $ret_ty:ty) => {{
let _f = $f;
move |a0: $t0, a1: $t1| -> $ret_ty {
- use $crate::function_internal::IntoArgHolderTuple;
- let tuple_args = (a0, a1).into_arg_holder_tuple();
- ::core::convert::TryInto::try_into(_f.call_tuple_with_len::<2,
_>(tuple_args)?)
+ ::core::convert::TryInto::try_into(_f.call_tuple((a0, a1))?)
.map_err(::core::convert::Into::into)
}
}};
@@ -849,9 +877,7 @@ macro_rules! into_typed_fn {
($f:expr, $trait:ident($t0:ty, $t1:ty, $t2:ty) -> $ret_ty:ty) => {{
let _f = $f;
move |a0: $t0, a1: $t1, a2: $t2| -> $ret_ty {
- use $crate::function_internal::IntoArgHolderTuple;
- let tuple_args = (a0, a1, a2).into_arg_holder_tuple();
- ::core::convert::TryInto::try_into(_f.call_tuple_with_len::<3,
_>(tuple_args)?)
+ ::core::convert::TryInto::try_into(_f.call_tuple((a0, a1, a2))?)
.map_err(::core::convert::Into::into)
}
}};
@@ -859,9 +885,7 @@ macro_rules! into_typed_fn {
($f:expr, $trait:ident($t0:ty, $t1:ty, $t2:ty, $t3:ty) -> $ret_ty:ty) => {{
let _f = $f;
move |a0: $t0, a1: $t1, a2: $t2, a3: $t3| -> $ret_ty {
- use $crate::function_internal::IntoArgHolderTuple;
- let tuple_args = (a0, a1, a2, a3).into_arg_holder_tuple();
- ::core::convert::TryInto::try_into(_f.call_tuple_with_len::<4,
_>(tuple_args)?)
+ ::core::convert::TryInto::try_into(_f.call_tuple((a0, a1, a2,
a3))?)
.map_err(::core::convert::Into::into)
}
}};
@@ -869,9 +893,7 @@ macro_rules! into_typed_fn {
($f:expr, $trait:ident($t0:ty, $t1:ty, $t2:ty, $t3:ty, $t4:ty) ->
$ret_ty:ty) => {{
let _f = $f;
move |a0: $t0, a1: $t1, a2: $t2, a3: $t3, a4: $t4| -> $ret_ty {
- use $crate::function_internal::IntoArgHolderTuple;
- let tuple_args = (a0, a1, a2, a3, a4).into_arg_holder_tuple();
- ::core::convert::TryInto::try_into(_f.call_tuple_with_len::<5,
_>(tuple_args)?)
+ ::core::convert::TryInto::try_into(_f.call_tuple((a0, a1, a2, a3,
a4))?)
.map_err(::core::convert::Into::into)
}
}};
@@ -879,9 +901,7 @@ macro_rules! into_typed_fn {
($f:expr, $trait:ident($t0:ty, $t1:ty, $t2:ty, $t3:ty, $t4:ty, $t5:ty) ->
$ret_ty:ty) => {{
let _f = $f;
move |a0: $t0, a1: $t1, a2: $t2, a3: $t3, a4: $t4, a5: $t5| -> $ret_ty
{
- use $crate::function_internal::IntoArgHolderTuple;
- let tuple_args = (a0, a1, a2, a3, a4, a5).into_arg_holder_tuple();
- ::core::convert::TryInto::try_into(_f.call_tuple_with_len::<6,
_>(tuple_args)?)
+ ::core::convert::TryInto::try_into(_f.call_tuple((a0, a1, a2, a3,
a4, a5))?)
.map_err(::core::convert::Into::into)
}
}};
@@ -890,9 +910,7 @@ macro_rules! into_typed_fn {
-> $ret_ty:ty) => {{
let _f = $f;
move |a0: $t0, a1: $t1, a2: $t2, a3: $t3, a4: $t4, a5: $t5, a6: $t6|
-> $ret_ty {
- use $crate::function_internal::IntoArgHolderTuple;
- let tuple_args = (a0, a1, a2, a3, a4, a5,
a6).into_arg_holder_tuple();
- ::core::convert::TryInto::try_into(_f.call_tuple_with_len::<7,
_>(tuple_args)?)
+ ::core::convert::TryInto::try_into(_f.call_tuple((a0, a1, a2, a3,
a4, a5, a6))?)
.map_err(::core::convert::Into::into)
}
}};
@@ -901,9 +919,7 @@ macro_rules! into_typed_fn {
-> $ret_ty:ty) => {{
let _f = $f;
move |a0: $t0, a1: $t1, a2: $t2, a3: $t3, a4: $t4, a5: $t5, a6: $t6,
a7: $t7| -> $ret_ty {
- use $crate::function_internal::IntoArgHolderTuple;
- let tuple_args = (a0, a1, a2, a3, a4, a5, a6,
a7).into_arg_holder_tuple();
- ::core::convert::TryInto::try_into(_f.call_tuple_with_len::<8,
_>(tuple_args)?)
+ ::core::convert::TryInto::try_into(_f.call_tuple((a0, a1, a2, a3,
a4, a5, a6, a7))?)
.map_err(::core::convert::Into::into)
}
}};
diff --git a/rust/tvm-ffi/src/object.rs b/rust/tvm-ffi/src/object.rs
index a937e6f3..c9d4a3ff 100644
--- a/rust/tvm-ffi/src/object.rs
+++ b/rust/tvm-ffi/src/object.rs
@@ -792,78 +792,6 @@ unsafe impl<T: ObjectRefAnyCompatible> AnyCompatible for T
{
}
}
-/// A value that converts into the object reference `T`, owned or borrowed.
-///
-/// An owned reference converts into an owned `T`, and a borrowed one borrows
-/// as `&T` without changing a reference count, as [`IntoIterator`] consumes a
-/// `Vec` but borrows from a `&Vec`.
[`impl_object_ref_upcast!`](crate::impl_object_ref_upcast)
-/// implements it for each derived reference and its reference into the base,
-/// and `#[derive(ObjectRef)]` for the type itself. A function that only reads
-/// the value borrows the output with `.borrow()`; one that keeps it takes
-/// ownership with [`into_owned_object_ref`](Self::into_owned_object_ref),
which clones only a
-/// borrowed reference.
-///
-/// # Examples
-///
-/// ```
-/// use std::borrow::Borrow;
-/// use tvm_ffi::derive::ObjectRef;
-/// use tvm_ffi::object::{IntoObjectRef, ObjectRef, ObjectRefCore};
-/// use tvm_ffi::{rs_object, Object, ObjectArc};
-///
-/// #[rs_object("my_ext.MyPair", final)]
-/// pub struct MyPairObj {
-/// base_: Object,
-/// pub first: i64,
-/// pub second: i64,
-/// }
-///
-/// #[derive(Clone, ObjectRef)]
-/// pub struct MyPair {
-/// data: ObjectArc<MyPairObj>,
-/// }
-///
-/// fn same(a: impl IntoObjectRef<ObjectRef>, b: &ObjectRef) -> bool {
-/// a.into_object_ref().borrow().same_as(b)
-/// }
-///
-/// let pair = MyPair::from_object(MyPairObj::new(Object::new(), 1, 2));
-/// let base: ObjectRef = pair.clone().into();
-/// assert!(same(&pair, &base)); // borrowed as `&ObjectRef`, no new reference
-/// assert!(same(pair.clone(), &base)); // moved into an `ObjectRef`
-///
-/// // A function that keeps the value takes ownership.
-/// fn keep(value: impl IntoObjectRef<ObjectRef>) -> ObjectRef {
-/// value.into_owned_object_ref()
-/// }
-/// assert!(keep(&pair).same_as(&base));
-/// ```
-pub trait IntoObjectRef<T> {
- /// `T` for an owned value, or `&T` for a borrowed one.
- type Output: std::borrow::Borrow<T> + Into<T>;
-
- /// Convert into the reference `T`.
- ///
- /// # Returns
- ///
- /// The owned or borrowed reference.
- fn into_object_ref(self) -> Self::Output;
-
- /// Convert into an owned `T`, as
[`Cow::into_owned`](std::borrow::Cow::into_owned)
- /// does: an owned value moves, and only a borrowed reference is cloned.
- ///
- /// # Returns
- ///
- /// The owned reference.
- #[inline(always)]
- fn into_owned_object_ref(self) -> T
- where
- Self: Sized,
- {
- self.into_object_ref().into()
- }
-}
-
/// An owning, hashable identity key for an FFI object.
///
/// The retained strong reference prevents the allocation address from being
diff --git a/rust/tvm-ffi/src/optional.rs b/rust/tvm-ffi/src/optional.rs
index 250ed0eb..d17208df 100644
--- a/rust/tvm-ffi/src/optional.rs
+++ b/rust/tvm-ffi/src/optional.rs
@@ -250,6 +250,8 @@ unsafe impl<T: OptionalCompatible> AnyCompatible for
Optional<T> {
}
}
+crate::impl_into_arg!(impl[T: OptionalCompatible] Optional<T>);
+
impl<T: OptionalCompatible> Default for Optional<T> {
/// The empty optional, holding `None`.
#[inline]
diff --git a/rust/tvm-ffi/src/type_traits.rs b/rust/tvm-ffi/src/type_traits.rs
index adef17ea..ad7fef78 100644
--- a/rust/tvm-ffi/src/type_traits.rs
+++ b/rust/tvm-ffi/src/type_traits.rs
@@ -16,28 +16,34 @@
* specific language governing permissions and limitations
* under the License.
*/
-//! [`AnyCompatible`], how a Rust type converts to and from FFI values.
+//! Traits that map Rust types to TVM-FFI values.
use crate::any::{Any, AnyView};
+use std::borrow::Borrow;
use tvm_ffi_sys::TVMFFITypeIndex as TypeIndex;
use tvm_ffi_sys::{TVMFFIAny, TVMFFIGetTypeInfo, TVMFFIObject};
-//-----------------------------------------------------
-// AnyCompatible
-//-----------------------------------------------------
-/// A type that an [`Any`] can hold: how its values are stored in, and read
-/// from, a `TVMFFIAny` cell.
+/// A type whose values an FFI cell can hold: how a value is stored in a
+/// `TVMFFIAny` and read back.
+///
+/// [`AnyView`] and [`TensorView`](crate::TensorView) borrow their value, so
+/// they are not. Containers and generic code bound on [`ContainerElement`] to
+/// also accept [`Any`].
+///
+/// # Implementing
///
-/// `#[derive(ObjectRef)]` implements it for object references; other types
-/// implement it by hand.
+/// Object references derive it with `#[derive(ObjectRef)]`. Any other type
+/// implements it by hand, then calls
+///
[`impl_any_compatible_conversions!`](crate::impl_any_compatible_conversions),
+/// which adds its `From`, `TryFrom` and argument conversions. Coherence keeps
+/// those out of this trait, so without the macro the type is stored but not
+/// converted.
///
/// # Safety
-/// Implementations must encode and decode `TVMFFIAny` cells in the layout of
-/// their FFI type index, and every `*_after_check` function must be sound for
-/// each cell that `check_any_strict` accepts.
[`is_undefined`](Self::is_undefined)
-/// returns false for every value, and true for all-zero bytes unless they are
-/// a value whose drop does nothing: reflection drops and reads a field it
-/// does not report undefined.
+/// - A value is written in the cell layout of its type index, and read back
from it.
+/// - Every `*_after_check` method is sound on each cell that
`check_any_strict` accepts.
+/// - `is_undefined` is false for every value. It is true for all-zero bytes,
+/// unless those bytes are a value whose drop does nothing.
pub unsafe trait AnyCompatible: Sized {
/// Whether the `AnyView -> Self` conversion matches one exact leaf type.
///
@@ -173,97 +179,20 @@ pub unsafe trait AnyCompatible: Sized {
}
}
-/// The type key of the runtime type index `type_index`.
-pub(crate) fn runtime_type_key(type_index: i32) -> String {
- unsafe {
- let info = TVMFFIGetTypeInfo(type_index);
- assert!(!info.is_null(), "TVMFFIGetTypeInfo returned null");
- (*info).type_key.as_str().to_string()
- }
-}
-
-/// Writes a type schema, `{"type":"<origin>"}` or, with type arguments,
-/// `{"type":"<origin>","args":[...]}`.
-pub(crate) fn type_schema(origin: &str, args: &[String]) -> String {
- if args.is_empty() {
- format!(r#"{{"type":"{origin}"}}"#)
- } else {
- format!(r#"{{"type":"{origin}","args":[{}]}}"#, args.join(","))
- }
-}
-
-/// The metadata recorded for a function or field of type schema
-/// `type_schema`: `{"type_schema":<type_schema as a JSON string>}`.
-pub(crate) fn type_schema_metadata(type_schema: &str) -> String {
- format!(r#"{{"type_schema":{}}}"#, escape_string_json(type_schema))
-}
-
-/// `text` as a JSON string literal, escaped so that the metadata matches the
-/// C++ runtime's byte for byte.
-fn escape_string_json(text: &str) -> String {
- let mut out = String::with_capacity(text.len() + 2);
- out.push('"');
- for ch in text.chars() {
- match ch {
- '"' => out.push_str("\\\""),
- '\\' => out.push_str("\\\\"),
- '/' => out.push_str("\\/"),
- '\u{8}' => out.push_str("\\b"),
- '\u{c}' => out.push_str("\\f"),
- '\n' => out.push_str("\\n"),
- '\r' => out.push_str("\\r"),
- '\t' => out.push_str("\\t"),
- ch if (ch as u32) < 0x20 || ch == '\u{7f}' => {
- out.push_str(&format!("\\u{:04x}", ch as u32))
- }
- ch => out.push(ch),
- }
- }
- out.push('"');
- out
-}
-
-/// The type schema of a function parameter or return type.
-///
-/// This is [`AnyCompatible::type_schema`] for a type that converts through
-/// [`Any`], and `{"type":"Any"}` for `Any` and `AnyView` themselves.
-pub(crate) trait TypeSchema {
- fn type_schema() -> String;
-}
-
-impl<T: AnyCompatible> TypeSchema for T {
- fn type_schema() -> String {
- <T as AnyCompatible>::type_schema()
- }
-}
-
-impl TypeSchema for Any {
- fn type_schema() -> String {
- type_schema("Any", &[])
- }
-}
-
-impl TypeSchema for AnyView<'_> {
- fn type_schema() -> String {
- type_schema("Any", &[])
- }
-}
-
-/// A value an FFI container such as [`Array`](crate::Array) or
-/// [`Map`](crate::Map) holds: every [`AnyCompatible`] type, and [`Any`].
+/// A value an FFI container such as [`Array`](crate::Array) holds: every
+/// [`AnyCompatible`] type, and [`Any`].
///
-/// Use it as the bound of code generic over container elements, as
-/// `Array<T: ContainerElement>` is. The trait is sealed: implement
-/// [`AnyCompatible`] instead, and the type is an element.
+/// Sealed: implement [`AnyCompatible`] to make a type an element.
pub trait ContainerElement: container_element_ops::Ops {}
impl<T: AnyCompatible> ContainerElement for T {}
impl ContainerElement for Any {}
-/// Every `Source` value is a valid `Self` as stored, so a container of
-/// `Source` is a container of `Self` without a copy, as C++
-/// `type_subsumes_v<Self, Source>`. [`Array::upcast`](crate::Array::upcast)
-/// and [`Map::upcast`](crate::Map::upcast) use it.
+/// `Self` subsumes `Source`: every `Source` value, as stored, is a valid
+/// `Self`, a compile-time fact checked by no code, as C++
+/// `type_subsumes_v<Self, Source>`. So a container of `Source` is a container
+/// of `Self` without a copy, as [`Array::upcast`](crate::Array::upcast) and
+/// [`Map::upcast`](crate::Map::upcast) use.
///
/// It holds for every type and itself, and for a base object reference and
/// each derived one, which
[`impl_object_ref_upcast!`](crate::impl_object_ref_upcast)
@@ -277,6 +206,48 @@ pub unsafe trait TypeSubsumes<Source: ?Sized> {}
unsafe impl<T: ?Sized> TypeSubsumes<T> for T {}
+/// A `T`, a `&T` or a subtype of `T`, taken where a `T` is expected; a `&str`
+/// or `&[u8]` converts into a `String` or `Bytes`.
+///
+/// [`into_arg`](Self::into_arg) returns a `T` or a `&T` without changing a
+/// reference count, but those two conversions allocate;
+/// [`into_owned`](Self::into_owned) moves an owned value and clones only a
+/// borrowed one, as [`Cow::into_owned`](std::borrow::Cow::into_owned).
+pub trait IntoArg<T> {
+ /// `T` when owned, `&T` when borrowed.
+ type Output: Borrow<T>;
+
+ /// Convert into a `T` or a `&T`.
+ fn into_arg(self) -> Self::Output;
+
+ /// Convert into an owned `T`, cloning only a borrowed value.
+ fn into_owned(self) -> T;
+}
+
+impl IntoArg<crate::String> for &str {
+ type Output = crate::String;
+ #[inline]
+ fn into_arg(self) -> crate::String {
+ crate::String::from(self)
+ }
+ #[inline]
+ fn into_owned(self) -> crate::String {
+ crate::String::from(self)
+ }
+}
+
+impl IntoArg<crate::string::Bytes> for &[u8] {
+ type Output = crate::string::Bytes;
+ #[inline]
+ fn into_arg(self) -> crate::string::Bytes {
+ crate::string::Bytes::from(self)
+ }
+ #[inline]
+ fn into_owned(self) -> crate::string::Bytes {
+ crate::string::Bytes::from(self)
+ }
+}
+
/// A type whose value an FFI cell stores in place, so `&Self` borrows from the
/// cell, as [`Array`](crate::Array) indexing does.
///
@@ -384,13 +355,6 @@ unsafe impl<T: crate::object::ObjectRefCore>
RefFromAnyUnchecked for Option<T> {
}
}
-unsafe impl<T: crate::object::ObjectRefCore> DowncastRefFromAny for Option<T> {
- #[inline(always)]
- unsafe fn downcast_ref_from_any(cell: &TVMFFIAny) -> Option<&Self> {
- downcast_ref_from_any_in_place::<Self>(cell)
- }
-}
-
/// A type that [`Any::downcast_ref`] and [`AnyView::downcast_ref`] borrow from
/// an FFI cell in place, without a reference count change: object types
/// (`ArrayObj`), managed references (`Array<T>`, `String`, any
@@ -398,7 +362,8 @@ unsafe impl<T: crate::object::ObjectRefCore>
DowncastRefFromAny for Option<T> {
/// reference and scalars such as `i64`.
///
/// Name it to bound a generic borrow, as in `fn get<T: DowncastRefFromAny>`.
-/// A reference that implements `ObjectRefCore` by hand implements it with
+/// Object types, derived references and containers implement it, not code by
+/// hand: a reference with a hand-written `ObjectRefCore` calls
/// [`impl_object_ref_downcast_ref!`](crate::impl_object_ref_downcast_ref).
///
/// # Safety
@@ -447,10 +412,59 @@ pub unsafe fn downcast_ref_from_any_in_place<T:
RefFromAnyUnchecked>(
}
}
+unsafe impl<T: crate::object::ObjectRefCore> DowncastRefFromAny for Option<T> {
+ #[inline(always)]
+ unsafe fn downcast_ref_from_any(cell: &TVMFFIAny) -> Option<&Self> {
+ downcast_ref_from_any_in_place::<Self>(cell)
+ }
+}
+
+macro_rules! impl_downcast_ref_from_any {
+ ($($t:ty),* $(,)?) => {
+ $(unsafe impl DowncastRefFromAny for $t {
+ #[inline(always)]
+ unsafe fn downcast_ref_from_any(cell: &TVMFFIAny) -> Option<&Self>
{
+ downcast_ref_from_any_in_place::<Self>(cell)
+ }
+ })*
+ };
+}
+
+// An `&Any` must own what it points at, as an `Any` does: a view's cell may
+// instead borrow a C string, byte array, `DLTensor` or rvalue slot, whose
+// `&Any` would clone into an owner of a borrowed resource. Those are refused;
+// an `Any` or container cell never holds them.
+unsafe impl DowncastRefFromAny for Any {
+ #[inline(always)]
+ unsafe fn downcast_ref_from_any(cell: &TVMFFIAny) -> Option<&Self> {
+ let index = cell.type_index;
+ let borrowed = index == TypeIndex::kTVMFFIRawStr as i32
+ || index == TypeIndex::kTVMFFIByteArrayPtr as i32
+ || index == TypeIndex::kTVMFFIDLTensorPtr as i32
+ || index == TypeIndex::kTVMFFIObjectRValueRef as i32;
+ if borrowed {
+ None
+ } else {
+ Some(Any::ref_from_any_unchecked(cell))
+ }
+ }
+}
+
+impl_downcast_ref_from_any!(
+ crate::String,
+ crate::string::Bytes,
+ i64,
+ f64,
+ crate::big_int::BigInt,
+ tvm_ffi_sys::dlpack::DLDataType,
+ tvm_ffi_sys::dlpack::DLDevice,
+);
+
/// A type that an object reference's [`ObjectRefCore::downcast_ref`] borrows
/// from the reference's object pointer: object types (`ArrayObj`), and managed
/// references that are exactly one object pointer (`Array<T>`, every
-/// `#[derive(ObjectRef)]` type).
+/// `#[derive(ObjectRef)]` type). Object types, derived references and
+/// containers implement it, not code by hand.
///
/// [`ObjectRefCore::downcast_ref`]: crate::object::ObjectRefCore::downcast_ref
///
@@ -532,249 +546,143 @@ pub unsafe fn downcast_ref_from_object_in_place<T:
RefFromAnyUnchecked>(
}
}
-macro_rules! impl_downcast_ref_from_any {
- ($($t:ty),* $(,)?) => {
- $(unsafe impl DowncastRefFromAny for $t {
- #[inline(always)]
- unsafe fn downcast_ref_from_any(cell: &TVMFFIAny) -> Option<&Self>
{
- downcast_ref_from_any_in_place::<Self>(cell)
- }
- })*
- };
-}
-
-// An `&Any` must own what it points at, as an `Any` does: a view's cell may
-// instead borrow a C string, byte array, `DLTensor` or rvalue slot, whose
-// `&Any` would clone into an owner of a borrowed resource. Those are refused;
-// an `Any` or container cell never holds them.
-unsafe impl DowncastRefFromAny for Any {
- #[inline(always)]
- unsafe fn downcast_ref_from_any(cell: &TVMFFIAny) -> Option<&Self> {
- let index = cell.type_index;
- let borrowed = index == TypeIndex::kTVMFFIRawStr as i32
- || index == TypeIndex::kTVMFFIByteArrayPtr as i32
- || index == TypeIndex::kTVMFFIDLTensorPtr as i32
- || index == TypeIndex::kTVMFFIObjectRValueRef as i32;
- if borrowed {
- None
- } else {
- Some(Any::ref_from_any_unchecked(cell))
- }
+//-----------------------------------------------------
+// AnyCompatible impls
+//-----------------------------------------------------
+unsafe impl AnyCompatible for bool {
+ unsafe fn copy_to_any_view(src: &Self, data: &mut TVMFFIAny) {
+ data.type_index = TypeIndex::kTVMFFIBool as i32;
+ data.small_str_len = 0;
+ data.data_union.v_int64 = *src as i64;
+ }
+ unsafe fn check_any_strict(data: &TVMFFIAny) -> bool {
+ data.type_index == TypeIndex::kTVMFFIBool as i32
}
-}
-
-impl_downcast_ref_from_any!(
- crate::String,
- crate::string::Bytes,
- i64,
- f64,
- crate::big_int::BigInt,
- tvm_ffi_sys::dlpack::DLDataType,
- tvm_ffi_sys::dlpack::DLDevice,
-);
-mod container_element_ops {
- use super::{Any, AnyCompatible, AnyView, TVMFFIAny};
+ unsafe fn copy_from_any_view_after_check(data: &TVMFFIAny) -> Self {
+ data.data_union.v_int64 != 0
+ }
- pub trait Ops: Sized {
- const CONTAINER_IS_ANY: bool = false;
+ unsafe fn move_to_any(src: Self, data: &mut TVMFFIAny) {
+ data.type_index = TypeIndex::kTVMFFIBool as i32;
+ data.small_str_len = 0;
+ data.data_union.v_int64 = src as i64;
+ }
- unsafe fn container_copy_to_any_view(src: &Self, data: &mut TVMFFIAny);
- unsafe fn container_move_to_any(src: Self, data: &mut TVMFFIAny);
- unsafe fn container_check_any_strict(data: &TVMFFIAny) -> bool;
- unsafe fn container_match_constraints(data: &TVMFFIAny) -> bool;
- unsafe fn container_copy_from_any_view_after_check(data: &TVMFFIAny)
-> Self;
- unsafe fn container_move_from_any_after_check(data: &mut TVMFFIAny) ->
Self;
- unsafe fn container_try_cast_from_any_view(data: &TVMFFIAny) ->
Result<Self, ()>;
- fn container_get_mismatch_type_info(data: &TVMFFIAny) -> String;
- fn container_type_str() -> String;
- fn container_type_schema() -> String;
+ unsafe fn move_from_any_after_check(data: &mut TVMFFIAny) -> Self {
+ data.data_union.v_int64 != 0
}
- impl<T: AnyCompatible> Ops for T {
- #[inline]
- unsafe fn container_copy_to_any_view(src: &Self, data: &mut TVMFFIAny)
{
- <T as AnyCompatible>::copy_to_any_view(src, data)
+ unsafe fn try_cast_from_any_view(data: &TVMFFIAny) -> Result<Self, ()> {
+ if data.type_index == TypeIndex::kTVMFFIBool as i32
+ || data.type_index == TypeIndex::kTVMFFIInt as i32
+ {
+ unsafe { Ok(data.data_union.v_int64 != 0) }
+ } else {
+ Err(())
}
+ }
- #[inline]
- unsafe fn container_move_to_any(src: Self, data: &mut TVMFFIAny) {
- <T as AnyCompatible>::move_to_any(src, data)
- }
+ fn type_str() -> String {
+ "bool".to_string()
+ }
+}
- #[inline]
- unsafe fn container_check_any_strict(data: &TVMFFIAny) -> bool {
- <T as AnyCompatible>::check_any_strict(data)
- }
- #[inline]
- unsafe fn container_match_constraints(data: &TVMFFIAny) -> bool {
- <T as AnyCompatible>::match_constraints(data)
- }
+macro_rules! impl_any_compatible_for_int {
+ ($($int_type:ty),* $(,)?) => {
+ $(
+ unsafe impl AnyCompatible for $int_type {
+ fn type_str() -> String {
+ "int".to_string()
+ }
- #[inline]
- unsafe fn container_copy_from_any_view_after_check(data: &TVMFFIAny)
-> Self {
- <T as AnyCompatible>::copy_from_any_view_after_check(data)
- }
-
- #[inline]
- unsafe fn container_move_from_any_after_check(data: &mut TVMFFIAny) ->
Self {
- <T as AnyCompatible>::move_from_any_after_check(data)
- }
-
- #[inline]
- unsafe fn container_try_cast_from_any_view(data: &TVMFFIAny) ->
Result<Self, ()> {
- <T as AnyCompatible>::try_cast_from_any_view(data)
- }
-
- #[inline]
- fn container_get_mismatch_type_info(data: &TVMFFIAny) -> String {
- <T as AnyCompatible>::get_mismatch_type_info(data)
- }
-
- #[inline]
- fn container_type_str() -> String {
- <T as AnyCompatible>::type_str()
- }
-
- #[inline]
- fn container_type_schema() -> String {
- <T as AnyCompatible>::type_schema()
- }
- }
-
- impl Ops for Any {
- const CONTAINER_IS_ANY: bool = true;
-
- #[inline]
- unsafe fn container_copy_to_any_view(src: &Self, data: &mut TVMFFIAny)
{
- *data = *src.as_raw_ffi_any();
- }
-
- #[inline]
- unsafe fn container_move_to_any(src: Self, data: &mut TVMFFIAny) {
- *data = Any::into_raw_ffi_any(src);
- }
-
- #[inline]
- unsafe fn container_check_any_strict(_data: &TVMFFIAny) -> bool {
- true
- }
- #[inline]
- unsafe fn container_match_constraints(_data: &TVMFFIAny) -> bool {
- true
- }
+ unsafe fn copy_to_any_view(src: &Self, data: &mut TVMFFIAny) {
+ data.type_index = TypeIndex::kTVMFFIInt as i32;
+ data.small_str_len = 0;
+ data.data_union.v_int64 = *src as i64;
+ }
- #[inline]
- unsafe fn container_copy_from_any_view_after_check(data: &TVMFFIAny)
-> Self {
- Any::from(AnyView::from_raw_ffi_any(*data))
- }
+ unsafe fn check_any_strict(data: &TVMFFIAny) -> bool {
+ data.type_index == TypeIndex::kTVMFFIInt as i32
+ }
- #[inline]
- unsafe fn container_move_from_any_after_check(data: &mut TVMFFIAny) ->
Self {
- Any::from_raw_ffi_any(std::mem::replace(data, TVMFFIAny::new()))
- }
+ unsafe fn match_constraints(data: &TVMFFIAny) -> bool {
+ <$int_type>::try_from(data.data_union.v_int64).is_ok()
+ }
- #[inline]
- unsafe fn container_try_cast_from_any_view(data: &TVMFFIAny) ->
Result<Self, ()> {
- Ok(Any::from(AnyView::from_raw_ffi_any(*data)))
- }
+ unsafe fn copy_from_any_view_after_check(data: &TVMFFIAny) ->
Self {
+ data.data_union.v_int64 as $int_type
+ }
- #[inline]
- fn container_get_mismatch_type_info(_data: &TVMFFIAny) -> String {
- "Any".to_string()
- }
+ unsafe fn move_to_any(src: Self, data: &mut TVMFFIAny) {
+ data.type_index = TypeIndex::kTVMFFIInt as i32;
+ data.small_str_len = 0;
+ data.data_union.v_int64 = src as i64;
+ }
- #[inline]
- fn container_type_str() -> String {
- "Any".to_string()
- }
+ unsafe fn move_from_any_after_check(data: &mut TVMFFIAny) ->
Self {
+ data.data_union.v_int64 as $int_type
+ }
- #[inline]
- fn container_type_schema() -> String {
- <Any as super::TypeSchema>::type_schema()
- }
- }
+ unsafe fn try_cast_from_any_view(data: &TVMFFIAny) ->
Result<Self, ()> {
+ if data.type_index == TypeIndex::kTVMFFIInt as i32 ||
+ data.type_index == TypeIndex::kTVMFFIBool as i32 {
+ Ok(data.data_union.v_int64 as $int_type)
+ } else {
+ Err(())
+ }
+ }
+ }
+ )*
+ };
}
-unsafe impl AnyCompatible for bool {
- unsafe fn copy_to_any_view(src: &Self, data: &mut TVMFFIAny) {
- data.type_index = TypeIndex::kTVMFFIBool as i32;
- data.small_str_len = 0;
- data.data_union.v_int64 = *src as i64;
- }
- unsafe fn check_any_strict(data: &TVMFFIAny) -> bool {
- data.type_index == TypeIndex::kTVMFFIBool as i32
- }
-
- unsafe fn copy_from_any_view_after_check(data: &TVMFFIAny) -> Self {
- data.data_union.v_int64 != 0
- }
-
- unsafe fn move_to_any(src: Self, data: &mut TVMFFIAny) {
- data.type_index = TypeIndex::kTVMFFIBool as i32;
- data.small_str_len = 0;
- data.data_union.v_int64 = src as i64;
- }
-
- unsafe fn move_from_any_after_check(data: &mut TVMFFIAny) -> Self {
- data.data_union.v_int64 != 0
- }
-
- unsafe fn try_cast_from_any_view(data: &TVMFFIAny) -> Result<Self, ()> {
- if data.type_index == TypeIndex::kTVMFFIBool as i32
- || data.type_index == TypeIndex::kTVMFFIInt as i32
- {
- unsafe { Ok(data.data_union.v_int64 != 0) }
- } else {
- Err(())
- }
- }
-
- fn type_str() -> String {
- "bool".to_string()
- }
-}
+// Implement AnyCompatible for all integer types
+impl_any_compatible_for_int!(i8, i16, i32, i64, isize, u8, u16, u32, u64,
usize);
-macro_rules! impl_any_compatible_for_int {
- ($($int_type:ty),* $(,)?) => {
+macro_rules! impl_any_compatible_for_float {
+ ($($float_type:ty),* $(,)?) => {
$(
- unsafe impl AnyCompatible for $int_type {
+ unsafe impl AnyCompatible for $float_type {
fn type_str() -> String {
- "int".to_string()
+ "float".to_string()
}
unsafe fn copy_to_any_view(src: &Self, data: &mut TVMFFIAny) {
- data.type_index = TypeIndex::kTVMFFIInt as i32;
+ data.type_index = TypeIndex::kTVMFFIFloat as i32;
data.small_str_len = 0;
- data.data_union.v_int64 = *src as i64;
+ data.data_union.v_float64 = *src as f64;
}
unsafe fn check_any_strict(data: &TVMFFIAny) -> bool {
- data.type_index == TypeIndex::kTVMFFIInt as i32
+ data.type_index == TypeIndex::kTVMFFIFloat as i32
}
unsafe fn match_constraints(data: &TVMFFIAny) -> bool {
- <$int_type>::try_from(data.data_union.v_int64).is_ok()
+ let value = data.data_union.v_float64;
+ ((value as $float_type) as f64).to_bits() ==
value.to_bits()
}
unsafe fn copy_from_any_view_after_check(data: &TVMFFIAny) ->
Self {
- data.data_union.v_int64 as $int_type
+ data.data_union.v_float64 as $float_type
}
unsafe fn move_to_any(src: Self, data: &mut TVMFFIAny) {
- data.type_index = TypeIndex::kTVMFFIInt as i32;
+ data.type_index = TypeIndex::kTVMFFIFloat as i32;
data.small_str_len = 0;
- data.data_union.v_int64 = src as i64;
+ data.data_union.v_float64 = src as f64;
}
unsafe fn move_from_any_after_check(data: &mut TVMFFIAny) ->
Self {
- data.data_union.v_int64 as $int_type
+ data.data_union.v_float64 as $float_type
}
unsafe fn try_cast_from_any_view(data: &TVMFFIAny) ->
Result<Self, ()> {
- if data.type_index == TypeIndex::kTVMFFIInt as i32 ||
+ if data.type_index == TypeIndex::kTVMFFIFloat as i32 {
+ Ok(data.data_union.v_float64 as $float_type)
+ } else if data.type_index == TypeIndex::kTVMFFIInt as i32
||
data.type_index == TypeIndex::kTVMFFIBool as i32 {
- Ok(data.data_union.v_int64 as $int_type)
+ Ok(data.data_union.v_int64 as $float_type)
} else {
Err(())
}
@@ -784,8 +692,8 @@ macro_rules! impl_any_compatible_for_int {
};
}
-// Implement AnyCompatible for all integer types
-impl_any_compatible_for_int!(i8, i16, i32, i64, isize, u8, u16, u32, u64,
usize);
+// Implement AnyCompatible for all float types
+impl_any_compatible_for_float!(f32, f64);
// Implement AnyCompatible for `Option<T>`
unsafe impl<T: AnyCompatible> AnyCompatible for Option<T> {
@@ -869,6 +777,45 @@ unsafe impl<T: AnyCompatible> AnyCompatible for Option<T> {
}
}
+// Special rule: we convert () to None
+// This allows us to effectively pass () around as null value
+// note that this is indeed a bit relaxation of the type
+// but it is necessary for us to enable void/none interoperability
+unsafe impl AnyCompatible for () {
+ fn type_str() -> String {
+ // make it consistent with c++ representation
+ "None".to_string()
+ }
+
+ unsafe fn copy_to_any_view(_src: &Self, data: &mut TVMFFIAny) {
+ data.type_index = TypeIndex::kTVMFFINone as i32;
+ data.small_str_len = 0;
+ data.data_union.v_int64 = 0;
+ }
+
+ unsafe fn move_to_any(_src: Self, data: &mut TVMFFIAny) {
+ data.type_index = TypeIndex::kTVMFFINone as i32;
+ data.small_str_len = 0;
+ data.data_union.v_int64 = 0;
+ }
+
+ unsafe fn check_any_strict(data: &TVMFFIAny) -> bool {
+ data.type_index == TypeIndex::kTVMFFINone as i32
+ }
+
+ unsafe fn copy_from_any_view_after_check(_data: &TVMFFIAny) -> Self {}
+
+ unsafe fn move_from_any_after_check(_data: &mut TVMFFIAny) -> Self {}
+
+ unsafe fn try_cast_from_any_view(data: &TVMFFIAny) -> Result<Self, ()> {
+ if data.type_index == TypeIndex::kTVMFFINone as i32 {
+ Ok(())
+ } else {
+ Err(())
+ }
+ }
+}
+
unsafe impl AnyCompatible for *mut core::ffi::c_void {
unsafe fn copy_to_any_view(src: &Self, data: &mut TVMFFIAny) {
data.type_index = TypeIndex::kTVMFFIOpaquePtr as i32;
@@ -908,96 +855,201 @@ unsafe impl AnyCompatible for *mut core::ffi::c_void {
}
}
-macro_rules! impl_any_compatible_for_float {
- ($($float_type:ty),* $(,)?) => {
- $(
- unsafe impl AnyCompatible for $float_type {
- fn type_str() -> String {
- "float".to_string()
- }
+mod container_element_ops {
+ use super::{Any, AnyCompatible, AnyView, TVMFFIAny};
- unsafe fn copy_to_any_view(src: &Self, data: &mut TVMFFIAny) {
- data.type_index = TypeIndex::kTVMFFIFloat as i32;
- data.small_str_len = 0;
- data.data_union.v_float64 = *src as f64;
- }
+ pub trait Ops: Sized {
+ const CONTAINER_IS_ANY: bool = false;
- unsafe fn check_any_strict(data: &TVMFFIAny) -> bool {
- data.type_index == TypeIndex::kTVMFFIFloat as i32
- }
+ unsafe fn container_copy_to_any_view(src: &Self, data: &mut TVMFFIAny);
+ unsafe fn container_move_to_any(src: Self, data: &mut TVMFFIAny);
+ unsafe fn container_check_any_strict(data: &TVMFFIAny) -> bool;
+ unsafe fn container_match_constraints(data: &TVMFFIAny) -> bool;
+ unsafe fn container_copy_from_any_view_after_check(data: &TVMFFIAny)
-> Self;
+ unsafe fn container_move_from_any_after_check(data: &mut TVMFFIAny) ->
Self;
+ unsafe fn container_try_cast_from_any_view(data: &TVMFFIAny) ->
Result<Self, ()>;
+ fn container_get_mismatch_type_info(data: &TVMFFIAny) -> String;
+ fn container_type_str() -> String;
+ fn container_type_schema() -> String;
+ }
- unsafe fn match_constraints(data: &TVMFFIAny) -> bool {
- let value = data.data_union.v_float64;
- ((value as $float_type) as f64).to_bits() ==
value.to_bits()
- }
+ impl<T: AnyCompatible> Ops for T {
+ #[inline(always)]
+ unsafe fn container_copy_to_any_view(src: &Self, data: &mut TVMFFIAny)
{
+ <T as AnyCompatible>::copy_to_any_view(src, data)
+ }
- unsafe fn copy_from_any_view_after_check(data: &TVMFFIAny) ->
Self {
- data.data_union.v_float64 as $float_type
- }
+ #[inline(always)]
+ unsafe fn container_move_to_any(src: Self, data: &mut TVMFFIAny) {
+ <T as AnyCompatible>::move_to_any(src, data)
+ }
- unsafe fn move_to_any(src: Self, data: &mut TVMFFIAny) {
- data.type_index = TypeIndex::kTVMFFIFloat as i32;
- data.small_str_len = 0;
- data.data_union.v_float64 = src as f64;
- }
+ #[inline(always)]
+ unsafe fn container_check_any_strict(data: &TVMFFIAny) -> bool {
+ <T as AnyCompatible>::check_any_strict(data)
+ }
+ #[inline(always)]
+ unsafe fn container_match_constraints(data: &TVMFFIAny) -> bool {
+ <T as AnyCompatible>::match_constraints(data)
+ }
- unsafe fn move_from_any_after_check(data: &mut TVMFFIAny) ->
Self {
- data.data_union.v_float64 as $float_type
- }
+ #[inline(always)]
+ unsafe fn container_copy_from_any_view_after_check(data: &TVMFFIAny)
-> Self {
+ <T as AnyCompatible>::copy_from_any_view_after_check(data)
+ }
- unsafe fn try_cast_from_any_view(data: &TVMFFIAny) ->
Result<Self, ()> {
- if data.type_index == TypeIndex::kTVMFFIFloat as i32 {
- Ok(data.data_union.v_float64 as $float_type)
- } else if data.type_index == TypeIndex::kTVMFFIInt as i32
||
- data.type_index == TypeIndex::kTVMFFIBool as i32 {
- Ok(data.data_union.v_int64 as $float_type)
- } else {
- Err(())
- }
- }
- }
- )*
- };
-}
+ #[inline(always)]
+ unsafe fn container_move_from_any_after_check(data: &mut TVMFFIAny) ->
Self {
+ <T as AnyCompatible>::move_from_any_after_check(data)
+ }
-// Implement AnyCompatible for all float types
-impl_any_compatible_for_float!(f32, f64);
+ #[inline(always)]
+ unsafe fn container_try_cast_from_any_view(data: &TVMFFIAny) ->
Result<Self, ()> {
+ <T as AnyCompatible>::try_cast_from_any_view(data)
+ }
-// Special rule: we convert () to None
-// This allows us to effectively pass () around as null value
-// note that this is indeed a bit relaxation of the type
-// but it is necessary for us to enable void/none interoperability
-unsafe impl AnyCompatible for () {
- fn type_str() -> String {
- // make it consistent with c++ representation
- "None".to_string()
- }
+ #[inline(always)]
+ fn container_get_mismatch_type_info(data: &TVMFFIAny) -> String {
+ <T as AnyCompatible>::get_mismatch_type_info(data)
+ }
- unsafe fn copy_to_any_view(_src: &Self, data: &mut TVMFFIAny) {
- data.type_index = TypeIndex::kTVMFFINone as i32;
- data.small_str_len = 0;
- data.data_union.v_int64 = 0;
+ #[inline(always)]
+ fn container_type_str() -> String {
+ <T as AnyCompatible>::type_str()
+ }
+
+ #[inline(always)]
+ fn container_type_schema() -> String {
+ <T as AnyCompatible>::type_schema()
+ }
}
- unsafe fn move_to_any(_src: Self, data: &mut TVMFFIAny) {
- data.type_index = TypeIndex::kTVMFFINone as i32;
- data.small_str_len = 0;
- data.data_union.v_int64 = 0;
+ impl Ops for Any {
+ const CONTAINER_IS_ANY: bool = true;
+
+ #[inline(always)]
+ unsafe fn container_copy_to_any_view(src: &Self, data: &mut TVMFFIAny)
{
+ *data = *src.as_raw_ffi_any();
+ }
+
+ #[inline(always)]
+ unsafe fn container_move_to_any(src: Self, data: &mut TVMFFIAny) {
+ *data = Any::into_raw_ffi_any(src);
+ }
+
+ #[inline(always)]
+ unsafe fn container_check_any_strict(_data: &TVMFFIAny) -> bool {
+ true
+ }
+ #[inline(always)]
+ unsafe fn container_match_constraints(_data: &TVMFFIAny) -> bool {
+ true
+ }
+
+ #[inline(always)]
+ unsafe fn container_copy_from_any_view_after_check(data: &TVMFFIAny)
-> Self {
+ Any::from(AnyView::from_raw_ffi_any(*data))
+ }
+
+ #[inline(always)]
+ unsafe fn container_move_from_any_after_check(data: &mut TVMFFIAny) ->
Self {
+ Any::from_raw_ffi_any(std::mem::replace(data, TVMFFIAny::new()))
+ }
+
+ #[inline(always)]
+ unsafe fn container_try_cast_from_any_view(data: &TVMFFIAny) ->
Result<Self, ()> {
+ Ok(Any::from(AnyView::from_raw_ffi_any(*data)))
+ }
+
+ #[inline(always)]
+ fn container_get_mismatch_type_info(_data: &TVMFFIAny) -> String {
+ "Any".to_string()
+ }
+
+ #[inline(always)]
+ fn container_type_str() -> String {
+ "Any".to_string()
+ }
+
+ #[inline(always)]
+ fn container_type_schema() -> String {
+ <Any as super::TypeSchema>::type_schema()
+ }
}
+}
- unsafe fn check_any_strict(data: &TVMFFIAny) -> bool {
- data.type_index == TypeIndex::kTVMFFINone as i32
+/// The type key of the runtime type index `type_index`.
+pub(crate) fn runtime_type_key(type_index: i32) -> String {
+ unsafe {
+ let info = TVMFFIGetTypeInfo(type_index);
+ assert!(!info.is_null(), "TVMFFIGetTypeInfo returned null");
+ (*info).type_key.as_str().to_string()
}
+}
- unsafe fn copy_from_any_view_after_check(_data: &TVMFFIAny) -> Self {}
+/// Writes a type schema, `{"type":"<origin>"}` or, with type arguments,
+/// `{"type":"<origin>","args":[...]}`.
+pub(crate) fn type_schema(origin: &str, args: &[String]) -> String {
+ if args.is_empty() {
+ format!(r#"{{"type":"{origin}"}}"#)
+ } else {
+ format!(r#"{{"type":"{origin}","args":[{}]}}"#, args.join(","))
+ }
+}
- unsafe fn move_from_any_after_check(_data: &mut TVMFFIAny) -> Self {}
+/// The metadata recorded for a function or field of type schema
+/// `type_schema`: `{"type_schema":<type_schema as a JSON string>}`.
+pub(crate) fn type_schema_metadata(type_schema: &str) -> String {
+ format!(r#"{{"type_schema":{}}}"#, escape_string_json(type_schema))
+}
- unsafe fn try_cast_from_any_view(data: &TVMFFIAny) -> Result<Self, ()> {
- if data.type_index == TypeIndex::kTVMFFINone as i32 {
- Ok(())
- } else {
- Err(())
+/// `text` as a JSON string literal, escaped so that the metadata matches the
+/// C++ runtime's byte for byte.
+fn escape_string_json(text: &str) -> String {
+ let mut out = String::with_capacity(text.len() + 2);
+ out.push('"');
+ for ch in text.chars() {
+ match ch {
+ '"' => out.push_str("\\\""),
+ '\\' => out.push_str("\\\\"),
+ '/' => out.push_str("\\/"),
+ '\u{8}' => out.push_str("\\b"),
+ '\u{c}' => out.push_str("\\f"),
+ '\n' => out.push_str("\\n"),
+ '\r' => out.push_str("\\r"),
+ '\t' => out.push_str("\\t"),
+ ch if (ch as u32) < 0x20 || ch == '\u{7f}' => {
+ out.push_str(&format!("\\u{:04x}", ch as u32))
+ }
+ ch => out.push(ch),
}
}
+ out.push('"');
+ out
+}
+
+/// The type schema of a function parameter or return type.
+///
+/// This is [`AnyCompatible::type_schema`] for a type that converts through
+/// [`Any`], and `{"type":"Any"}` for `Any` and `AnyView` themselves.
+pub(crate) trait TypeSchema {
+ fn type_schema() -> String;
+}
+
+impl<T: AnyCompatible> TypeSchema for T {
+ fn type_schema() -> String {
+ <T as AnyCompatible>::type_schema()
+ }
+}
+
+impl TypeSchema for Any {
+ fn type_schema() -> String {
+ type_schema("Any", &[])
+ }
+}
+
+impl TypeSchema for AnyView<'_> {
+ fn type_schema() -> String {
+ type_schema("Any", &[])
+ }
}
diff --git a/rust/tvm-ffi/tests/test_big_int.rs
b/rust/tvm-ffi/tests/test_big_int.rs
index c5c1ae8a..e782cbe6 100644
--- a/rust/tvm-ffi/tests/test_big_int.rs
+++ b/rust/tvm-ffi/tests/test_big_int.rs
@@ -484,7 +484,7 @@ fn test_big_int_containers() {
assert!(map.contains_key(value).unwrap());
assert_eq!(map.get(value).unwrap(), Some(i as i64));
}
- assert_eq!(map.get(&BigInt::from(1u128 << 64)).unwrap(), None);
+ assert_eq!(map.get(BigInt::from(1u128 << 64)).unwrap(), None);
}
#[test]
diff --git a/rust/tvm-ffi/tests/test_function.rs
b/rust/tvm-ffi/tests/test_function.rs
index 42d453c2..e47c5277 100644
--- a/rust/tvm-ffi/tests/test_function.rs
+++ b/rust/tvm-ffi/tests/test_function.rs
@@ -85,7 +85,7 @@ fn test_function_call_tuple() {
let result = sum1.call_tuple((1,)).unwrap();
assert_eq!(i32::try_from(result).unwrap(), 1 + offset);
// test pass by reference
- let result = sum1.call_tuple_with_len::<1, _>((&1,)).unwrap();
+ let result = sum1.call_tuple((&1,)).unwrap();
assert_eq!(i32::try_from(result).unwrap(), 1 + offset);
let typed_fn = |x: &i32| -> Result<i32> {
sum1.call_tuple((x,))?.try_into() };
let result = typed_fn(&1);
diff --git a/rust/tvm-ffi/tests/test_function_metadata.rs
b/rust/tvm-ffi/tests/test_function_metadata.rs
index e45863e4..753bc986 100644
--- a/rust/tvm-ffi/tests/test_function_metadata.rs
+++ b/rust/tvm-ffi/tests/test_function_metadata.rs
@@ -53,7 +53,7 @@ fn global_metadata(name: &str) -> String {
assert_eq!(unsafe { tvm_ffi_sys::TVMFFITestingDummyTarget() }, 0);
Function::get_global("ffi.GetGlobalFuncMetadata")
.unwrap()
- .call_tuple_with_len::<1, _>((String::from(name),))
+ .call_tuple((String::from(name),))
.unwrap()
.try_into()
.unwrap()
@@ -137,7 +137,7 @@ fn test_exports_without_metadata() {
// SAFETY: rust_add takes two arguments and does not use the handle.
let add =
unsafe { Function::from_extern_c(std::ptr::null_mut(),
__tvm_ffi_rust_add, None).unwrap() };
- let sum = add.call_tuple_with_len::<2, _>((1i64, 2i64)).unwrap();
+ let sum = add.call_tuple((1i64, 2i64)).unwrap();
assert_eq!(i64::try_from(sum).unwrap(), 3);
without_export_metadata::__tvm_ffi__metadata_rust_schema_id_int();
without_export_metadata::__tvm_ffi__metadata_rust_packed();
@@ -287,6 +287,6 @@ fn test_global_untyped_metadata_matches_cpp() {
fn test_global_typed_registration_calls_the_function() {
register_globals();
let add = Function::get_global("testing.rust.add").unwrap();
- let sum = add.call_tuple_with_len::<2, _>((1i64, 2i64)).unwrap();
+ let sum = add.call_tuple((1i64, 2i64)).unwrap();
assert_eq!(i64::try_from(sum).unwrap(), 3);
}
diff --git a/rust/tvm-ffi/tests/test_map.rs b/rust/tvm-ffi/tests/test_map.rs
index 475e5f7c..7b51c0e0 100644
--- a/rust/tvm-ffi/tests/test_map.rs
+++ b/rust/tvm-ffi/tests/test_map.rs
@@ -45,13 +45,13 @@ fn test_map_basic_lookup() {
assert_eq!(map.len(), 3);
assert!(!map.is_empty());
- assert_eq!(map.get(&1).unwrap(), Some(10));
- assert_eq!(map.get(&2).unwrap(), Some(20));
- assert_eq!(map.get(&3).unwrap(), Some(30));
- assert_eq!(map.get(&99).unwrap(), None);
+ assert_eq!(map.get(1).unwrap(), Some(10));
+ assert_eq!(map.get(2).unwrap(), Some(20));
+ assert_eq!(map.get(3).unwrap(), Some(30));
+ assert_eq!(map.get(99).unwrap(), None);
- assert!(map.contains_key(&1).unwrap());
- assert!(!map.contains_key(&99).unwrap());
+ assert!(map.contains_key(1).unwrap());
+ assert!(!map.contains_key(99).unwrap());
}
#[test]
@@ -59,7 +59,7 @@ fn test_map_empty() {
let map: Map<i64, i64> = Map::new();
assert_eq!(map.len(), 0);
assert!(map.is_empty());
- assert_eq!(map.get(&1).unwrap(), None);
+ assert_eq!(map.get(1).unwrap(), None);
// All three iterators must handle the empty (remaining == 0) case.
assert_eq!(map.iter().count(), 0);
assert_eq!(map.keys().count(), 0);
@@ -72,8 +72,8 @@ fn test_map_empty() {
fn test_map_from_iter_duplicate_keys_last_wins() {
let map: Map<i64, i64> = [(1i64, 10i64), (1, 20), (2,
30)].into_iter().collect();
assert_eq!(map.len(), 2);
- assert_eq!(map.get(&1).unwrap(), Some(20));
- assert_eq!(map.get(&2).unwrap(), Some(30));
+ assert_eq!(map.get(1).unwrap(), Some(20));
+ assert_eq!(map.get(2).unwrap(), Some(30));
}
#[test]
@@ -109,10 +109,10 @@ fn test_map_string_keys() {
.collect();
assert_eq!(map.len(), 3);
- assert_eq!(map.get(&String::from("a")).unwrap(), Some(1));
- assert_eq!(map.get(&String::from("c")).unwrap(), Some(3));
- assert_eq!(map.get(&String::from("z")).unwrap(), None);
- assert!(map.contains_key(&String::from("b")).unwrap());
+ assert_eq!(map.get("a").unwrap(), Some(1));
+ assert_eq!(map.get("c").unwrap(), Some(3));
+ assert_eq!(map.get("z").unwrap(), None);
+ assert!(map.contains_key("b").unwrap());
}
#[test]
@@ -124,8 +124,8 @@ fn test_map_any_roundtrip() {
let back: Map<i64, i64> = Map::try_from(any).expect("Any -> Map failed");
assert_eq!(back.len(), 2);
- assert_eq!(back.get(&1).unwrap(), Some(10));
- assert_eq!(back.get(&2).unwrap(), Some(20));
+ assert_eq!(back.get(1).unwrap(), Some(10));
+ assert_eq!(back.get(2).unwrap(), Some(20));
}
#[test]
@@ -144,23 +144,22 @@ fn test_map_with_any_values() {
.collect();
assert_eq!(map.len(), 3);
- assert!(map.contains_key(&String::from("number")).unwrap());
- assert!(!map.contains_key(&String::from("missing")).unwrap());
+ assert!(map.contains_key("number").unwrap());
+ assert!(!map.contains_key("missing").unwrap());
assert_eq!(format!("{map:?}"), "Map<String, Any>[3]");
assert_eq!(AnyView::from(&array).debug_strong_count().unwrap(), 2);
assert_eq!(
-
i64::try_from(map.get(&String::from("number")).unwrap().unwrap()).unwrap(),
+ i64::try_from(map.get("number").unwrap().unwrap()).unwrap(),
7
);
assert_eq!(
- String::try_from(map.get(&String::from("text")).unwrap().unwrap())
+ String::try_from(map.get("text").unwrap().unwrap())
.unwrap()
.as_str(),
"value"
);
- let fetched_array =
-
Array::<i64>::try_from(map.get(&String::from("array")).unwrap().unwrap()).unwrap();
+ let fetched_array =
Array::<i64>::try_from(map.get("array").unwrap().unwrap()).unwrap();
assert_eq!(
fetched_array.iter().copied().collect::<Vec<_>>(),
vec![1, 2, 3]
@@ -229,7 +228,7 @@ fn test_map_shares_underlying_object() {
// Cloning shares the same underlying MapObj rather than copying entries.
let clone = map.clone();
assert_eq!(clone.len(), 1);
- assert_eq!(clone.get(&1).unwrap(), Some(10));
+ assert_eq!(clone.get(1).unwrap(), Some(10));
}
#[test]
@@ -245,10 +244,7 @@ fn test_map_object_values_and_refcount() {
assert_eq!(AnyView::from(&t).debug_strong_count().unwrap(), base + 1);
// The value round-trips correctly and `get` hands back a fresh handle.
- let got = map
- .get(&String::from("x"))
- .unwrap()
- .expect("key should be present");
+ let got = map.get("x").unwrap().expect("key should be present");
assert_eq!(get_val(&got), 7.0);
assert_eq!(got.ndim(), 2);
assert_eq!(AnyView::from(&t).debug_strong_count().unwrap(), base + 2);
@@ -274,7 +270,7 @@ fn test_map_object_values_and_refcount() {
fn test_map_as_function_argument() {
let map: Map<i64, i64> = [(1i64, 10i64), (2, 20), (3,
30)].into_iter().collect();
- // Exercises the `ArgIntoRef`/`call_tuple` path, by value and by reference.
+ // Exercises the `call_tuple` path, by value and by reference.
let map_size = Function::get_global("ffi.MapSize").unwrap();
let n_by_value: i64 = map_size
.call_tuple((map.clone(),))
@@ -303,12 +299,12 @@ fn test_map_get_missing_with_object_values() {
.into_iter()
.collect();
- let present = map.get(&String::from("x")).unwrap();
+ let present = map.get("x").unwrap();
assert!(present.is_some());
assert_eq!(get_val(&present.unwrap()), 7.0);
// Absent key returns `None`, never an object miscast as a tensor.
- assert!(map.get(&String::from("missing")).unwrap().is_none());
+ assert!(map.get("missing").unwrap().is_none());
}
/// Views a map behind an `Any` as `Map<K, V>` while bypassing the strict
@@ -334,7 +330,7 @@ fn mistyped_value_map() -> Map<i64, String> {
#[test]
fn test_map_get_type_mismatch_is_err() {
let map = mistyped_value_map();
- assert!(map.get(&1).is_err());
+ assert!(map.get(1).is_err());
}
/// Iterators panic on a value type mismatch rather than silently truncating
@@ -357,7 +353,7 @@ fn test_map_get_mistyped_key_debug_asserts() {
// keys do not match `K = String`.
let real: Map<i64, i64> = [(1i64, 10i64)].into_iter().collect();
let map: Map<String, i64> = view_map_unchecked(Any::from(real));
- let _ = map.get(&String::from("anything"));
+ let _ = map.get("anything");
}
/// `try_from` rejects a map whose values can neither strictly match nor cast
@@ -377,8 +373,8 @@ fn test_map_any_cast_slow_path_converts() {
let converted: Map<f64, f64> =
Map::try_from(Any::from(real.clone())).expect("i64 entries cast to
f64");
assert_eq!(converted.len(), 2);
- assert_eq!(converted.get(&1.0).unwrap(), Some(10.0));
- assert_eq!(converted.get(&2.0).unwrap(), Some(20.0));
+ assert_eq!(converted.get(1.0).unwrap(), Some(10.0));
+ assert_eq!(converted.get(2.0).unwrap(), Some(20.0));
// Each map owns its own object: nothing is shared between them.
assert_eq!(AnyView::from(&real).debug_strong_count(), Some(1));
assert_eq!(AnyView::from(&converted).debug_strong_count(), Some(1));
@@ -392,6 +388,6 @@ fn test_map_from_dict_copies() {
.unwrap();
let map = Map::<String, i64>::try_from(dict.clone()).unwrap();
assert_eq!(map.len(), 2);
- assert_eq!(map.get(&String::from("b")).unwrap(), Some(2));
+ assert_eq!(map.get("b").unwrap(), Some(2));
assert_eq!(dict.debug_strong_count(), Some(1));
}
diff --git a/rust/tvm-ffi/tests/test_match_any.rs
b/rust/tvm-ffi/tests/test_match_any.rs
index 8999cd80..96943f3d 100644
--- a/rust/tvm-ffi/tests/test_match_any.rs
+++ b/rust/tvm-ffi/tests/test_match_any.rs
@@ -307,7 +307,7 @@ fn type_alias_matcher_keeps_strict_compatibility() {
let module: Module = Function::get_global("ffi.SystemLib")
.unwrap()
- .call_tuple_with_len::<0, _>(())
+ .call_tuple(())
.unwrap()
.try_into()
.unwrap();
diff --git a/rust/tvm-ffi/tests/test_module.rs
b/rust/tvm-ffi/tests/test_module.rs
index 449be9ec..1096e17c 100644
--- a/rust/tvm-ffi/tests/test_module.rs
+++ b/rust/tvm-ffi/tests/test_module.rs
@@ -55,13 +55,13 @@ fn testing_module() -> Module {
fn importing_module() -> Module {
let module: Module = Function::get_global("ffi.SystemLib")
.unwrap()
- .call_tuple_with_len::<1,
_>((String::from("testing.rust.test_module."),))
+ .call_tuple((String::from("testing.rust.test_module."),))
.unwrap()
.try_into()
.unwrap();
Function::get_global("ffi.ModuleImportModule")
.unwrap()
- .call_tuple_with_len::<2, _>((&module, &testing_module()))
+ .call_tuple((&module, &testing_module()))
.unwrap();
module
}
diff --git a/rust/tvm-ffi/tests/test_rs_object.rs
b/rust/tvm-ffi/tests/test_rs_object.rs
index 9f68e23e..3bffb1e9 100644
--- a/rust/tvm-ffi/tests/test_rs_object.rs
+++ b/rust/tvm-ffi/tests/test_rs_object.rs
@@ -371,6 +371,22 @@ fn test_constructors_deref_and_upcast() {
assert!(ObjectRef::from(&root).same_as(&root));
}
+#[test]
+fn test_into_arg_into_owned_moves_or_clones() {
+ fn keep(value: impl IntoArg<ObjectRef>) -> ObjectRef {
+ value.into_owned()
+ }
+ let pair = point(1, "a");
+ let count = || AnyView::from(&pair).debug_strong_count().unwrap();
+ let base = count();
+ let cloned = keep(&pair);
+ assert!(cloned.same_as(&pair));
+ assert_eq!(count(), base + 1);
+ let moved = keep(pair.clone());
+ assert!(moved.same_as(&pair));
+ assert_eq!(count(), base + 2);
+}
+
#[test]
fn test_containers_upcast_without_a_copy() {
fn keep_array(value: impl Into<Array<RsPoint>>) -> Array<RsPoint> {
@@ -379,8 +395,8 @@ fn test_containers_upcast_without_a_copy() {
fn keep_map(value: impl Into<Map<tvm_ffi::String, RsPoint>>) ->
Map<tvm_ffi::String, RsPoint> {
value.into()
}
- fn len(value: impl IntoObjectRef<Array<RsPoint>>) -> usize {
- value.into_object_ref().borrow().len()
+ fn len(value: impl IntoArg<Array<RsPoint>>) -> usize {
+ value.into_arg().borrow().len()
}
let (a, b) = (point(1, "a"), point(2, "b"));
@@ -403,7 +419,7 @@ fn test_containers_upcast_without_a_copy() {
let map3: Map<tvm_ffi::String, RsPoint3> = [("p".into(), point3(1,
3))].into();
let upcast: Map<tvm_ffi::String, RsPoint> = map3.clone().upcast();
assert!(upcast.same_as(&map3));
- assert_eq!(upcast.get(&"p".into()).unwrap().unwrap().x, 1);
+ assert_eq!(upcast.get("p").unwrap().unwrap().x, 1);
let roots: &Map<tvm_ffi::String, ObjectRef> = map3.upcast_ref();
assert!(roots.same_as(&map3));
}
diff --git a/rust/tvm-ffi/tests/test_structural_mutate.rs
b/rust/tvm-ffi/tests/test_structural_mutate.rs
index 61b7ea95..ae84991e 100644
--- a/rust/tvm-ffi/tests/test_structural_mutate.rs
+++ b/rust/tvm-ffi/tests/test_structural_mutate.rs
@@ -358,7 +358,7 @@ fn
user_driven_mutator_controls_default_recursion_and_in_place_opt_in() {
.and_then(Map::<i64, i64>::try_from)
.unwrap();
assert_eq!(map_pointer(&mutated_map), source_map_pointer);
- assert_eq!(mutated_map.get(&1).unwrap(), Some(11));
+ assert_eq!(mutated_map.get(1).unwrap(), Some(11));
let dict = call_global("ffi.Dict", &[Any::from(1i64), Any::from(10i64)]);
let dict_pointer = any_object_pointer(&dict);
@@ -1295,7 +1295,7 @@ fn unique_map_reuses_nested_unique_value_storage() {
let mapped = structural_map(source, &mut IncrementIntegers,
WalkOrder::PostOrder)
.and_then(Map::<i64, Array<i64>>::try_from)
.unwrap();
- let mapped_child = mapped.get(&1).unwrap().unwrap();
+ let mapped_child = mapped.get(1).unwrap().unwrap();
assert_eq!(map_pointer(&mapped), source_pointer);
assert_eq!(array_pointer(&mapped_child), child_pointer);
@@ -1319,8 +1319,8 @@ fn shared_map_and_dict_copy_only_when_a_value_changes() {
.and_then(Map::<i64, i64>::try_from)
.unwrap();
assert_ne!(map_pointer(&mapped), source_pointer);
- assert_eq!(source.get(&1).unwrap(), Some(10));
- assert_eq!(mapped.get(&1).unwrap(), Some(11));
+ assert_eq!(source.get(1).unwrap(), Some(10));
+ assert_eq!(mapped.get(1).unwrap(), Some(11));
let dict = call_global("ffi.Dict", &[Any::from(1i64), Any::from(10i64)]);
let dict_pointer = any_object_pointer(&dict);
@@ -1353,8 +1353,8 @@ fn
shared_map_callback_error_preserves_source_and_reports_object_context() {
Err(error) => error,
};
- assert_eq!(source.get(&1).unwrap(), Some(10));
- assert_eq!(source.get(&2).unwrap(), Some(20));
+ assert_eq!(source.get(1).unwrap(), Some(10));
+ assert_eq!(source.get(2).unwrap(), Some(20));
assert_eq!(error.message(), "map mapper failed");
assert!(error.backtrace().contains("origin"));
assert!(error.backtrace().contains("object `ffi.Map`"));
@@ -1938,8 +1938,8 @@ fn map_keys_are_anchors_and_object_leaves_are_preserved()
{
.and_then(Map::<FfiString, i64>::try_from)
.unwrap();
assert_eq!(key_callbacks, 0);
- assert_eq!(mapped.get(&FfiString::from("a")).unwrap(), Some(2));
- assert_eq!(mapped.get(&FfiString::from("b")).unwrap(), Some(3));
+ assert_eq!(mapped.get(FfiString::from("a")).unwrap(), Some(2));
+ assert_eq!(mapped.get(FfiString::from("b")).unwrap(), Some(3));
let string = FfiString::from("leaf");
let heterogeneous = Function::get_global("ffi.Array")
diff --git a/tests/python/test_stubgen_rust.py
b/tests/python/test_stubgen_rust.py
index c42c1da6..edfbbecc 100644
--- a/tests/python/test_stubgen_rust.py
+++ b/tests/python/test_stubgen_rust.py
@@ -778,8 +778,8 @@ impl ExprObj {
impl Expr {
/// Lossless complete-field allocation.
- pub fn new(span: impl Into<Option<Span>>, ty: impl IntoObjectRef<Type>) ->
Self {
- let obj = ExprObj::new(span.into(), ty.into_owned_object_ref());
+ pub fn new(span: impl Into<Option<Span>>, ty: impl IntoArg<Type>) -> Self {
+ let obj = ExprObj::new(span.into(), ty.into_owned());
Self { data_: ObjectArc::new(obj) }
}
}"""
@@ -826,16 +826,11 @@ impl Add {
/// Lossless complete-field allocation.
pub fn new(
span: impl Into<Option<Span>>,
- ty: impl IntoObjectRef<PrimType>,
- a: impl IntoObjectRef<PrimExpr>,
- b: impl IntoObjectRef<PrimExpr>,
+ ty: impl IntoArg<PrimType>,
+ a: impl IntoArg<PrimExpr>,
+ b: impl IntoArg<PrimExpr>,
) -> Self {
- let obj = AddObj::new(
- span.into(),
- ty.into_owned_object_ref(),
- a.into_owned_object_ref(),
- b.into_owned_object_ref(),
- );
+ let obj = AddObj::new(span.into(), ty.into_owned(), a.into_owned(),
b.into_owned());
Self { data_: ObjectArc::new(obj) }
}
}
@@ -850,7 +845,7 @@ def test_render_complete_expr_golden() -> None:
RUST.add_directive(imports, "nullable", "ir.Expr.span", 1)
text, imports = _render(_expr(), imports)
assert text == EXPR_EXPECTED
- assert _uses(imports) == {"tvm_ffi::Object", "tvm_ffi::IntoObjectRef",
"tvm_ffi::ObjectArc"}
+ assert _uses(imports) == {"tvm_ffi::Object", "tvm_ffi::IntoArg",
"tvm_ffi::ObjectArc"}
def test_render_complete_add_golden() -> None:
@@ -871,7 +866,7 @@ def test_render_complete_add_golden() -> None:
assert text == ADD_EXPECTED
assert _uses(imports) == {
"std::ops::Deref",
- "tvm_ffi::IntoObjectRef",
+ "tvm_ffi::IntoArg",
"tvm_ffi::ObjectArc",
"crate::ir::ExprObj",
"crate::ir::Expr",
@@ -1192,25 +1187,20 @@ def test_custom_new_renames_the_wrapper_allocator() ->
None:
assert (
"impl Add {\n /// Lossless complete-field allocation.\n"
" pub fn from_fields(\n"
- " span: impl IntoObjectRef<Span>,\n"
- " ty: impl IntoObjectRef<Type>,\n"
- " a: impl IntoObjectRef<Expr>,\n"
- " b: impl IntoObjectRef<Expr>,\n"
+ " span: impl IntoArg<Span>,\n"
+ " ty: impl IntoArg<Type>,\n"
+ " a: impl IntoArg<Expr>,\n"
+ " b: impl IntoArg<Expr>,\n"
" ) -> Self {\n"
- " let obj = AddObj::new(\n"
- " span.into_owned_object_ref(),\n"
- " ty.into_owned_object_ref(),\n"
- " a.into_owned_object_ref(),\n"
- " b.into_owned_object_ref(),\n"
- " );\n"
+ " let obj = AddObj::new(span.into_owned(), ty.into_owned(),
a.into_owned(), b.into_owned());\n"
" Self { data_: ObjectArc::new(obj) }\n"
" }\n}"
) in text
assert " pub fn new(" not in text
-def test_wrapper_allocator_takes_object_references_as_into_object_ref() ->
None:
- """An object reference is `impl IntoObjectRef`, a value `impl Into`, a
scalar itself.
+def test_wrapper_allocator_takes_object_references_as_into_arg() -> None:
+ """An object reference is `impl IntoArg`, a value `impl Into`, a scalar
itself.
A `field` directive narrowing an object reference keeps it one; `nullable`
makes it an
`Option`, a value. `Shape` is a container, taken as `impl Into` like
`Array`.
@@ -1247,12 +1237,12 @@ def
test_wrapper_allocator_takes_object_references_as_into_object_ref() -> None:
text, imports = _render(info, imports)
assert (
" pub fn new(\n"
- " tensor: impl IntoObjectRef<Tensor>,\n"
- " owner: impl IntoObjectRef<ObjectRef>,\n"
- " callback: impl IntoObjectRef<Function>,\n"
- " module: impl IntoObjectRef<Module>,\n"
- " var: impl IntoObjectRef<Var>,\n"
- " buffer: impl IntoObjectRef<BufferVar>,\n"
+ " tensor: impl IntoArg<Tensor>,\n"
+ " owner: impl IntoArg<ObjectRef>,\n"
+ " callback: impl IntoArg<Function>,\n"
+ " module: impl IntoArg<Module>,\n"
+ " var: impl IntoArg<Var>,\n"
+ " buffer: impl IntoArg<BufferVar>,\n"
" span: impl Into<Option<Span>>,\n"
" name: impl Into<String>,\n"
" items: impl Into<Array<Any>>,\n"
@@ -1265,12 +1255,12 @@ def
test_wrapper_allocator_takes_object_references_as_into_object_ref() -> None:
" count: i32,\n"
" ) -> Self {\n"
" let obj = NodeObj::new(\n"
- " tensor.into_owned_object_ref(),\n"
- " owner.into_owned_object_ref(),\n"
- " callback.into_owned_object_ref(),\n"
- " module.into_owned_object_ref(),\n"
- " var.into_owned_object_ref(),\n"
- " buffer.into_owned_object_ref(),\n"
+ " tensor.into_owned(),\n"
+ " owner.into_owned(),\n"
+ " callback.into_owned(),\n"
+ " module.into_owned(),\n"
+ " var.into_owned(),\n"
+ " buffer.into_owned(),\n"
" span.into(),\n"
" name.into(),\n"
" items.into(),\n"
@@ -1283,10 +1273,10 @@ def
test_wrapper_allocator_takes_object_references_as_into_object_ref() -> None:
" count,\n"
" );\n"
) in text, text
- assert "tvm_ffi::IntoObjectRef" in _uses(imports)
+ assert "tvm_ffi::IntoArg" in _uses(imports)
-def
test_wrapper_allocator_without_object_references_does_not_import_into_object_ref()
-> None:
+def
test_wrapper_allocator_without_object_references_does_not_import_into_arg() ->
None:
info = _info(
"demo.Pair",
(_field("name", "str", 24, 16), _field("count", "int", 40, 8)),
@@ -1295,8 +1285,8 @@ def
test_wrapper_allocator_without_object_references_does_not_import_into_object
)
text, imports = _render(info)
assert " pub fn new(name: impl Into<String>, count: i64) -> Self {" in
text
- assert "IntoObjectRef" not in text
- assert "tvm_ffi::IntoObjectRef" not in _uses(imports)
+ assert "IntoArg" not in text
+ assert "tvm_ffi::IntoArg" not in _uses(imports)
def test_allocator_body_wraps_like_rustfmt() -> None: