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 25fda031 [Rust] Borrow object-reference upcasts through AsRef (#930)
25fda031 is described below
commit 25fda031d4f27a0076f065471802719baab4633b
Author: Tianqi Chen <[email protected]>
AuthorDate: Thu Nov 5 09:53:08 2026 -0500
[Rust] Borrow object-reference upcasts through AsRef (#930)
Lets a derived object reference borrow as its base without a
reference-count bump.
- `impl_object_upcast!(Source => Target)` now also implements
`AsRef<Target> for Source`. It views `&Source` as `&Target` in place:
both are one object pointer, and the declaration already promises that
every `Source` object is a valid `Target`. A compile-time assert keeps
the two layouts equal. Until now the only borrowed conversion was
`From<&Source>`, which clones.
- `#[derive(ObjectRef)]` implements `AsRef<Self>`, as `str`, `Path` and
`[T]` do, so an `impl AsRef<Base>` bound accepts `&Base` as well as each
derived reference.
APIs that only read a base reference can take `impl AsRef<Base>` and
accept every subtype for free. A bare `x.as_ref()` on a type with
several upcast targets needs a type annotation, as with `String`.
---
rust/tvm-ffi-macros/src/object_macros.rs | 9 +++++++++
rust/tvm-ffi/src/lib.rs | 4 +++-
rust/tvm-ffi/src/macros.rs | 20 +++++++++++++++++++-
3 files changed, 31 insertions(+), 2 deletions(-)
diff --git a/rust/tvm-ffi-macros/src/object_macros.rs
b/rust/tvm-ffi-macros/src/object_macros.rs
index 76cc3492..c62c6448 100644
--- a/rust/tvm-ffi-macros/src/object_macros.rs
+++ b/rust/tvm-ffi-macros/src/object_macros.rs
@@ -574,6 +574,15 @@ pub(crate) fn expand_object_ref(
}
}
+ // As `str`, `Path` and `[T]` do, so `impl AsRef<Base>` bounds accept
the
+ // base itself; upcasts add `AsRef` to each base.
+ impl ::core::convert::AsRef<#struct_name> for #struct_name {
+ #[inline(always)]
+ fn as_ref(&self) -> &Self {
+ self
+ }
+ }
+
impl ::std::convert::From<&#struct_name> for #struct_name {
#[inline]
fn from(value: &#struct_name) -> Self {
diff --git a/rust/tvm-ffi/src/lib.rs b/rust/tvm-ffi/src/lib.rs
index 8394fe52..d11c972f 100644
--- a/rust/tvm-ffi/src/lib.rs
+++ b/rust/tvm-ffi/src/lib.rs
@@ -273,7 +273,8 @@ pub use tvm_ffi_macros::rs_object;
/// before it go on the struct.
/// * `ParentType` - The reference to the parent's object, `ObjectRef` for a
/// type under `ffi.Object`. `TypeName` converts into it by
-/// `impl_object_upcast!`; a conversion into a further ancestor takes its own
+/// `impl_object_upcast!`, and `&TypeName` borrows as `&ParentType` through
+/// `AsRef`; a conversion into a further ancestor takes its own
/// `impl_object_upcast!`.
/// * `ObjectName` - The object type.
/// * `crate = path` - Optional, after `ObjectName`: where the generated code
@@ -296,6 +297,7 @@ pub use tvm_ffi_macros::rs_object;
///
/// let pair = MyPair::from(MyPairObj::new(Object::new(), 1, 2));
/// assert_eq!(pair.first + pair.second, 3);
+/// let _borrowed: &ObjectRef = pair.as_ref();
/// let _parent: ObjectRef = pair.into();
/// ```
pub use tvm_ffi_macros::def_object_ref;
diff --git a/rust/tvm-ffi/src/macros.rs b/rust/tvm-ffi/src/macros.rs
index 0c5d2ef6..cc371779 100644
--- a/rust/tvm-ffi/src/macros.rs
+++ b/rust/tvm-ffi/src/macros.rs
@@ -61,7 +61,9 @@ macro_rules! cached_global_func {
}
/// Implement zero-copy conversions from a derived object reference to one of
-/// its base object-reference types.
+/// its base object-reference types: `From<Source>` and `From<&Source>` into
+/// `Target`, and `AsRef<Target>`, which borrows a `&Source` as `&Target`
+/// without touching the reference count.
///
/// # Safety
///
@@ -101,6 +103,22 @@ macro_rules! impl_object_upcast {
}
}
+ impl ::core::convert::AsRef<$target> for $source {
+ #[inline(always)]
+ fn as_ref(&self) -> &$target {
+ const _: () = assert!(
+ ::core::mem::size_of::<$source>() ==
::core::mem::size_of::<$target>()
+ && ::core::mem::align_of::<$source>()
+ == ::core::mem::align_of::<$target>(),
+ "an object reference upcast must keep the reference's
layout"
+ );
+ // SAFETY: both references are exactly one object pointer,
and the
+ // macro declaration promises that every `source` object
is a valid
+ // `target`, so a `&source` is a valid `&target`.
+ unsafe { &*(self as *const $source as *const $target) }
+ }
+ }
+
)+
};
}