tvm_ffi/
any.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 crate::error::Error;
20use crate::object;
21use crate::type_traits::AnyCompatible;
22use tvm_ffi_sys::TVMFFITypeIndex as TypeIndex;
23use tvm_ffi_sys::{TVMFFIAny, TVMFFIAnyViewToOwnedAny};
24
25/// Unmanaged Any that can hold reference to values
26#[derive(Copy, Clone)]
27#[repr(C)]
28pub struct AnyView<'a> {
29    data: TVMFFIAny,
30    /// needs to explicit mark lifetime to avoid lifetime mismatch
31    _phantom: std::marker::PhantomData<&'a ()>,
32}
33
34/// Managed Any that can hold reference to values
35#[repr(C)]
36pub struct Any {
37    data: TVMFFIAny,
38}
39
40//---------------------
41// AnyView
42//---------------------
43impl<'a> AnyView<'a> {
44    pub fn new() -> Self {
45        Self {
46            data: TVMFFIAny::new(),
47            _phantom: std::marker::PhantomData,
48        }
49    }
50
51    #[inline]
52    pub fn type_index(&self) -> i32 {
53        self.data.type_index
54    }
55
56    /// More strict version than try_from/try_into
57    ///
58    /// This function will not try to cast the type
59    /// and ensures invariance that the return value is only Some(T)
60    /// Any::from(T) contains exactly the same value value
61    ///
62    /// will return Some(T) if the type is exactly compatible with T
63    /// will return None if the type is not compatible with T
64    #[inline]
65    pub fn try_as<T>(&self) -> Option<T>
66    where
67        T: AnyCompatible,
68    {
69        unsafe {
70            if T::check_any_strict(&self.data) {
71                Some(T::copy_from_any_view_after_check(&self.data))
72            } else {
73                None
74            }
75        }
76    }
77
78    /// Get the strong count of the underlying object for testing/debugging purposes
79    ///
80    /// If the underlying object is not ref counted, return None
81    pub fn debug_strong_count(&self) -> Option<usize> {
82        unsafe {
83            if self.data.type_index >= TypeIndex::kTVMFFIStaticObjectBegin as i32 {
84                Some(object::unsafe_::strong_count(self.data.data_union.v_obj))
85            } else {
86                None
87            }
88        }
89    }
90}
91
92impl<'a, T: AnyCompatible> From<&'a T> for AnyView<'a> {
93    #[inline]
94    fn from(value: &'a T) -> Self {
95        unsafe {
96            let mut data = TVMFFIAny::new();
97            T::copy_to_any_view(&value, &mut data);
98            Self {
99                data: data,
100                _phantom: std::marker::PhantomData,
101            }
102        }
103    }
104}
105
106impl Default for AnyView<'_> {
107    fn default() -> Self {
108        Self::new()
109    }
110}
111
112/// Holder for Any value
113///
114/// This is used to define try_from rule while conforming to orphan rule
115/// Users should not use this directly
116pub struct TryFromTemp<T> {
117    value: T,
118}
119
120impl<T> TryFromTemp<T> {
121    /// Create a new holder for the value
122    #[inline(always)]
123    pub fn new(value: T) -> Self {
124        Self { value }
125    }
126
127    /// Move the value out of the holder
128    #[inline(always)]
129    pub fn into_value(this: Self) -> T {
130        this.value
131    }
132}
133
134//---------------------
135// Any
136//---------------------
137impl Any {
138    pub fn new() -> Self {
139        Self {
140            data: TVMFFIAny::new(),
141        }
142    }
143    #[inline]
144    pub fn type_index(&self) -> i32 {
145        self.data.type_index
146    }
147    /// Try to query if stored typed in Any exactly matches the type T
148    ///
149    /// This function is fast in the case of failure and can be used to check
150    /// if the type is compatible with T
151    ///
152    /// This function will not try to cast the type
153    /// and ensures invariance that the return value is only Some(T)
154    /// `Any::from(T)` contains exactly the same value value
155    /// `Any::try_as<T>()` contains exactly the same value value
156    ///
157    /// will return Some(T) if the type is exactly compatible with T
158    /// will return None if the type is not compatible with T
159    #[inline]
160    pub fn try_as<T>(&self) -> Option<T>
161    where
162        T: AnyCompatible,
163    {
164        unsafe {
165            if T::check_any_strict(&self.data) {
166                Some(T::copy_from_any_view_after_check(&self.data))
167            } else {
168                None
169            }
170        }
171    }
172
173    #[inline]
174    pub unsafe fn as_data_ptr(&mut self) -> *mut TVMFFIAny {
175        &mut self.data
176    }
177
178    #[inline]
179    pub unsafe fn into_raw_ffi_any(this: Self) -> TVMFFIAny {
180        this.data
181    }
182
183    #[inline]
184    pub unsafe fn from_raw_ffi_any(data: TVMFFIAny) -> Self {
185        Self { data }
186    }
187
188    /// Get the strong count of the underlying object for testing/debugging purposes
189    ///
190    /// If the underlying object is not ref counted, return None
191    pub fn debug_strong_count(&self) -> Option<usize> {
192        unsafe {
193            if self.data.type_index >= TypeIndex::kTVMFFIStaticObjectBegin as i32 {
194                Some(object::unsafe_::strong_count(self.data.data_union.v_obj))
195            } else {
196                None
197            }
198        }
199    }
200}
201
202impl Default for Any {
203    fn default() -> Self {
204        Self::new()
205    }
206}
207
208impl Clone for Any {
209    #[inline]
210    fn clone(&self) -> Self {
211        if self.data.type_index >= TypeIndex::kTVMFFIStaticObjectBegin as i32 {
212            unsafe { object::unsafe_::inc_ref(self.data.data_union.v_obj) }
213        }
214        Self { data: self.data }
215    }
216}
217
218impl Drop for Any {
219    #[inline]
220    fn drop(&mut self) {
221        if self.data.type_index >= TypeIndex::kTVMFFIStaticObjectBegin as i32 {
222            unsafe { object::unsafe_::dec_ref(self.data.data_union.v_obj) }
223        }
224    }
225}
226
227// convert Any ref to AnyView
228impl<'a> From<&'a Any> for AnyView<'a> {
229    #[inline]
230    fn from(value: &'a Any) -> Self {
231        Self {
232            data: value.data,
233            _phantom: std::marker::PhantomData,
234        }
235    }
236}
237
238// convert AnyView to Any
239impl From<AnyView<'_>> for Any {
240    #[inline]
241    fn from(value: AnyView<'_>) -> Self {
242        unsafe {
243            let mut data = TVMFFIAny::new();
244            crate::check_safe_call!(TVMFFIAnyViewToOwnedAny(&value.data, &mut data)).unwrap();
245            Self { data }
246        }
247    }
248}
249
250impl<T: AnyCompatible> From<T> for Any {
251    #[inline]
252    fn from(value: T) -> Self {
253        unsafe {
254            let mut data = TVMFFIAny::new();
255            T::move_to_any(value, &mut data);
256            Self { data }
257        }
258    }
259}
260
261impl<'a, T: AnyCompatible> TryFrom<AnyView<'a>> for TryFromTemp<T> {
262    type Error = crate::error::Error;
263    #[inline]
264    fn try_from(value: AnyView<'a>) -> Result<Self, Self::Error> {
265        unsafe {
266            if T::check_any_strict(&value.data) {
267                Ok(TryFromTemp::new(T::copy_from_any_view_after_check(
268                    &value.data,
269                )))
270            } else {
271                T::try_cast_from_any_view(&value.data)
272                    .map_err(|_| {
273                        let msg = format!(
274                            "Cannot convert from type `{}` to `{}`",
275                            T::get_mismatch_type_info(&value.data),
276                            T::type_str()
277                        );
278                        crate::error::Error::new(crate::error::TYPE_ERROR, &msg, "")
279                    })
280                    .map(TryFromTemp::new)
281            }
282        }
283    }
284}
285
286impl<T: AnyCompatible> TryFrom<Any> for TryFromTemp<T> {
287    type Error = crate::error::Error;
288    #[inline]
289    fn try_from(value: Any) -> Result<Self, Self::Error> {
290        unsafe {
291            if T::check_any_strict(&value.data) {
292                let mut value = std::mem::ManuallyDrop::new(value);
293                Ok(TryFromTemp::new(T::move_from_any_after_check(
294                    &mut value.data,
295                )))
296            } else {
297                T::try_cast_from_any_view(&value.data)
298                    .map_err(|_| {
299                        let msg = format!(
300                            "Cannot convert from type `{}` to `{}`",
301                            T::get_mismatch_type_info(&value.data),
302                            T::type_str()
303                        );
304                        crate::error::Error::new(crate::error::TYPE_ERROR, &msg, "")
305                    })
306                    .map(TryFromTemp::new)
307            }
308        }
309    }
310}
311
312crate::impl_try_from_any!(
313    bool,
314    i8,
315    i16,
316    i32,
317    i64,
318    isize,
319    u8,
320    u16,
321    u32,
322    u64,
323    usize,
324    f32,
325    f64,
326    (),
327    *mut core::ffi::c_void,
328    crate::string::String,
329    crate::string::Bytes,
330    crate::object::ObjectRef,
331    tvm_ffi_sys::dlpack::DLDataType,
332    tvm_ffi_sys::dlpack::DLDevice,
333);
334
335crate::impl_try_from_any_for_parametric!(Option<T>);
336
337//------------------------------------------------------------
338/// ArgTryFromAnyView: Helper for function argument passing
339///-----------------------------------------------------------
340pub(crate) trait ArgTryFromAnyView: Sized {
341    fn try_from_any_view(value: &AnyView, arg_index: usize) -> Result<Self, Error>;
342}
343
344impl<T: AnyCompatible> ArgTryFromAnyView for T {
345    fn try_from_any_view(value: &AnyView, arg_index: usize) -> Result<Self, Error> {
346        unsafe {
347            if T::check_any_strict(&value.data) {
348                Ok(T::copy_from_any_view_after_check(&value.data))
349            } else {
350                T::try_cast_from_any_view(&value.data).map_err(|_| {
351                    let msg = format!(
352                        "Argument #{}: Cannot convert from type `{}` to `{}`",
353                        arg_index,
354                        T::get_mismatch_type_info(&value.data),
355                        T::type_str()
356                    );
357                    crate::error::Error::new(crate::error::TYPE_ERROR, &msg, "")
358                })
359            }
360        }
361    }
362}