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) }
+                }
+            }
+
         )+
     };
 }

Reply via email to