Skip to main content

tvm_ffi/
object.rs

1/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements.  See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership.  The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License.  You may obtain a copy of the License at
9 *
10 *   http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied.  See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19use std::ops::{Deref, DerefMut};
20use std::sync::atomic::AtomicU64;
21
22use crate::derive::ObjectRef;
23use crate::type_traits::AnyCompatible;
24pub use tvm_ffi_sys::TVMFFITypeIndex as TypeIndex;
25/// Object related ABI handling
26use tvm_ffi_sys::{TVMFFIAny, TVMFFIGetTypeInfo, TVMFFIObject, COMBINED_REF_COUNT_BOTH_ONE};
27
28/// Object type is by default the TVMFFIObject
29#[repr(C)]
30pub struct Object {
31    /// example implementation of the object
32    header: TVMFFIObject,
33}
34
35/// Arc-like wrapper for Object that allows shared ownership
36///
37/// \tparam T The type of the object to be wrapped
38#[repr(C)]
39pub struct ObjectArc<T: ObjectCore> {
40    ptr: std::ptr::NonNull<T>,
41    _phantom: std::marker::PhantomData<T>,
42}
43
44unsafe impl<T: Send + Sync + ObjectCore> Send for ObjectArc<T> {}
45unsafe impl<T: Send + Sync + ObjectCore> Sync for ObjectArc<T> {}
46
47/// Traits that can be used to check if a type is an object
48///
49/// This trait is unsafe because it is used to access the object header
50/// and the object header is unsafe to access
51pub unsafe trait ObjectCore: Sized + 'static {
52    /// the type key of the object
53    const TYPE_KEY: &'static str;
54    /// Depth of this type in the object inheritance tree.
55    ///
56    /// The root [`Object`] has depth zero, and every registered subtype has
57    /// depth one greater than its parent. This value must be non-negative and
58    /// agree with the runtime type table entry for `Self`.
59    const TYPE_DEPTH: i32;
60    /// Whether every instance of this type has exactly `Self::type_index()`.
61    ///
62    /// A final type has no separately registered object-system subtype.
63    #[doc(hidden)]
64    const TYPE_FINAL: bool = false;
65    // return the type index of the object
66    fn type_index() -> i32;
67    /// Return the object header
68    /// This function is implemented as a static function so
69    ///
70    /// # Arguments
71    /// * `this` - The object to get the header
72    ///
73    /// # Returns
74    /// * `&mut TVMFFIObject` - The object header
75    /// \return The object header
76    unsafe fn object_header_mut(this: &mut Self) -> &mut TVMFFIObject;
77}
78
79/// Traits for objects with extra items that follows the object
80///
81/// This extra trait can be helpful to implement array types and string types
82pub unsafe trait ObjectCoreWithExtraItems: ObjectCore {
83    /// type of extra items storage that follows the object
84    type ExtraItem;
85    /// Return the number of extra items
86    fn extra_items_count(this: &Self) -> usize;
87    /// Return the extra items data pointer
88    unsafe fn extra_items(this: &Self) -> &[Self::ExtraItem] {
89        let extra_items_ptr = (this as *const Self as *const u8).add(std::mem::size_of::<Self>());
90        std::slice::from_raw_parts(
91            extra_items_ptr as *const Self::ExtraItem,
92            Self::extra_items_count(this),
93        )
94    }
95    /// Return the extra items data pointer
96    unsafe fn extra_items_mut(this: &mut Self) -> &mut [Self::ExtraItem] {
97        let extra_items_ptr = (this as *mut Self as *mut u8).add(std::mem::size_of::<Self>());
98        std::slice::from_raw_parts_mut(
99            extra_items_ptr as *mut Self::ExtraItem,
100            Self::extra_items_count(this),
101        )
102    }
103}
104
105/// Traits to specify core operations of ObjectRef
106///
107/// used by the ffi Any system and not user facing
108///
109/// We mark as unsafe since it moves out the internal of the ObjectRef
110///
111/// # Safety
112///
113/// `data`, `into_data`, and `from_data` must preserve the same object
114/// allocation and form an ownership-preserving round trip. That allocation must
115/// start with a valid `TVMFFIObject` header whose registered object-range
116/// runtime type index correctly describes its layout and inheritance.
117///
118/// When `Self` also implements [`AnyCompatible`], `copy_to_any_view` must
119/// produce a non-owning view, while `move_to_any` must transfer ownership of
120/// the same object pointer and dynamic type index. `move_from_any_after_check`
121/// must be able to reclaim that owned representation exactly once, and a true
122/// `check_any_strict` result must guarantee that both after-check constructors
123/// are valid for it.
124pub unsafe trait ObjectRefCore: Sized + Clone {
125    type ContainerType: ObjectCore;
126    fn data(this: &Self) -> &ObjectArc<Self::ContainerType>;
127    fn into_data(this: Self) -> ObjectArc<Self::ContainerType>;
128
129    /// Construct a reference view from an owning container handle.
130    ///
131    /// # Safety
132    ///
133    /// In addition to containing a valid `ContainerType` allocation, `data`
134    /// must satisfy every semantic invariant imposed by `Self`. This matters
135    /// for zero-state views that share a container type but accept only a
136    /// subset of its values, such as a typed expression view.
137    unsafe fn from_data(data: ObjectArc<Self::ContainerType>) -> Self;
138
139    /// Return whether two object references point to the same allocation.
140    #[inline]
141    fn same_as<Other: ObjectRefCore>(&self, other: &Other) -> bool {
142        unsafe {
143            ObjectArc::as_raw(Self::data(self)).cast::<()>()
144                == ObjectArc::as_raw(Other::data(other)).cast::<()>()
145        }
146    }
147
148    /// Borrow the underlying object as node type `N` when its runtime type matches.
149    ///
150    /// Unlike [`ObjectRefCast::try_cast`], this method neither consumes the
151    /// reference nor changes the object's reference count. The returned node
152    /// cannot outlive `self`.
153    #[inline(always)]
154    fn as_node<N: ObjectCore>(&self) -> Option<&N> {
155        let object = unsafe { ObjectArc::as_raw(Self::data(self)) };
156        let type_index = unsafe { (*object.cast::<TVMFFIObject>()).type_index };
157        if !is_instance_of::<N>(type_index) {
158            return None;
159        }
160        Some(unsafe { &*object.cast::<N>() })
161    }
162}
163
164/// An owning, hashable identity key for an FFI object.
165///
166/// The retained strong reference prevents the allocation address from being
167/// reused while the key is alive. This makes it suitable for identity-based
168/// maps without exposing raw object pointers to downstream code.
169#[derive(Clone)]
170pub struct ObjectIdentity {
171    data: ObjectArc<Object>,
172}
173
174impl ObjectIdentity {
175    /// Retain the allocation referenced by `value` as an identity key.
176    pub fn of<T: ObjectRefCore>(value: &T) -> Self {
177        unsafe {
178            let ptr = ObjectArc::as_raw(T::data(value)) as *mut TVMFFIObject;
179            unsafe_::inc_ref(ptr);
180            Self {
181                data: ObjectArc::from_raw(ptr.cast::<Object>()),
182            }
183        }
184    }
185
186    #[inline]
187    fn as_ptr(&self) -> *const TVMFFIObject {
188        unsafe { ObjectArc::as_raw(&self.data).cast::<TVMFFIObject>() }
189    }
190}
191
192impl PartialEq for ObjectIdentity {
193    #[inline]
194    fn eq(&self, other: &Self) -> bool {
195        self.as_ptr() == other.as_ptr()
196    }
197}
198
199impl Eq for ObjectIdentity {}
200
201impl std::hash::Hash for ObjectIdentity {
202    #[inline]
203    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
204        self.as_ptr().hash(state);
205    }
206}
207
208impl std::fmt::Debug for ObjectIdentity {
209    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
210        f.debug_tuple("ObjectIdentity")
211            .field(&self.as_ptr())
212            .finish()
213    }
214}
215
216/// Check whether a runtime type index refers to `Target` or one of its
217/// subtypes.
218///
219/// The subtype relation lives in the process-wide type table maintained by the
220/// tvm-ffi library: every registered type records its depth in the single
221/// inheritance tree together with the chain of its ancestors. The check is
222/// O(1) — if `target` really is an ancestor, it must appear in the candidate's
223/// ancestor array exactly at `target`'s depth.
224///
225/// This is a hidden support function for derive-generated object checks. Object
226/// indices in the registered range must refer to entries in the runtime type
227/// table.
228#[doc(hidden)]
229#[inline(always)]
230pub fn is_instance_of<Target: ObjectCore>(object_type_index: i32) -> bool {
231    let target_type_index = Target::type_index();
232    if object_type_index == target_type_index {
233        return true;
234    }
235    // A final type cannot have a separately registered subtype. Keep common
236    // borrowed checks, such as `IntImmObj`, to one integer comparison.
237    if Target::TYPE_FINAL {
238        return false;
239    }
240    let object_begin = TypeIndex::kTVMFFIStaticObjectBegin as i32;
241    // Only object types participate in the type hierarchy.
242    if object_type_index < object_begin || target_type_index < object_begin {
243        return false;
244    }
245    // Parent indices are always smaller than their descendants.
246    if object_type_index < target_type_index {
247        return false;
248    }
249    unsafe {
250        let object_info = TVMFFIGetTypeInfo(object_type_index);
251        if object_info.is_null() {
252            return false;
253        }
254        let target_depth = Target::TYPE_DEPTH;
255        if (*object_info).type_depth <= target_depth {
256            return false;
257        }
258        let ancestor = *(*object_info).type_acenstors.add(target_depth as usize);
259        !ancestor.is_null() && (*ancestor).type_index == target_type_index
260    }
261}
262
263/// Runtime-checked casting between arbitrary `ObjectRef` types.
264///
265/// The cast uses the target's [`AnyCompatible::check_any_strict`] implementation,
266/// mirroring the semantics of `ObjectRef::as<T>` in C++. This supports both
267/// object hierarchies and parameterized object containers.
268///
269/// This trait is blanket-implemented for every [`ObjectRefCore`] type that is
270/// also [`AnyCompatible`].
271pub trait ObjectRefCast: ObjectRefCore + AnyCompatible {
272    /// Consume `self` and rewrap the underlying object as `B` without copying.
273    #[inline(always)]
274    fn try_cast<B>(self) -> crate::error::Result<B>
275    where
276        B: ObjectRefCore + AnyCompatible,
277    {
278        let mut any_data = TVMFFIAny::new();
279        unsafe {
280            // Keep ownership in `self` while the target check runs. This makes
281            // the failure and panic paths unwind normally instead of stranding
282            // an owned object inside a raw TVMFFIAny.
283            Self::copy_to_any_view(&self, &mut any_data);
284            debug_assert!(any_data.type_index >= TypeIndex::kTVMFFIStaticObjectBegin as i32);
285            // SAFETY: ObjectRefCore's contract requires its AnyCompatible
286            // representation to contain a valid object-range type index.
287            std::hint::assert_unchecked(
288                any_data.type_index >= TypeIndex::kTVMFFIStaticObjectBegin as i32,
289            );
290
291            if B::check_any_strict(&any_data) {
292                // Transfer ownership only after the borrowed representation has
293                // passed the target's complete hierarchy/container check.
294                Self::move_to_any(self, &mut any_data);
295                Ok(B::move_from_any_after_check(&mut any_data))
296            } else {
297                let msg = format!(
298                    "Cannot convert from type `{}` to `{}`",
299                    B::get_mismatch_type_info(&any_data),
300                    B::type_str()
301                );
302                Err(crate::error::Error::new(crate::error::TYPE_ERROR, &msg, ""))
303            }
304        }
305    }
306}
307
308impl<T: ObjectRefCore + AnyCompatible> ObjectRefCast for T {}
309
310/// Base class for ObjectRef
311///
312/// This class is used to store the data of the ObjectRef
313#[repr(C)]
314#[derive(ObjectRef, Clone)]
315pub struct ObjectRef {
316    data: ObjectArc<Object>,
317}
318
319/// Unsafe operations on object
320#[doc(hidden)]
321pub mod unsafe_ {
322    use tvm_ffi_sys::{
323        COMBINED_REF_COUNT_BOTH_ONE, COMBINED_REF_COUNT_MASK_U32, COMBINED_REF_COUNT_STRONG_ONE,
324        COMBINED_REF_COUNT_WEAK_ONE,
325    };
326
327    use std::ffi::c_void;
328    use std::sync::atomic::{fence, Ordering};
329    use tvm_ffi_sys::TVMFFIObject;
330    use tvm_ffi_sys::TVMFFIObjectDeleterFlagBitMask::{
331        kTVMFFIObjectDeleterFlagBitMaskBoth, kTVMFFIObjectDeleterFlagBitMaskStrong,
332        kTVMFFIObjectDeleterFlagBitMaskWeak,
333    };
334
335    /// Increase the strong reference count of the object
336    ///
337    /// This function is same as TVMFFIObjectIncRef but implemented natively in Rust
338    ///
339    /// # Arguments
340    /// * `obj` - The object to increase the reference count
341    #[inline]
342    pub unsafe fn inc_ref(handle: *mut TVMFFIObject) {
343        let obj = &mut *handle;
344        obj.combined_ref_count.fetch_add(1, Ordering::Relaxed);
345    }
346
347    /// Decrease the strong reference count of the object
348    ///
349    /// This function is same as TVMFFIObjectDecRef but implemented natively in Rust
350    ///
351    /// # Arguments
352    /// * `obj` - The object to decrease the reference count
353    #[inline]
354    pub(crate) unsafe fn dec_ref(handle: *mut TVMFFIObject) {
355        let obj = &mut *handle;
356        let old_combined_count = obj
357            .combined_ref_count
358            .fetch_sub(COMBINED_REF_COUNT_STRONG_ONE, Ordering::Relaxed);
359        if old_combined_count == COMBINED_REF_COUNT_BOTH_ONE {
360            if let Some(deleter) = obj.deleter {
361                fence(Ordering::Acquire);
362                deleter(
363                    obj as *mut TVMFFIObject as *mut c_void,
364                    kTVMFFIObjectDeleterFlagBitMaskBoth as i32,
365                );
366            }
367        } else if (old_combined_count & COMBINED_REF_COUNT_MASK_U32)
368            == COMBINED_REF_COUNT_STRONG_ONE
369        {
370            // slow path, there is still a weak reference left
371            // need to run two phase decrement
372            fence(Ordering::Acquire);
373            if let Some(deleter) = obj.deleter {
374                deleter(
375                    obj as *mut TVMFFIObject as *mut c_void,
376                    kTVMFFIObjectDeleterFlagBitMaskStrong as i32,
377                );
378            }
379            let old_weak_count = obj
380                .combined_ref_count
381                .fetch_sub(COMBINED_REF_COUNT_WEAK_ONE, Ordering::Release);
382            if old_weak_count == COMBINED_REF_COUNT_WEAK_ONE {
383                fence(Ordering::Acquire);
384                if let Some(deleter) = obj.deleter {
385                    deleter(
386                        obj as *mut TVMFFIObject as *mut c_void,
387                        kTVMFFIObjectDeleterFlagBitMaskWeak as i32,
388                    );
389                }
390            }
391        }
392    }
393
394    #[inline]
395    pub(crate) unsafe fn strong_count(handle: *mut TVMFFIObject) -> usize {
396        let obj = &mut *handle;
397        (obj.combined_ref_count.load(Ordering::Relaxed) & COMBINED_REF_COUNT_MASK_U32) as usize
398    }
399
400    #[inline]
401    pub(crate) unsafe fn weak_count(handle: *mut TVMFFIObject) -> usize {
402        let obj = &mut *handle;
403        (obj.combined_ref_count.load(Ordering::Relaxed) >> 32) as usize
404    }
405
406    /// Generic object deleter for objects allocated through Rust's global allocator.
407    pub(crate) unsafe extern "C" fn object_deleter_for_new<T>(ptr: *mut c_void, flags: i32)
408    where
409        T: super::ObjectCore,
410    {
411        let obj = ptr as *mut T;
412        if flags & kTVMFFIObjectDeleterFlagBitMaskStrong as i32 != 0 {
413            std::ptr::drop_in_place(obj);
414        }
415        if flags & kTVMFFIObjectDeleterFlagBitMaskWeak as i32 != 0 {
416            std::alloc::dealloc(ptr as *mut u8, std::alloc::Layout::new::<T>());
417        }
418    }
419
420    pub(crate) unsafe extern "C" fn object_deleter_for_new_with_extra_items<T, U>(
421        ptr: *mut c_void,
422        flags: i32,
423    ) where
424        T: super::ObjectCoreWithExtraItems<ExtraItem = U>,
425    {
426        let obj = ptr as *mut T;
427        if flags == kTVMFFIObjectDeleterFlagBitMaskBoth as i32 {
428            let extra_items_count = T::extra_items_count(&(*obj));
429            std::ptr::drop_in_place(obj);
430            let layout = std::alloc::Layout::from_size_align(
431                std::mem::size_of::<T>() + extra_items_count * std::mem::size_of::<U>(),
432                std::mem::align_of::<T>(),
433            )
434            .unwrap();
435            std::alloc::dealloc(ptr as *mut u8, layout);
436        } else {
437            assert_eq!(std::mem::size_of::<T>() % std::mem::size_of::<u64>(), 0);
438            if flags & kTVMFFIObjectDeleterFlagBitMaskStrong as i32 != 0 {
439                let extra_items_count = T::extra_items_count(&(*obj));
440                std::ptr::drop_in_place(obj);
441                std::ptr::write(obj as *mut u64, extra_items_count as u64);
442            }
443            if flags & kTVMFFIObjectDeleterFlagBitMaskWeak as i32 != 0 {
444                let extra_items_count = std::ptr::read(obj as *mut u64) as usize;
445                let layout = std::alloc::Layout::from_size_align(
446                    std::mem::size_of::<T>() + extra_items_count * std::mem::size_of::<U>(),
447                    std::mem::align_of::<T>(),
448                )
449                .unwrap();
450                std::alloc::dealloc(ptr as *mut u8, layout);
451            }
452        }
453    }
454}
455
456//---------------------
457// Object
458//---------------------
459
460impl Object {
461    pub fn new() -> Self {
462        Self {
463            header: TVMFFIObject::new(),
464        }
465    }
466}
467
468unsafe impl ObjectCore for Object {
469    const TYPE_KEY: &'static str = "ffi.Object";
470    const TYPE_DEPTH: i32 = 0;
471    #[inline]
472    fn type_index() -> i32 {
473        TypeIndex::kTVMFFIStaticObjectBegin as i32
474    }
475    #[inline]
476    unsafe fn object_header_mut(this: &mut Self) -> &mut TVMFFIObject {
477        &mut this.header
478    }
479}
480
481//---------------------
482// ObjectArc
483//---------------------
484
485impl<T: ObjectCore> ObjectArc<T> {
486    pub fn new(data: T) -> Self {
487        unsafe {
488            let layout = std::alloc::Layout::new::<T>();
489            let raw_data_ptr = std::alloc::alloc(layout);
490            if raw_data_ptr.is_null() {
491                std::alloc::handle_alloc_error(layout);
492            }
493            let ptr = raw_data_ptr as *mut T;
494            std::ptr::write(ptr, data);
495            // now override the header directly
496            std::ptr::write(
497                ptr as *mut TVMFFIObject,
498                TVMFFIObject {
499                    combined_ref_count: AtomicU64::new(COMBINED_REF_COUNT_BOTH_ONE),
500                    type_index: T::type_index(),
501                    __padding: 0,
502                    deleter: Some(unsafe_::object_deleter_for_new::<T>),
503                },
504            );
505            // move into the object arc ptr
506            Self {
507                ptr: std::ptr::NonNull::new_unchecked(ptr as *mut T),
508                _phantom: std::marker::PhantomData,
509            }
510        }
511    }
512    pub fn new_with_extra_items<U>(data: T) -> Self
513    where
514        T: ObjectCoreWithExtraItems<ExtraItem = U>,
515    {
516        unsafe {
517            // ensure strict alignment requirements
518            // so we can have { T, U*extra_items } layout
519            assert_eq!(std::mem::align_of::<T>() % std::mem::align_of::<U>(), 0);
520            assert_eq!(std::mem::size_of::<T>() % std::mem::align_of::<U>(), 0);
521            let extra_items_count = T::extra_items_count(&data);
522            let layout = std::alloc::Layout::from_size_align(
523                std::mem::size_of::<T>() + extra_items_count * std::mem::size_of::<U>(),
524                std::mem::align_of::<T>(),
525            )
526            .unwrap();
527            let raw_data_ptr = std::alloc::alloc(layout);
528            if raw_data_ptr.is_null() {
529                std::alloc::handle_alloc_error(layout);
530            }
531            let ptr = raw_data_ptr as *mut T;
532            std::ptr::write(ptr, data);
533            // now override the header directly
534            std::ptr::write(
535                ptr as *mut TVMFFIObject,
536                TVMFFIObject {
537                    combined_ref_count: AtomicU64::new(COMBINED_REF_COUNT_BOTH_ONE),
538                    type_index: T::type_index(),
539                    __padding: 0,
540                    deleter: Some(unsafe_::object_deleter_for_new_with_extra_items::<T, U>),
541                },
542            );
543            // move into the object arc ptr
544            Self {
545                ptr: std::ptr::NonNull::new_unchecked(ptr as *mut T),
546                _phantom: std::marker::PhantomData,
547            }
548        }
549    }
550
551    /// Move a previously allocated object into the ObjectArc
552    ///
553    /// # Arguments
554    /// * `ptr` - The raw pointer to move into the ObjectArc
555    ///
556    /// # Returns
557    /// * `ObjectArc<T>` - The ObjectArc
558    /// \return The ObjectArc
559    #[inline]
560    pub unsafe fn from_raw(ptr: *const T) -> Self {
561        Self {
562            ptr: std::ptr::NonNull::new_unchecked(ptr as *mut T),
563            _phantom: std::marker::PhantomData,
564        }
565    }
566
567    /// Move the ObjectArc into a raw pointer
568    ///
569    /// # Arguments
570    /// * `this` - The ObjectArc to move into a raw pointer
571    ///
572    /// # Returns
573    /// * `*const T` - The raw pointer
574    #[inline]
575    pub unsafe fn into_raw(this: Self) -> *const T {
576        let droped_this = std::mem::ManuallyDrop::new(this);
577        droped_this.ptr.as_ptr() as *const T
578    }
579
580    /// Get the raw pointer from the ObjectArc
581    ///
582    /// Caller should view this as a non-owning reference
583    ///
584    /// # Arguments
585    /// * `this` - The ObjectArc to get the raw pointer
586    ///
587    /// # Returns
588    /// * `*const T` - The raw pointer
589    /// \return The raw pointer
590    #[inline]
591    pub unsafe fn as_raw(this: &Self) -> *const T {
592        this.ptr.as_ptr() as *const T
593    }
594
595    /// Get the raw mutable pointer from the ObjectArc
596    ///
597    /// Caller should view this as a non-owning reference
598    ///
599    /// # Arguments
600    /// * `this` - The ObjectArc to get the raw pointer
601    ///
602    /// # Returns
603    /// * `*mut T` - The raw pointer
604    #[inline]
605    pub unsafe fn as_raw_mut(this: &mut Self) -> *mut T {
606        this.ptr.as_mut()
607    }
608
609    /// Get the strong reference count of the ObjectArc
610    ///
611    /// # Arguments
612    /// * `this` - The ObjectArc to get the strong reference count
613    ///
614    /// # Returns
615    /// * `usize` - The strong reference count
616    #[inline]
617    pub fn strong_count(this: &Self) -> usize {
618        unsafe {
619            unsafe_::strong_count(this.ptr.as_ref() as *const T as *mut T as *mut TVMFFIObject)
620        }
621    }
622
623    /// Get the weak reference count of the ObjectArc
624    ///
625    /// # Arguments
626    /// * `this` - The ObjectArc to get the weak reference count
627    ///
628    /// # Returns
629    /// * `usize` - The weak reference count
630    #[inline]
631    pub fn weak_count(this: &Self) -> usize {
632        unsafe { unsafe_::weak_count(this.ptr.as_ref() as *const T as *mut T as *mut TVMFFIObject) }
633    }
634}
635
636// implement Deref for ObjectArc
637impl<T: ObjectCore> Deref for ObjectArc<T> {
638    type Target = T;
639    #[inline]
640    fn deref(&self) -> &Self::Target {
641        unsafe { self.ptr.as_ref() }
642    }
643}
644
645// implement DerefMut for ObjectArc
646impl<T: ObjectCore> DerefMut for ObjectArc<T> {
647    #[inline]
648    fn deref_mut(&mut self) -> &mut Self::Target {
649        unsafe { self.ptr.as_mut() }
650    }
651}
652
653// implement Drop for ObjectArc
654impl<T: ObjectCore> Drop for ObjectArc<T> {
655    fn drop(&mut self) {
656        unsafe { unsafe_::dec_ref(self.ptr.as_mut() as *mut T as *mut TVMFFIObject) }
657    }
658}
659
660// implement Clone for ObjectArc
661impl<T: ObjectCore> Clone for ObjectArc<T> {
662    #[inline]
663    fn clone(&self) -> Self {
664        unsafe { unsafe_::inc_ref(self.ptr.as_ref() as *const T as *mut T as *mut TVMFFIObject) }
665        Self {
666            ptr: self.ptr,
667            _phantom: std::marker::PhantomData,
668        }
669    }
670}