Skip to main content

tvm_ffi/
rvalue_ref.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 */
19
20//! Move-aware object arguments compatible with C++ `ffi::RValueRef<T>`.
21
22use std::cell::UnsafeCell;
23use std::marker::PhantomData;
24
25use tvm_ffi_sys::{TVMFFIAny, TVMFFIObject, TVMFFITypeIndex as TypeIndex};
26
27use crate::any::ArgTryFromAnyView;
28use crate::{AnyCompatible, AnyView, Error, ObjectRefCore, Result};
29
30/// A move-aware object argument compatible with C++ `ffi::RValueRef<T>`.
31///
32/// The callee may take the stored strong reference without incrementing its
33/// count; otherwise this wrapper retains and releases it.
34pub struct RValueRef<T>
35where
36    T: ObjectRefCore + AnyCompatible,
37{
38    slot: UnsafeCell<*mut TVMFFIObject>,
39    _marker: PhantomData<T>,
40}
41
42impl<T> RValueRef<T>
43where
44    T: ObjectRefCore + AnyCompatible,
45{
46    /// Transfer an owned object reference into an rvalue argument slot.
47    pub fn new(value: T) -> Self {
48        let mut raw = TVMFFIAny::new();
49        unsafe { T::move_to_any(value, &mut raw) };
50        debug_assert!(raw.type_index >= TypeIndex::kTVMFFIStaticObjectBegin as i32);
51        Self {
52            slot: UnsafeCell::new(unsafe { raw.data_union.v_obj }),
53            _marker: PhantomData,
54        }
55    }
56
57    /// Take the owned object without copying or incrementing its reference count.
58    pub fn into_inner(mut self) -> T {
59        let object = *self.slot.get_mut();
60        assert!(!object.is_null(), "RValueRef has already been moved");
61        *self.slot.get_mut() = std::ptr::null_mut();
62        unsafe {
63            let mut raw = object_any(object);
64            T::move_from_any_after_check(&mut raw)
65        }
66    }
67
68    unsafe fn from_view(value: &AnyView<'_>, arg_index: Option<usize>) -> Result<Self> {
69        let raw = value.as_raw_ffi_any();
70        let converted = if raw.type_index == TypeIndex::kTVMFFIObjectRValueRef as i32 {
71            let slot = raw.data_union.v_ptr.cast::<*mut TVMFFIObject>();
72            if slot.is_null() || (*slot).is_null() {
73                return Err(conversion_error::<T>(raw, arg_index, true));
74            }
75            let object = *slot;
76            let object_view = object_any(object);
77            if T::check_any_strict(&object_view) {
78                *slot = std::ptr::null_mut();
79                return Ok(Self {
80                    slot: UnsafeCell::new(object),
81                    _marker: PhantomData,
82                });
83            }
84            T::try_cast_from_any_view(&object_view)
85        } else if T::check_any_strict(raw) {
86            Ok(T::copy_from_any_view_after_check(raw))
87        } else {
88            T::try_cast_from_any_view(raw)
89        };
90
91        converted
92            .map(Self::new)
93            .map_err(|()| conversion_error::<T>(raw, arg_index, false))
94    }
95}
96
97impl<T> From<T> for RValueRef<T>
98where
99    T: ObjectRefCore + AnyCompatible,
100{
101    fn from(value: T) -> Self {
102        Self::new(value)
103    }
104}
105
106impl<'a, T> From<&'a RValueRef<T>> for AnyView<'a>
107where
108    T: ObjectRefCore + AnyCompatible,
109{
110    fn from(value: &'a RValueRef<T>) -> Self {
111        let mut raw = TVMFFIAny::new();
112        raw.type_index = TypeIndex::kTVMFFIObjectRValueRef as i32;
113        raw.data_union.v_ptr = value.slot.get().cast();
114        unsafe { AnyView::from_raw_ffi_any(raw) }
115    }
116}
117
118impl<T> TryFrom<AnyView<'_>> for RValueRef<T>
119where
120    T: ObjectRefCore + AnyCompatible,
121{
122    type Error = Error;
123
124    fn try_from(value: AnyView<'_>) -> Result<Self> {
125        unsafe { Self::from_view(&value, None) }
126    }
127}
128
129impl<T> ArgTryFromAnyView for RValueRef<T>
130where
131    T: ObjectRefCore + AnyCompatible,
132{
133    fn try_from_any_view(value: &AnyView<'_>, arg_index: usize) -> Result<Self> {
134        unsafe { Self::from_view(value, Some(arg_index)) }
135    }
136}
137
138impl<T> Drop for RValueRef<T>
139where
140    T: ObjectRefCore + AnyCompatible,
141{
142    fn drop(&mut self) {
143        let object = *self.slot.get_mut();
144        if !object.is_null() {
145            unsafe { crate::object::unsafe_::dec_ref(object) };
146        }
147    }
148}
149
150unsafe fn object_any(object: *mut TVMFFIObject) -> TVMFFIAny {
151    let mut raw = TVMFFIAny::new();
152    raw.type_index = (*object).type_index;
153    raw.data_union.v_obj = object;
154    raw
155}
156
157unsafe fn conversion_error<T>(
158    raw: &TVMFFIAny,
159    arg_index: Option<usize>,
160    already_moved: bool,
161) -> Error
162where
163    T: ObjectRefCore + AnyCompatible,
164{
165    let source = if already_moved {
166        "an already-moved RValueRef".to_string()
167    } else if raw.type_index == TypeIndex::kTVMFFIObjectRValueRef as i32 {
168        "RValueRef with an incompatible object type".to_string()
169    } else {
170        T::get_mismatch_type_info(raw)
171    };
172    let prefix = arg_index
173        .map(|index| format!("Argument #{index}: "))
174        .unwrap_or_default();
175    Error::new(
176        crate::error::TYPE_ERROR,
177        &format!(
178            "{prefix}Cannot convert from `{source}` to `RValueRef<{}>`",
179            T::type_str()
180        ),
181        "",
182    )
183}