tvm_ffi/function.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::any::{Any, AnyView};
20use crate::derive::{Object, ObjectRef};
21use crate::error::{Error, Result};
22use crate::function_internal::{AsPackedCallable, TupleAsPackedArgs};
23use crate::object::{Object, ObjectArc, ObjectCore};
24use crate::type_traits::AnyCompatible;
25use tvm_ffi_sys::{
26 TVMFFIAny, TVMFFIByteArray, TVMFFIFunctionCell, TVMFFIFunctionCreate, TVMFFIFunctionGetGlobal,
27 TVMFFIFunctionSetGlobal, TVMFFIGetTypeInfo, TVMFFIObjectHandle, TVMFFISafeCallType,
28 TVMFFITypeIndex, TVMFFITypeKeyToIndex,
29};
30
31/// function object
32#[repr(C)]
33#[derive(Object)]
34#[type_key = "ffi.Function"]
35#[type_index(TVMFFITypeIndex::kTVMFFIFunction)]
36pub struct FunctionObj {
37 object: Object,
38 cell: TVMFFIFunctionCell,
39}
40
41/// Error reference class
42#[derive(Clone, ObjectRef)]
43pub struct Function {
44 data: ObjectArc<FunctionObj>,
45}
46
47//------------------------------------------------------------------------
48// CallbackFunctionObjImpl
49//------------------------------------------------------------------------
50/// Special helper class to hold a generic callback state as Object
51/// Logically this Impl can be viewed as a FunctionObj
52/// We can create an ObjectArc<CallbackFunctionObjImpl<F>> so the deleter
53/// can correctly delete the entire object including callback part
54/// then we will convert to ObjectArc<FunctionObj> to be used as function
55#[repr(C)]
56struct CallbackFunctionObjImpl<F: Fn(&[AnyView]) -> Result<Any> + 'static> {
57 function: FunctionObj,
58 callback: F,
59}
60
61impl<F: Fn(&[AnyView]) -> Result<Any> + 'static> CallbackFunctionObjImpl<F> {
62 pub fn from_callback(callback: F) -> Self {
63 Self {
64 function: FunctionObj {
65 object: Object::new(),
66 cell: TVMFFIFunctionCell {
67 // specfic callback for F
68 safe_call: Self::invoke_callback,
69 cxx_call: std::ptr::null_mut(),
70 },
71 },
72 callback,
73 }
74 }
75
76 unsafe extern "C" fn invoke_callback(
77 handle: *mut std::ffi::c_void,
78 args: *const TVMFFIAny,
79 num_args: i32,
80 result: *mut TVMFFIAny,
81 ) -> i32 {
82 let this = &*(handle as *mut Self);
83 let packed_args = std::slice::from_raw_parts(args as *const AnyView, num_args as usize);
84 let ret_value = (this.callback)(packed_args);
85 match ret_value {
86 Ok(value) => {
87 *result = Any::into_raw_ffi_any(value);
88 0
89 }
90 Err(error) => {
91 Error::set_raised(&error);
92 -1
93 }
94 }
95 }
96}
97
98unsafe impl<F: Fn(&[AnyView]) -> Result<Any> + 'static> ObjectCore for CallbackFunctionObjImpl<F> {
99 const TYPE_KEY: &'static str = FunctionObj::TYPE_KEY;
100 const TYPE_DEPTH: i32 = FunctionObj::TYPE_DEPTH;
101 fn type_index() -> i32 {
102 FunctionObj::type_index()
103 }
104 unsafe fn object_header_mut(this: &mut Self) -> &mut tvm_ffi_sys::TVMFFIObject {
105 FunctionObj::object_header_mut(&mut this.function)
106 }
107}
108
109impl Function {
110 /// Call the function in packed format.
111 pub fn call_packed(&self, packed_args: &[AnyView]) -> Result<Any> {
112 unsafe {
113 let packed_args_ptr = packed_args.as_ptr() as *const TVMFFIAny;
114 let mut result = Any::new();
115 let ret_code = (self.data.cell.safe_call)(
116 ObjectArc::as_raw(&self.data) as *mut FunctionObj as *mut std::ffi::c_void,
117 packed_args_ptr,
118 packed_args.len() as i32,
119 Any::as_data_ptr(&mut result),
120 );
121 if ret_code == 0 {
122 Ok(result)
123 } else {
124 Err(Error::from_raised())
125 }
126 }
127 }
128
129 pub fn call_tuple<TupleType>(&self, tuple_args: TupleType) -> Result<Any>
130 where
131 TupleType: TupleAsPackedArgs,
132 {
133 // This is a workaround for Rust's requirement that stack allocation size
134 // must be known at compile time for generic types.
135 // While we know args_len is a constant, Rust doesn't allow us to directly
136 // declare [AnyView::new(); args_len] in generic contexts.
137 //
138 // We use a small vector optimization pattern:
139 // 1. First allocate a small stack buffer (stack_args)
140 // 2. If args_len exceeds STACK_LEN, allocate a heap buffer (heap_args)
141 // 3. Use the appropriate buffer based on size
142 //
143 // Since args_len is a compile-time constant, the compiler should optimize
144 // away the unused branch, making this approach efficient.
145 const STACK_LEN: usize = 4;
146 let mut stack_args = [AnyView::new(); STACK_LEN];
147 let mut heap_args = Vec::<AnyView>::new();
148 let args_len = <TupleType as TupleAsPackedArgs>::LEN;
149 // get packed arguments
150 let packed_args: &mut [AnyView] = if args_len <= STACK_LEN {
151 &mut stack_args[..args_len]
152 } else {
153 heap_args.resize(args_len, AnyView::new());
154 &mut heap_args[..args_len]
155 };
156 (&tuple_args).fill_any_view(packed_args);
157 self.call_packed(packed_args)
158 }
159 /// Call function with compile-time known argument count
160 /// This is an optimized version of call_tuple for when the argument count
161 /// is known at compile time, avoiding the small vector optimization overhead.
162 ///
163 /// # Arguments
164 /// * `tuple_args` - The tuple arguments
165 ///
166 /// # Returns
167 /// * `Any` - The result
168 pub fn call_tuple_with_len<const LEN: usize, TupleType>(
169 &self,
170 tuple_args: TupleType,
171 ) -> Result<Any>
172 where
173 TupleType: TupleAsPackedArgs,
174 {
175 let mut packed_args = [AnyView::new(); LEN];
176 (&tuple_args).fill_any_view(&mut packed_args);
177 self.call_packed(&packed_args)
178 }
179 /// Get global function by name
180 /// This function will throw an error if the function is not found.
181 ///
182 /// # Arguments
183 /// * `name` - The name of the function
184 ///
185 /// # Returns
186 /// * `Function` - The global function
187 pub fn get_global(name: &str) -> Result<Function> {
188 unsafe {
189 let name_arg = TVMFFIByteArray::from_str(name);
190 let mut result: TVMFFIObjectHandle = ::std::ptr::null_mut();
191 crate::check_safe_call!(TVMFFIFunctionGetGlobal(&name_arg, &mut result))?;
192 if result.is_null() {
193 crate::bail!(crate::error::RUNTIME_ERROR, "Function {} not found", name);
194 }
195 Ok(Self {
196 data: ObjectArc::<FunctionObj>::from_raw(result as *mut FunctionObj),
197 })
198 }
199 }
200
201 /// Look up a reflected method of a type by type index and method name
202 ///
203 /// Methods registered through the C++ reflection registry
204 /// (`refl::ObjectDef<T>().def(...)`) live in the per-type method table
205 /// rather than the global function table. Constructors registered via
206 /// `refl::init` are reachable under the reserved name `__ffi_init__`.
207 /// For instance methods, the first packed argument is the object itself.
208 ///
209 /// `type_index` must be a registered type index (e.g. obtained from a
210 /// live object via `Any::type_index` or from a type key); the underlying
211 /// C API treats an unregistered index as a fatal error.
212 ///
213 /// # Arguments
214 /// * `type_index` - The type index of the type that owns the method
215 /// * `method_name` - The name of the method
216 ///
217 /// # Returns
218 /// * `Function` - The reflected method
219 pub fn from_type_method(type_index: i32, method_name: &str) -> Result<Function> {
220 unsafe {
221 let type_info = TVMFFIGetTypeInfo(type_index);
222 if type_info.is_null() {
223 crate::bail!(
224 crate::error::TYPE_ERROR,
225 "Cannot find type info for type_index={}",
226 type_index
227 );
228 }
229 let type_info = &*type_info;
230 for i in 0..type_info.num_methods as usize {
231 let method_info = &*type_info.methods.add(i);
232 if method_info.name.as_str() != method_name {
233 continue;
234 }
235 if !<Function as AnyCompatible>::check_any_strict(&method_info.method) {
236 crate::bail!(
237 crate::error::TYPE_ERROR,
238 "Method `{}` of type `{}` is not a Function",
239 method_name,
240 type_info.type_key.as_str()
241 );
242 }
243 // the table entry stores the method as a non-owning AnyView;
244 // copy out a strong reference
245 return Ok(<Function as AnyCompatible>::copy_from_any_view_after_check(
246 &method_info.method,
247 ));
248 }
249 crate::bail!(
250 crate::error::TYPE_ERROR,
251 "Cannot find method `{}` of type `{}`",
252 method_name,
253 type_info.type_key.as_str()
254 );
255 }
256 }
257
258 /// Look up a function-valued attribute for a concrete runtime type.
259 ///
260 /// Type attributes are not inherited from base types.
261 pub fn from_type_attr(type_index: i32, attr_name: &str) -> Result<Function> {
262 let value = crate::reflection::get_type_attr(type_index, attr_name).ok_or_else(|| {
263 crate::error::Error::new(
264 crate::error::TYPE_ERROR,
265 &format!(
266 "Cannot find type attribute `{}` for type_index={}",
267 attr_name, type_index
268 ),
269 "",
270 )
271 })?;
272 Function::try_from(value)
273 }
274
275 /// Look up a reflected method of a type by type key and method name
276 ///
277 /// Same as [`Function::from_type_method`], but resolves `type_key` to a
278 /// type index first.
279 ///
280 /// # Arguments
281 /// * `type_key` - The type key of the type that owns the method
282 /// * `method_name` - The name of the method
283 ///
284 /// # Returns
285 /// * `Function` - The reflected method
286 pub fn from_type_key_method(type_key: &str, method_name: &str) -> Result<Function> {
287 unsafe {
288 let type_key_arg = TVMFFIByteArray::from_str(type_key);
289 let mut type_index: i32 = 0;
290 crate::check_safe_call!(TVMFFITypeKeyToIndex(&type_key_arg, &mut type_index))?;
291 Self::from_type_method(type_index, method_name)
292 }
293 }
294
295 /// Register a function as a global function
296 /// # Arguments
297 /// * `name` - The name of the function
298 /// * `func` - The function to register
299 ///
300 /// # Returns
301 /// * `Result<()>` - The result of the registration
302 pub fn register_global(name: &str, func: Function) -> Result<()> {
303 unsafe {
304 let name_arg = TVMFFIByteArray::from_str(name);
305 let can_override = 0;
306 crate::check_safe_call!(TVMFFIFunctionSetGlobal(
307 &name_arg,
308 ObjectArc::as_raw(&func.data) as *mut FunctionObj as TVMFFIObjectHandle,
309 can_override
310 ))?;
311 Ok(())
312 }
313 }
314 /// Construct a function from a packed function
315 /// # Arguments
316 /// * `func` - The packed function in signature of `Fn(&[AnyView]) -> Result<Any>`
317 ///
318 /// # Returns
319 /// * `Function` - The function
320 pub fn from_packed<F>(func: F) -> Self
321 where
322 F: Fn(&[AnyView]) -> Result<Any> + 'static,
323 {
324 unsafe {
325 let callback_arc = ObjectArc::new(CallbackFunctionObjImpl::from_callback(func));
326 let func_arc = ObjectArc::<FunctionObj>::from_raw(
327 ObjectArc::into_raw(callback_arc) as *mut FunctionObj
328 );
329 Self { data: func_arc }
330 }
331 }
332
333 /// Construct a function from a typed function
334 /// # Arguments
335 /// * `func` - The typed function with function signature of `F(T0, T1, ...) -> Result<O>`
336 ///
337 /// # Returns
338 /// * `Function` - The function
339 pub fn from_typed<F, I, O>(func: F) -> Self
340 where
341 F: AsPackedCallable<I, O> + 'static,
342 {
343 let closure = move |packed_args: &[AnyView]| -> Result<Any> {
344 let ret_value = func.call_packed(packed_args)?;
345 Ok(ret_value)
346 };
347 Self::from_packed(closure)
348 }
349
350 /// # Safety
351 ///
352 /// `handle` must be a valid pointer (or null) that is compatible with
353 /// `safe_call` and `deleter`. The caller must ensure the handle outlives
354 /// the returned `Function` (or that `deleter` properly frees it).
355 pub unsafe fn from_extern_c(
356 handle: *mut std::ffi::c_void,
357 safe_call: TVMFFISafeCallType,
358 deleter: Option<unsafe extern "C" fn(*mut std::ffi::c_void)>,
359 ) -> Self {
360 unsafe {
361 let mut out_handle: TVMFFIObjectHandle = std::ptr::null_mut();
362 crate::check_safe_call!(TVMFFIFunctionCreate(
363 handle,
364 safe_call,
365 deleter,
366 &mut out_handle
367 ))
368 .unwrap();
369 Self {
370 data: ObjectArc::<FunctionObj>::from_raw(out_handle as *mut FunctionObj),
371 }
372 }
373 }
374}