You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tvm.apache.org by GitBox <gi...@apache.org> on 2020/06/09 16:15:45 UTC

[GitHub] [incubator-tvm] adelbertc commented on a change in pull request #5527: [Rust] Second stage of Rust Refactor

adelbertc commented on a change in pull request #5527:
URL: https://github.com/apache/incubator-tvm/pull/5527#discussion_r437142025



##########
File path: rust/macros/src/lib.rs
##########
@@ -17,121 +17,25 @@
  * under the License.
  */
 
-extern crate proc_macro;
+use proc_macro::TokenStream;
 
-use quote::quote;
-use std::{fs::File, io::Read};
-use syn::parse::{Parse, ParseStream, Result};
-use syn::LitStr;
+mod external;
+mod import_module;
+mod object;
+mod util;
 
-use std::path::PathBuf;
-
-struct ImportModule {
-    importing_file: LitStr,
+#[proc_macro]
+pub fn import_module(input: TokenStream) -> TokenStream {
+    import_module::macro_impl(input)
 }
 
-impl Parse for ImportModule {
-    fn parse(input: ParseStream) -> Result<Self> {
-        let importing_file: LitStr = input.parse()?;
-        Ok(ImportModule { importing_file })
-    }
+#[proc_macro_derive(Object, attributes(base, ref_name, type_key))]
+pub fn macro_impl(input: TokenStream) -> TokenStream {
+    // let input = proc_macro2::TokenStream::from(input);

Review comment:
       delete

##########
File path: rust/tvm-rt/src/function.rs
##########
@@ -0,0 +1,345 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+//! This module provides an idiomatic Rust API for creating and working with TVM functions.
+//!
+//! For calling an already registered TVM function use [`function::Builder`]
+//! To register a TVM packed function from Rust side either
+//! use [`function::register`] or the macro [`register_global_func`].
+//!
+//! See the tests and examples repository for more examples.
+
+use lazy_static::lazy_static;
+use std::convert::TryFrom;
+use std::{
+    collections::BTreeMap,
+    ffi::{CStr, CString},
+    mem::{self, MaybeUninit},
+    os::raw::{c_char, c_int},
+    ptr, slice, str,
+    sync::Mutex,
+};
+
+pub use tvm_sys::{ffi, ArgValue, RetValue};
+
+use crate::errors::Error;
+
+use super::to_boxed_fn::ToBoxedFn;
+use super::to_function::{ToFunction, Typed};
+
+pub type Result<T> = std::result::Result<T, Error>;
+
+lazy_static! {
+    static ref GLOBAL_FUNCTIONS: Mutex<BTreeMap<String, Option<Function>>> = {
+        let mut out_size = 0 as c_int;
+        let mut names_ptr = ptr::null_mut() as *mut *const c_char;
+        check_call!(ffi::TVMFuncListGlobalNames(
+            &mut out_size as *mut _,
+            &mut names_ptr as *mut _,
+        ));
+        let names_list = unsafe { slice::from_raw_parts(names_ptr, out_size as usize) };
+
+        let names_list: Vec<String> =
+            names_list
+            .iter()
+            .map(|&p| unsafe { CStr::from_ptr(p).to_str().unwrap().into() })
+            .collect();
+
+        // println!("{:?}", &names_list);

Review comment:
       remove

##########
File path: rust/tvm-rt/src/function.rs
##########
@@ -0,0 +1,345 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+//! This module provides an idiomatic Rust API for creating and working with TVM functions.
+//!
+//! For calling an already registered TVM function use [`function::Builder`]
+//! To register a TVM packed function from Rust side either
+//! use [`function::register`] or the macro [`register_global_func`].
+//!
+//! See the tests and examples repository for more examples.
+
+use lazy_static::lazy_static;
+use std::convert::TryFrom;
+use std::{
+    collections::BTreeMap,
+    ffi::{CStr, CString},
+    mem::{self, MaybeUninit},
+    os::raw::{c_char, c_int},
+    ptr, slice, str,
+    sync::Mutex,
+};
+
+pub use tvm_sys::{ffi, ArgValue, RetValue};
+
+use crate::errors::Error;
+
+use super::to_boxed_fn::ToBoxedFn;
+use super::to_function::{ToFunction, Typed};
+
+pub type Result<T> = std::result::Result<T, Error>;
+
+lazy_static! {
+    static ref GLOBAL_FUNCTIONS: Mutex<BTreeMap<String, Option<Function>>> = {
+        let mut out_size = 0 as c_int;
+        let mut names_ptr = ptr::null_mut() as *mut *const c_char;
+        check_call!(ffi::TVMFuncListGlobalNames(
+            &mut out_size as *mut _,
+            &mut names_ptr as *mut _,
+        ));
+        let names_list = unsafe { slice::from_raw_parts(names_ptr, out_size as usize) };
+
+        let names_list: Vec<String> =
+            names_list
+            .iter()
+            .map(|&p| unsafe { CStr::from_ptr(p).to_str().unwrap().into() })
+            .collect();
+
+        // println!("{:?}", &names_list);
+
+        let names_list = names_list
+            .into_iter()
+            .map(|p| (p, None))
+            .collect();
+
+        Mutex::new(names_list)
+    };
+}
+
+/// Wrapper around TVM function handle which includes `is_global`
+/// indicating whether the function is global or not, and `is_cloned` showing
+/// not to drop a cloned function from Rust side.
+/// The value of these fields can be accessed through their respective methods.
+#[derive(Debug, Hash)]
+pub struct Function {
+    pub(crate) handle: ffi::TVMFunctionHandle,
+    // whether the registered function is global or not.
+    is_global: bool,
+    // whether the function has been cloned from frontend or not.
+    is_cloned: bool,
+}
+
+unsafe impl Send for Function {}
+unsafe impl Sync for Function {}
+
+impl Function {
+    pub(crate) fn new(handle: ffi::TVMFunctionHandle) -> Self {
+        Function {
+            handle,
+            is_global: false,
+            is_cloned: false,
+        }
+    }
+
+    /// For a given function, it returns a function by name.
+    pub fn get<S: AsRef<str>>(name: S) -> Option<&'static Function> {
+        let mut globals = GLOBAL_FUNCTIONS.lock().unwrap();
+        globals.get_mut(name.as_ref()).and_then(|maybe_func| {
+            if maybe_func.is_none() {
+                let name = CString::new(name.as_ref()).unwrap();
+                let mut handle = ptr::null_mut() as ffi::TVMFunctionHandle;
+                check_call!(ffi::TVMFuncGetGlobal(
+                    name.as_ptr() as *const c_char,
+                    &mut handle as *mut _
+                ));
+                maybe_func.replace(Function {
+                    handle,
+                    is_global: true,
+                    is_cloned: false,
+                });
+            }
+
+            unsafe {
+                mem::transmute::<Option<&Function>, Option<&'static Function>>(maybe_func.as_ref())
+            }
+        })
+    }
+
+    /// Returns the underlying TVM function handle.
+    pub fn handle(&self) -> ffi::TVMFunctionHandle {
+        self.handle
+    }
+
+    /// Returns `true` if the underlying TVM function is global and `false` otherwise.
+    pub fn is_global(&self) -> bool {
+        self.is_global
+    }
+
+    /// Returns `true` if the underlying TVM function has been cloned
+    /// from the frontend and `false` otherwise.
+    pub fn is_cloned(&self) -> bool {
+        self.is_cloned
+    }
+
+    /// Calls the function that created from `Builder`.
+    pub fn invoke<'a>(&self, arg_buf: Vec<ArgValue<'a>>) -> Result<RetValue> {
+        let num_args = arg_buf.len();
+        let (mut values, mut type_codes): (Vec<ffi::TVMValue>, Vec<ffi::TVMTypeCode>) =
+            arg_buf.iter().map(|arg| arg.to_tvm_value()).unzip();
+
+        let mut ret_val = unsafe { MaybeUninit::uninit().assume_init() };
+        let mut ret_type_code = 0i32;
+        check_call!(ffi::TVMFuncCall(
+            self.handle,
+            values.as_mut_ptr(),
+            type_codes.as_mut_ptr() as *mut i32,
+            num_args as c_int,
+            &mut ret_val as *mut _,
+            &mut ret_type_code as *mut _
+        ));
+
+        Ok(RetValue::from_tvm_value(ret_val, ret_type_code as u32))
+    }
+
+    pub fn to_boxed_fn<F: ?Sized>(&'static self) -> Box<F>
+    where
+        F: ToBoxedFn,
+    {
+        F::to_boxed_fn(self)
+    }
+}
+
+impl Clone for Function {
+    fn clone(&self) -> Function {
+        Self {
+            handle: self.handle,
+            is_global: self.is_global,
+            is_cloned: true,
+        }
+    }
+}
+
+impl Drop for Function {
+    fn drop(&mut self) {
+        if !self.is_global && !self.is_cloned {
+            check_call!(ffi::TVMFuncFree(self.handle));
+        }
+    }
+}
+
+impl From<Function> for RetValue {
+    fn from(func: Function) -> RetValue {
+        RetValue::FuncHandle(func.handle)
+    }
+}
+
+impl TryFrom<RetValue> for Function {
+    type Error = Error;
+
+    fn try_from(ret_value: RetValue) -> Result<Function> {
+        match ret_value {
+            RetValue::FuncHandle(handle) => Ok(Function::new(handle)),
+            _ => Err(Error::downcast(
+                format!("{:?}", ret_value),
+                "FunctionHandle",
+            )),
+        }
+    }
+}
+
+impl<'a> From<Function> for ArgValue<'a> {
+    fn from(func: Function) -> ArgValue<'a> {
+        ArgValue::FuncHandle(func.handle)
+    }
+}
+
+impl<'a> TryFrom<ArgValue<'a>> for Function {
+    type Error = Error;
+
+    fn try_from(arg_value: ArgValue<'a>) -> Result<Function> {
+        match arg_value {
+            ArgValue::FuncHandle(handle) => Ok(Function::new(handle)),
+            _ => Err(Error::downcast(
+                format!("{:?}", arg_value),
+                "FunctionHandle",
+            )),
+        }
+    }
+}
+
+impl<'a> TryFrom<&ArgValue<'a>> for Function {
+    type Error = Error;
+
+    fn try_from(arg_value: &ArgValue<'a>) -> Result<Function> {
+        match arg_value {
+            ArgValue::FuncHandle(handle) => Ok(Function::new(*handle)),
+            _ => Err(Error::downcast(
+                format!("{:?}", arg_value),
+                "FunctionHandle",
+            )),
+        }
+    }
+}
+
+/// Registers a Rust function with an arbitrary type signature in
+/// the TVM registry.
+///
+///
+/// A function is convertible if and only if its arguments and return types are convertible
+/// to and from TVM values respectively.
+///
+/// Use [`register_override`] if control of overriding existing global TVM function
+/// is required, this function will panic if a function is already registered.
+///
+/// ## Example
+///
+/// ```
+/// # use tvm_rt::{ArgValue, RetValue};
+/// # use tvm_rt::function::{Function, Result, register};
+///
+/// fn sum(x: i64, y: i64, z: i64) -> i64 {
+///     x + y + z
+/// }
+///
+/// register(sum, "mysum".to_owned()).unwrap();
+/// let func = Function::get("mysum").unwrap();
+/// let boxed_fn = func.to_boxed_fn::<dyn Fn(i64, i64, i64) -> Result<i64>>();
+/// let ret = boxed_fn(10, 20, 30).unwrap();
+/// assert_eq!(ret, 60);
+/// ```
+pub fn register<F, I, O, S: Into<String>>(f: F, name: S) -> Result<()>
+where
+    F: ToFunction<I, O>,
+    F: Typed<I, O>,
+{
+    register_override(f, name, false)
+}
+
+/// Register a function with explicit control over whether to override an existing registration or not.
+///
+/// See `register` for more details on how to use the registration API.
+pub fn register_override<F, I, O, S: Into<String>>(f: F, name: S, override_: bool) -> Result<()>
+where
+    F: ToFunction<I, O>,
+    F: Typed<I, O>,
+{
+    let func = f.to_function();
+    let name = name.into();
+    let mut globals = GLOBAL_FUNCTIONS.lock().unwrap();
+    // Not sure about this code
+    let handle = func.handle();
+    globals.insert(name.clone(), Some(func));
+    let name = CString::new(name)?;
+    check_call!(ffi::TVMFuncRegisterGlobal(
+        name.into_raw(),
+        handle,
+        override_ as c_int
+    ));
+
+    Ok(())
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::function::Function;
+
+    static CANARY: &str = "runtime.ModuleLoadFromFile";
+
+    // #[test]
+    // fn list_global_func() {
+    //     assert!(GLOBAL_FUNCTIONS.lock().unwrap().contains_key(CANARY));
+    // }

Review comment:
       remove

##########
File path: rust/tvm-rt/src/object/mod.rs
##########
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+use std::convert::TryFrom;
+use std::convert::TryInto;
+use std::ffi::CString;
+
+use crate::errors::Error;
+use crate::external;
+
+use tvm_sys::{ArgValue, RetValue};
+
+mod object_ptr;
+
+pub use object_ptr::{IsObject, Object, ObjectPtr};
+
+#[derive(Clone)]
+pub struct ObjectRef(pub Option<ObjectPtr<Object>>);
+
+impl ObjectRef {
+    pub fn null() -> ObjectRef {
+        ObjectRef(None)
+    }
+}
+
+pub trait ToObjectRef {
+    fn to_object_ref(&self) -> ObjectRef;
+}
+
+impl ToObjectRef for ObjectRef {
+    fn to_object_ref(&self) -> ObjectRef {
+        self.clone()
+    }
+}
+
+impl TryFrom<RetValue> for ObjectRef {
+    type Error = Error;
+
+    fn try_from(ret_val: RetValue) -> Result<ObjectRef, Self::Error> {
+        let optr = ret_val.try_into()?;
+        Ok(ObjectRef(Some(optr)))
+    }
+}
+
+impl From<ObjectRef> for RetValue {
+    fn from(object_ref: ObjectRef) -> RetValue {
+        use std::ffi::c_void;
+        let object_ptr = &object_ref.0;
+        match object_ptr {
+            None => RetValue::ObjectHandle(std::ptr::null::<c_void>() as *mut c_void),
+            Some(value) => value.clone().into(),
+        }
+    }
+}
+
+impl<'a> std::convert::TryFrom<ArgValue<'a>> for ObjectRef {
+    type Error = Error;
+
+    fn try_from(arg_value: ArgValue<'a>) -> Result<ObjectRef, Self::Error> {
+        let optr = arg_value.try_into()?;
+        Ok(ObjectRef(Some(optr)))
+    }
+}
+
+impl<'a> std::convert::TryFrom<&ArgValue<'a>> for ObjectRef {
+    type Error = Error;
+
+    fn try_from(arg_value: &ArgValue<'a>) -> Result<ObjectRef, Self::Error> {
+        // TODO(@jroesch): remove the clone
+        let value: ArgValue<'a> = arg_value.clone();
+        ObjectRef::try_from(value)
+    }
+}
+
+impl<'a> From<ObjectRef> for ArgValue<'a> {
+    fn from(object_ref: ObjectRef) -> ArgValue<'a> {
+        use std::ffi::c_void;
+        let object_ptr = &object_ref.0;
+        match object_ptr {
+            None => ArgValue::ObjectHandle(std::ptr::null::<c_void>() as *mut c_void),
+            Some(value) => value.clone().into(),
+        }
+    }
+}
+
+impl<'a> From<&ObjectRef> for ArgValue<'a> {
+    fn from(object_ref: &ObjectRef) -> ArgValue<'a> {
+        let oref: ObjectRef = object_ref.clone();
+        ArgValue::<'a>::from(oref)
+    }
+}
+
+external! {
+    #[name("ir.DebugPrint")]
+    fn debug_print(object: ObjectRef) -> CString;
+}
+
+// external! {
+//     #[name("ir.TextPrinter")]
+//     fn as_text(object: ObjectRef) -> CString;
+// }

Review comment:
       remove

##########
File path: rust/tvm-rt/src/to_function.rs
##########
@@ -0,0 +1,359 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+//! This module provides an idiomatic Rust API for creating and working with TVM functions.
+//!
+//! For calling an already registered TVM function use [`function::Builder`]
+//! To register a TVM packed function from Rust side either
+//! use [`function::register`] or the macro [`register_global_func`].
+//!
+//! See the tests and examples repository for more examples.
+
+use std::convert::{TryFrom, TryInto};
+use std::{
+    mem::MaybeUninit,
+    os::raw::{c_int, c_void},
+    ptr, slice,
+};
+
+use super::{function::Result, Function};
+use crate::errors::Error;
+
+pub use tvm_sys::{ffi, ArgValue, RetValue};
+
+/// A trait representing whether the function arguments
+/// and return type can be assigned to a TVM packed function.
+///
+/// By splitting the conversion to function into two traits
+/// we are able to improve error reporting, by splitting the
+/// conversion of inputs and outputs to this trait.
+///
+/// And the implementation of it to `ToFunction`.
+pub trait Typed<I, O> {
+    fn args(i: &[ArgValue<'static>]) -> Result<I>;
+    fn ret(o: O) -> RetValue;
+}
+
+impl<F, O: Into<RetValue>> Typed<(), O> for F
+where
+    F: Fn() -> O,
+{
+    fn args(_args: &[ArgValue<'static>]) -> Result<()> {
+        debug_assert!(_args.len() == 0);
+        Ok(())
+    }
+
+    fn ret(o: O) -> RetValue {
+        o.into()
+    }
+}
+
+impl<F, A, O: Into<RetValue>, E> Typed<(A,), O> for F
+where
+    F: Fn(A) -> O,
+    Error: From<E>,
+    A: TryFrom<ArgValue<'static>, Error = E>,
+{
+    fn args(args: &[ArgValue<'static>]) -> Result<(A,)> {
+        debug_assert!(args.len() == 1);
+        let a: A = args[0].clone().try_into()?;
+        Ok((a,))
+    }
+
+    fn ret(o: O) -> RetValue {
+        o.into()
+    }
+}
+
+impl<F, A, B, O: Into<RetValue>, E> Typed<(A, B), O> for F
+where
+    F: Fn(A, B) -> O,
+    Error: From<E>,
+    A: TryFrom<ArgValue<'static>, Error = E>,
+    B: TryFrom<ArgValue<'static>, Error = E>,
+{
+    fn args(args: &[ArgValue<'static>]) -> Result<(A, B)> {
+        debug_assert!(args.len() == 2);
+        let a: A = args[0].clone().try_into()?;
+        let b: B = args[1].clone().try_into()?;
+        Ok((a, b))
+    }
+
+    fn ret(o: O) -> RetValue {
+        o.into()
+    }
+}
+
+impl<F, A, B, C, O: Into<RetValue>, E> Typed<(A, B, C), O> for F
+where
+    F: Fn(A, B, C) -> O,
+    Error: From<E>,
+    A: TryFrom<ArgValue<'static>, Error = E>,
+    B: TryFrom<ArgValue<'static>, Error = E>,
+    C: TryFrom<ArgValue<'static>, Error = E>,
+{
+    fn args(args: &[ArgValue<'static>]) -> Result<(A, B, C)> {
+        debug_assert!(args.len() == 3);
+        let a: A = args[0].clone().try_into()?;
+        let b: B = args[1].clone().try_into()?;
+        let c: C = args[2].clone().try_into()?;
+        Ok((a, b, c))
+    }
+
+    fn ret(o: O) -> RetValue {
+        o.into()
+    }
+}
+
+pub trait ToFunction<I, O>: Sized {
+    type Handle;
+
+    fn into_raw(self) -> *mut Self::Handle;
+
+    fn call(handle: *mut Self::Handle, args: &[ArgValue<'static>]) -> Result<RetValue>
+    where
+        Self: Typed<I, O>;
+
+    fn drop(handle: *mut Self::Handle);
+
+    fn to_function(self) -> Function
+    where
+        Self: Typed<I, O>,
+    {
+        let mut fhandle = ptr::null_mut() as ffi::TVMFunctionHandle;
+        let resource_handle = self.into_raw();
+        check_call!(ffi::TVMFuncCreateFromCFunc(
+            Some(Self::tvm_callback),
+            resource_handle as *mut _,
+            Some(Self::tvm_finalizer),
+            &mut fhandle as *mut _
+        ));
+        Function::new(fhandle)
+    }
+
+    /// The callback function which is wrapped converted by TVM
+    /// into a packed function stored in fhandle.
+    unsafe extern "C" fn tvm_callback(
+        args: *mut ffi::TVMValue,
+        type_codes: *mut c_int,
+        num_args: c_int,
+        ret: ffi::TVMRetValueHandle,
+        fhandle: *mut c_void,
+    ) -> c_int
+    where
+        Self: Typed<I, O>,
+    {
+        // turning off the incorrect linter complaints
+        #![allow(unused_assignments, unused_unsafe)]
+        let len = num_args as usize;
+        let args_list = slice::from_raw_parts_mut(args, len);
+        let type_codes_list = slice::from_raw_parts_mut(type_codes, len);
+        let mut local_args: Vec<ArgValue> = Vec::new();
+        let mut value = MaybeUninit::uninit().assume_init();
+        let mut tcode = MaybeUninit::uninit().assume_init();
+        let rust_fn = fhandle as *mut Self::Handle;
+        for i in 0..len {
+            value = args_list[i];
+            println!("{:?}", value.v_handle);
+            tcode = type_codes_list[i];
+            if tcode == ffi::TVMTypeCode_kTVMObjectHandle as c_int
+                || tcode == ffi::TVMTypeCode_kTVMPackedFuncHandle as c_int
+                || tcode == ffi::TVMTypeCode_kTVMModuleHandle as c_int
+            {
+                check_call!(ffi::TVMCbArgToReturn(
+                    &mut value as *mut _,
+                    &mut tcode as *mut _
+                ));
+                println!("{:?}", value.v_handle);
+            }
+            let arg_value = ArgValue::from_tvm_value(value, tcode as u32);
+            println!("{:?}", arg_value);
+            local_args.push(arg_value);
+        }
+
+        let rv = match Self::call(rust_fn, local_args.as_slice()) {
+            Ok(v) => v,
+            Err(msg) => {
+                crate::set_last_error(&msg);
+                return -1;
+            }
+        };
+
+        let (mut ret_val, ret_tcode) = rv.to_tvm_value();
+        let mut ret_type_code = ret_tcode as c_int;
+        check_call!(ffi::TVMCFuncSetReturn(
+            ret,
+            &mut ret_val as *mut _,
+            &mut ret_type_code as *mut _,
+            1 as c_int
+        ));
+        0
+    }
+
+    /// The finalizer which is invoked when the packed function's
+    /// reference count is zero.
+    unsafe extern "C" fn tvm_finalizer(fhandle: *mut c_void) {
+        let handle = std::mem::transmute(fhandle);
+        Self::drop(handle)
+    }
+}
+
+// /// A wrapper that is used to work around inference issues for bare functions.
+// ///
+// /// Used to implement `register_untyped`.
+// pub(self) struct RawFunction {
+//     fn_ptr: for<'a> fn (&'a [ArgValue<'static>]) -> Result<RetValue>
+// }
+
+// impl RawFunction {
+//     fn new(fn_ptr: for<'a> fn (&'a [ArgValue<'static>]) -> Result<RetValue>) -> RawFunction {
+//         RawFunction { fn_ptr: fn_ptr }
+//     }
+// }
+
+// impl Typed<&[ArgValue<'static>], ()> for RawFunction {
+//     fn args(i: &[ArgValue<'static>]) -> Result<&[ArgValue<'static>]> {
+//         Ok(i)
+//     }
+
+//     fn ret(o: O) -> RetValue;
+// }
+
+// impl ToFunction<(), ()> for RawFunction
+// {
+//     type Handle = fn(&[ArgValue<'static>]) -> Result<RetValue>;
+
+//     fn into_raw(self) -> *mut Self::Handle {
+//         self.fn_ptr as *mut Self::Handle
+//     }
+
+//     fn call(handle: *mut Self::Handle, args: &[ArgValue<'static>]) -> Result<RetValue> {
+//         let handle: Self::Handle = unsafe { std::mem::transmute(handle) };
+//         let r = handle(args);
+//         println!("afters");
+//         r
+//     }
+
+//     // Function's don't need de-allocation because the pointers are into the code section of memory.
+//     fn drop(_: *mut Self::Handle) {}
+// }
+
+impl<O, F> ToFunction<(), O> for F
+where
+    F: Fn() -> O + 'static,
+{
+    type Handle = Box<dyn Fn() -> O + 'static>;
+
+    fn into_raw(self) -> *mut Self::Handle {
+        let ptr: Box<Self::Handle> = Box::new(Box::new(self));
+        Box::into_raw(ptr)
+    }
+
+    fn call(handle: *mut Self::Handle, _: &[ArgValue<'static>]) -> Result<RetValue>
+    where
+        F: Typed<(), O>,
+    {
+        // Ideally we shouldn't need to clone, probably doesn't really matter.
+        let out = unsafe { (*handle)() };
+        Ok(F::ret(out))
+    }
+
+    fn drop(_: *mut Self::Handle) {}
+}
+
+macro_rules! to_function_instance {
+    ($(($param:ident,$index:tt),)+) => {
+        impl<F, $($param,)+ O> ToFunction<($($param,)+), O> for
+        F where F: Fn($($param,)+) -> O + 'static {
+            type Handle = Box<dyn Fn($($param,)+) -> O + 'static>;
+
+            fn into_raw(self) -> *mut Self::Handle {
+                let ptr: Box<Self::Handle> = Box::new(Box::new(self));
+                Box::into_raw(ptr)
+            }
+
+            fn call(handle: *mut Self::Handle, args: &[ArgValue<'static>]) -> Result<RetValue> where F: Typed<($($param,)+), O> {
+                // Ideally we shouldn't need to clone, probably doesn't really matter.
+                let args = F::args(args)?;
+                let out = unsafe {
+                    (*handle)($(args.$index),+)
+                };
+                Ok(F::ret(out))
+            }
+
+            fn drop(_: *mut Self::Handle) {}
+        }
+    }
+}
+
+to_function_instance!((A, 0),);
+to_function_instance!((A, 0), (B, 1),);
+to_function_instance!((A, 0), (B, 1), (C, 2),);
+to_function_instance!((A, 0), (B, 1), (C, 2), (D, 3),);
+
+#[cfg(test)]
+mod tests {
+    // use super::RawFunction;
+    use super::{Function, ToFunction, Typed};
+
+    fn zero() -> i32 {
+        10
+    }
+
+    fn helper<F, I, O>(f: F) -> Function
+    where
+        F: ToFunction<I, O>,
+        F: Typed<I, O>,
+    {
+        f.to_function()
+    }
+
+    // fn func_args(args: &[ArgValue<'static>]) -> Result<RetValue> {

Review comment:
       remove




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org