This is an automated email from the ASF dual-hosted git repository. jroesch pushed a commit to branch rust-tvm in repository https://gitbox.apache.org/repos/asf/incubator-tvm.git
commit 62b6d1bac749e53d40fd999955b496feec486079 Author: Jared Roesch <jroe...@octoml.ai> AuthorDate: Mon Jun 8 13:42:32 2020 -0700 Convert external macro to procmacro --- rust/macros/src/external.rs | 163 +++++++++++++++++++++++++++++++++++++++++ rust/macros/src/lib.rs | 1 + rust/macros/src/object.rs | 58 +++++++-------- rust/macros/src/util.rs | 11 +++ rust/tvm-rt/Cargo.toml | 1 - rust/tvm-rt/src/context.rs | 5 +- rust/tvm-rt/src/errors.rs | 2 + rust/tvm-rt/src/function.rs | 11 +-- rust/tvm-rt/src/lib.rs | 2 + rust/tvm-rt/src/module.rs | 29 ++++---- rust/tvm-rt/src/object/mod.rs | 14 ++-- rust/tvm-rt/src/string.rs | 5 +- rust/tvm-rt/src/to_boxed_fn.rs | 36 ++++----- 13 files changed, 255 insertions(+), 83 deletions(-) diff --git a/rust/macros/src/external.rs b/rust/macros/src/external.rs new file mode 100644 index 0000000..989cc6a --- /dev/null +++ b/rust/macros/src/external.rs @@ -0,0 +1,163 @@ +/* + * 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::env; +use quote::quote; +use proc_macro2::Span; +use syn::parse::{Parse, ParseStream, Result}; + +use syn::{Ident, Meta, FnArg, Generics, TraitItemMethod, Lit, NestedMeta, Type, ReturnType, Pat}; + +struct External { + tvm_name: String, + ident: Ident, + generics: Generics, + inputs: Vec<FnArg>, + ret_type: ReturnType, +} + +impl Parse for External { + fn parse(input: ParseStream) -> Result<Self> { + let method: TraitItemMethod = input.parse()?; + assert_eq!(method.attrs.len(), 1); + let sig = method.sig; + let tvm_name = method.attrs[0].parse_meta()?; + let tvm_name = match tvm_name { + Meta::List(meta_list) => { + let name = meta_list.path.get_ident() + .expect("name"); + assert_eq!(name.to_string(), "name".to_string()); + match meta_list.nested.first() { + Some(NestedMeta::Lit(Lit::Str(lit))) => lit.value(), + _ => panic!(), + } + } + _ => panic!() + }; + assert_eq!(method.default, None); + assert!(method.semi_token != None); + let ident = sig.ident; + let generics = sig.generics; + let inputs = sig.inputs.iter().map(|param| param.clone()).collect(); + let ret_type = sig.output; + + Ok(External { + tvm_name, + ident, + generics, + inputs, + ret_type, + }) + } +} + +struct ExternalInput { + externs: Vec<External>, +} + +impl Parse for ExternalInput { + fn parse(input: ParseStream) -> Result<Self> { + let mut externs: Vec<External> = Vec::new(); + + loop { + if input.is_empty() { break; } + externs.push(input.parse()?); + } + + Ok(ExternalInput { externs }) + } +} + + pub fn macro_impl(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let ext_input = syn::parse_macro_input!(input as ExternalInput); + + let tvm_rt_crate = if env::var("CARGO_PKG_NAME").unwrap() == "tvm-rt" { + quote!( crate ) + } else { + quote!( tvm_rt ) + }; + + let err_type = quote! { #tvm_rt_crate::Error }; + + let mut items = Vec::new(); + + for external in &ext_input.externs { + let name = &external.ident; + let global_name = format!("global_{}", external.ident); + let global_name = Ident::new(&global_name, Span::call_site()); + let ext_name = &external.tvm_name; + + let ty_params: Vec<syn::TypeParam> = + external.generics.params.iter().map(|ty_param| + match ty_param { + syn::GenericParam::Type(param) => param.clone(), + _ => panic!() + }).collect(); + + let args = &external.inputs; + + let (args, tys): (Vec<Ident>, Vec<Type>) = + args.iter().map(|arg| { + match arg { + FnArg::Typed(pat_type) => { + match &*pat_type.pat { + Pat::Ident(pat_ident) => { + let ident: Ident = pat_ident.ident.clone(); + let ty: Type = *pat_type.ty.clone(); + (ident, ty) + }, + _ => panic!() + } + }, + _ => panic!(), + } + }).unzip(); + + let ret_type = match &external.ret_type { + ReturnType::Type(_, rtype) => *rtype.clone(), + _ => panic!() + }; + + let global = quote! { + #[allow(non_upper_case_globals)] + static #global_name: ::once_cell::sync::Lazy<&'static #tvm_rt_crate::Function> = + ::once_cell::sync::Lazy::new(|| { + #tvm_rt_crate::Function::get(#ext_name) + .expect(concat!("unable to load external function", stringify!(#ext_name), "from TVM registry.")) + }); + }; + + items.push(global); + + let wrapper = quote! { + pub fn #name<#(#ty_params),*>(#(#args : #tys),*) -> Result<#ret_type, #err_type> { + let func_ref: &#tvm_rt_crate::Function = &#global_name; + let func_ref: Box<dyn Fn(#(#tys),*) -> Result<#ret_type, #err_type>> = func_ref.to_boxed_fn(); + let res: #ret_type = func_ref(#(#args),*)?; + Ok(res) + } + }; + + items.push(wrapper); + } + + proc_macro::TokenStream::from(quote! { + #(#items + )* + }) + } diff --git a/rust/macros/src/lib.rs b/rust/macros/src/lib.rs index d0ac1ca..603e1ce 100644 --- a/rust/macros/src/lib.rs +++ b/rust/macros/src/lib.rs @@ -22,6 +22,7 @@ use proc_macro::TokenStream; mod external; mod import_module; mod object; +mod util; #[proc_macro] pub fn import_module(input: TokenStream) -> TokenStream { diff --git a/rust/macros/src/object.rs b/rust/macros/src/object.rs index 670d326..bee22c3 100644 --- a/rust/macros/src/object.rs +++ b/rust/macros/src/object.rs @@ -23,7 +23,10 @@ use quote::quote; use syn::DeriveInput; use syn::Ident; +use crate::util::get_tvm_rt_crate; + pub fn macro_impl(input: proc_macro::TokenStream) -> TokenStream { + let tvm_rt_crate = get_tvm_rt_crate(); let derive_input = syn::parse_macro_input!(input as DeriveInput); let payload_id = derive_input.ident; @@ -63,7 +66,7 @@ pub fn macro_impl(input: proc_macro::TokenStream) -> TokenStream { let base = base.expect("should be present"); let expanded = quote! { - unsafe impl tvm_rt::object::IsObject for #payload_id { + unsafe impl #tvm_rt_crate::object::IsObject for #payload_id { const TYPE_KEY: &'static str = #type_key; fn as_object<'s>(&'s self) -> &'s Object { @@ -72,9 +75,9 @@ pub fn macro_impl(input: proc_macro::TokenStream) -> TokenStream { } #[derive(Clone)] - pub struct #ref_id(Option<tvm_rt::object::ObjectPtr<#payload_id>>); + pub struct #ref_id(Option<#tvm_rt_crate::object::ObjectPtr<#payload_id>>); - impl tvm_rt::object::ToObjectRef for #ref_id { + impl #tvm_rt_crate::object::ToObjectRef for #ref_id { fn to_object_ref(&self) -> ObjectRef { ObjectRef(self.0.as_ref().map(|o| o.upcast())) } @@ -88,25 +91,25 @@ pub fn macro_impl(input: proc_macro::TokenStream) -> TokenStream { } } - impl std::convert::TryFrom<tvm_rt::RetValue> for #ref_id { - type Error = tvm_rt::Error; + impl std::convert::TryFrom<#tvm_rt_crate::RetValue> for #ref_id { + type Error = #tvm_rt_crate::Error; - fn try_from(ret_val: tvm_rt::RetValue) -> Result<#ref_id, Self::Error> { + fn try_from(ret_val: #tvm_rt_crate::RetValue) -> Result<#ref_id, Self::Error> { use std::convert::TryInto; let oref: ObjectRef = ret_val.try_into()?; - let ptr = oref.0.ok_or(tvm_rt::Error::Null)?; + let ptr = oref.0.ok_or(#tvm_rt_crate::Error::Null)?; let ptr = ptr.downcast::<#payload_id>()?; Ok(#ref_id(Some(ptr))) } } - impl<'a> From<#ref_id> for tvm_rt::ArgValue<'a> { - fn from(object_ref: #ref_id) -> tvm_rt::ArgValue<'a> { + impl<'a> From<#ref_id> for #tvm_rt_crate::ArgValue<'a> { + fn from(object_ref: #ref_id) -> #tvm_rt_crate::ArgValue<'a> { use std::ffi::c_void; let object_ptr = &object_ref.0; match object_ptr { None => { - tvm_rt::ArgValue:: + #tvm_rt_crate::ArgValue:: ObjectHandle(std::ptr::null::<c_void>() as *mut c_void) } Some(value) => value.clone().into() @@ -114,40 +117,40 @@ pub fn macro_impl(input: proc_macro::TokenStream) -> TokenStream { } } - impl<'a> From<&#ref_id> for tvm_rt::ArgValue<'a> { - fn from(object_ref: &#ref_id) -> tvm_rt::ArgValue<'a> { + impl<'a> From<&#ref_id> for #tvm_rt_crate::ArgValue<'a> { + fn from(object_ref: &#ref_id) -> #tvm_rt_crate::ArgValue<'a> { let oref: #ref_id = object_ref.clone(); - tvm_rt::ArgValue::<'a>::from(oref) + #tvm_rt_crate::ArgValue::<'a>::from(oref) } } - impl<'a> std::convert::TryFrom<tvm_rt::ArgValue<'a>> for #ref_id { - type Error = tvm_rt::Error; + impl<'a> std::convert::TryFrom<#tvm_rt_crate::ArgValue<'a>> for #ref_id { + type Error = #tvm_rt_crate::Error; - fn try_from(arg_value: tvm_rt::ArgValue<'a>) -> Result<#ref_id, Self::Error> { + fn try_from(arg_value: #tvm_rt_crate::ArgValue<'a>) -> Result<#ref_id, Self::Error> { use std::convert::TryInto; let optr = arg_value.try_into()?; Ok(#ref_id(Some(optr))) } } - impl<'a> std::convert::TryFrom<&tvm_rt::ArgValue<'a>> for #ref_id { - type Error = tvm_rt::Error; + impl<'a> std::convert::TryFrom<&#tvm_rt_crate::ArgValue<'a>> for #ref_id { + type Error = #tvm_rt_crate::Error; - fn try_from(arg_value: &tvm_rt::ArgValue<'a>) -> Result<#ref_id, Self::Error> { + fn try_from(arg_value: &#tvm_rt_crate::ArgValue<'a>) -> Result<#ref_id, Self::Error> { use std::convert::TryInto; let optr = arg_value.try_into()?; Ok(#ref_id(Some(optr))) } } - impl From<#ref_id> for tvm_rt::RetValue { - fn from(object_ref: #ref_id) -> tvm_rt::RetValue { + impl From<#ref_id> for #tvm_rt_crate::RetValue { + fn from(object_ref: #ref_id) -> #tvm_rt_crate::RetValue { use std::ffi::c_void; let object_ptr = &object_ref.0; match object_ptr { None => { - tvm_rt::RetValue::ObjectHandle(std::ptr::null::<c_void>() as *mut c_void) + #tvm_rt_crate::RetValue::ObjectHandle(std::ptr::null::<c_void>() as *mut c_void) } Some(value) => value.clone().into() } @@ -158,14 +161,3 @@ pub fn macro_impl(input: proc_macro::TokenStream) -> TokenStream { TokenStream::from(expanded) } - -// impl TryFrom<RetValue> for Var { -// type Error = anyhow::Error; - -// fn try_from(ret_val: RetValue) -> Result<Var, Self::Error> { -// let oref: ObjectRef = ret_val.try_into()?; -// let var_ptr = oref.0.ok_or(anyhow!("null ptr"))?; -// let var_ptr = var_ptr.downcast::<VarNode>()?; -// Ok(Var(Some(var_ptr))) -// } -// } diff --git a/rust/macros/src/util.rs b/rust/macros/src/util.rs new file mode 100644 index 0000000..c07c073 --- /dev/null +++ b/rust/macros/src/util.rs @@ -0,0 +1,11 @@ +use std::env; +use quote::quote; +use proc_macro2::TokenStream; + +pub fn get_tvm_rt_crate() -> TokenStream { + if env::var("CARGO_PKG_NAME").unwrap() == "tvm-rt" { + quote!( crate ) + } else { + quote!( tvm_rt ) + } +} diff --git a/rust/tvm-rt/Cargo.toml b/rust/tvm-rt/Cargo.toml index 417f256..b234da1 100644 --- a/rust/tvm-rt/Cargo.toml +++ b/rust/tvm-rt/Cargo.toml @@ -30,7 +30,6 @@ edition = "2018" [dependencies] thiserror = "^1.0" -anyhow = "^1.0" lazy_static = "1.1" ndarray = "0.12" num-traits = "0.2" diff --git a/rust/tvm-rt/src/context.rs b/rust/tvm-rt/src/context.rs index ea4cffa..0c01d91 100644 --- a/rust/tvm-rt/src/context.rs +++ b/rust/tvm-rt/src/context.rs @@ -30,8 +30,9 @@ macro_rules! impl_device_attrs { }; } -external_func! { - fn get_device_attr(device_type: i32, device_id: i32, device_kind: i32) -> i32 as "runtime.GetDeviceAttr"; +crate::external! { + #[name("runtime.GetDeviceAttr")] + fn get_device_attr(device_type: i32, device_id: i32, device_kind: i32) -> i32; } impl ContextExt for Context { diff --git a/rust/tvm-rt/src/errors.rs b/rust/tvm-rt/src/errors.rs index f081258..414484d 100644 --- a/rust/tvm-rt/src/errors.rs +++ b/rust/tvm-rt/src/errors.rs @@ -60,6 +60,8 @@ pub enum Error { Downcast(#[from] tvm_sys::errors::ValueDowncastError), #[error("raw pointer passed across boundary was null")] Null, + #[error("failed to load module due to invalid path {0}")] + ModuleLoadPath(String), } impl Error { diff --git a/rust/tvm-rt/src/function.rs b/rust/tvm-rt/src/function.rs index b0122ff..4b34bc1 100644 --- a/rust/tvm-rt/src/function.rs +++ b/rust/tvm-rt/src/function.rs @@ -25,7 +25,6 @@ //! //! See the tests and examples repository for more examples. -use anyhow::Result; use lazy_static::lazy_static; use std::convert::TryFrom; use std::{ @@ -44,6 +43,8 @@ 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; @@ -137,7 +138,7 @@ impl Function { } /// Calls the function that created from `Builder`. - pub fn invoke<'a>(&self, arg_buf: Vec<ArgValue<'a>>) -> Result<RetValue> { + pub fn invoke<'a>(&self, arg_buf: Vec<ArgValue<'a>>) -> Result<RetValue, Error> { 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(); @@ -263,7 +264,7 @@ impl<'a> TryFrom<&ArgValue<'a>> for Function { /// 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<()> +pub fn register<F, I, O, S: Into<String>>(f: F, name: S) -> Result<(), Error> where F: ToFunction<I, O>, F: Typed<I, O>, @@ -274,7 +275,7 @@ where /// 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<()> +pub fn register_override<F, I, O, S: Into<String>>(f: F, name: S, override_: bool) -> Result<(), Error> where F: ToFunction<I, O>, F: Typed<I, O>, @@ -323,7 +324,7 @@ mod tests { function::register_override(constfn, "constfn".to_owned(), true).unwrap(); let func = Function::get("constfn").unwrap(); - let func = func.to_boxed_fn::<dyn Fn() -> Result<i32>>(); + let func = func.to_boxed_fn::<dyn Fn() -> Result<i32, Error>>(); let ret = func().unwrap(); assert_eq!(ret, 10); } diff --git a/rust/tvm-rt/src/lib.rs b/rust/tvm-rt/src/lib.rs index 9b64eb6..70a8efd 100644 --- a/rust/tvm-rt/src/lib.rs +++ b/rust/tvm-rt/src/lib.rs @@ -57,6 +57,8 @@ pub use tvm_sys::byte_array::ByteArray; pub use tvm_sys::datatype::DataType; use tvm_sys::ffi; +pub use tvm_macros::external; + // Macro to check the return call to TVM runtime shared library. #[macro_export] macro_rules! check_call { diff --git a/rust/tvm-rt/src/module.rs b/rust/tvm-rt/src/module.rs index 2abccc7..b8b56f4 100644 --- a/rust/tvm-rt/src/module.rs +++ b/rust/tvm-rt/src/module.rs @@ -26,10 +26,10 @@ use std::{ ptr, }; -use anyhow::{anyhow, ensure, Error}; use tvm_sys::ffi; use crate::{errors, function::Function}; +use crate::errors::Error; const ENTRY_FUNC: &str = "__tvm_main__"; @@ -43,12 +43,12 @@ pub struct Module { entry_func: Option<Function>, } -external_func! { - fn runtime_enabled(target: CString) -> i32 as "runtime.RuntimeEnabled"; -} +crate::external! { + #[name("runtime.RuntimeEnabled")] + fn runtime_enabled(target: CString) -> i32; -external_func! { - fn load_from_file(file_name: CString, format: CString) -> Module as "runtime.ModuleLoadFromFile"; + #[name("runtime.ModuleLoadFromFile")] + fn load_from_file(file_name: CString, format: CString) -> Module; } impl Module { @@ -76,12 +76,13 @@ impl Module { query_import as c_int, &mut fhandle as *mut _ )); - ensure!( - !fhandle.is_null(), - errors::NullHandleError { + + if !fhandle.is_null() { + return Err(errors::NullHandleError { name: name.into_string()?.to_string() - } - ); + }) + } + Ok(Function::new(fhandle)) } @@ -97,13 +98,15 @@ impl Module { .extension() .unwrap_or_else(|| std::ffi::OsStr::new("")) .to_str() - .ok_or_else(|| anyhow!("Bad module load path: `{}`.", path.as_ref().display()))?, + .ok_or_else(|| Error::ModuleLoadPath(path.as_ref().display())) )?; + let cpath = CString::new( path.as_ref() .to_str() - .ok_or_else(|| anyhow!("Bad module load path: `{}`.", path.as_ref().display()))?, + .ok_or_else(|| Error::ModuleLoadPath(path.as_ref().display())) )?; + let module = load_from_file(cpath, ext)?; Ok(module) } diff --git a/rust/tvm-rt/src/object/mod.rs b/rust/tvm-rt/src/object/mod.rs index 9dcf836..6ddfe16 100644 --- a/rust/tvm-rt/src/object/mod.rs +++ b/rust/tvm-rt/src/object/mod.rs @@ -3,7 +3,7 @@ use std::convert::TryInto; use std::ffi::CString; use crate::errors::Error; -use crate::external_func; +use crate::external; use tvm_sys::{ArgValue, RetValue}; @@ -87,10 +87,12 @@ impl<'a> From<&ObjectRef> for ArgValue<'a> { } } -external_func! { - fn debug_print(object: ObjectRef) -> CString as "ir.DebugPrint"; +external! { + #[name("ir.DebugPrint")] + fn debug_print(object: ObjectRef) -> CString; } -external_func! { - fn as_text(object: ObjectRef) -> CString as "ir.TextPrinter"; -} +// external! { +// #[name("ir.TextPrinter")] +// fn as_text(object: ObjectRef) -> CString; +// } diff --git a/rust/tvm-rt/src/string.rs b/rust/tvm-rt/src/string.rs index ac80625..ce1cee6 100644 --- a/rust/tvm-rt/src/string.rs +++ b/rust/tvm-rt/src/string.rs @@ -2,7 +2,8 @@ use std::ffi::{CString, NulError}; use std::os::raw::c_char; use super::{Object, ObjectPtr, ObjectRef}; -use crate as tvm_rt; +use super::errors::Error; + use tvm_macros::Object; #[repr(C)] @@ -43,7 +44,7 @@ impl String { } } - pub fn to_string(&self) -> anyhow::Result<std::string::String> { + pub fn to_string(&self) -> Result<std::string::String, Error> { let string = self.to_cstring()?.into_string()?; Ok(string) } diff --git a/rust/tvm-rt/src/to_boxed_fn.rs b/rust/tvm-rt/src/to_boxed_fn.rs index d6ea96d..d2dde67 100644 --- a/rust/tvm-rt/src/to_boxed_fn.rs +++ b/rust/tvm-rt/src/to_boxed_fn.rs @@ -25,24 +25,23 @@ //! //! See the tests and examples repository for more examples. -use anyhow::Result; - pub use tvm_sys::{ffi, ArgValue, RetValue}; -use crate::Module; +use crate::{Module, errors}; use super::function::Function; +type Result<T> = std::result::Result<T, errors::Error>; + pub trait ToBoxedFn { fn to_boxed_fn(func: &'static Function) -> Box<Self>; } use std::convert::{TryFrom, TryInto}; -impl<E, O> ToBoxedFn for dyn Fn() -> Result<O> +impl<O> ToBoxedFn for dyn Fn() -> Result<O> where - E: std::error::Error + Send + Sync + 'static, - O: TryFrom<RetValue, Error = E>, + O: TryFrom<RetValue, Error = errors::Error>, { fn to_boxed_fn(func: &'static Function) -> Box<Self> { Box::new(move || { @@ -54,11 +53,10 @@ where } } -impl<E, A, O> ToBoxedFn for dyn Fn(A) -> Result<O> +impl<A, O> ToBoxedFn for dyn Fn(A) -> Result<O> where - E: std::error::Error + Send + Sync + 'static, A: Into<ArgValue<'static>>, - O: TryFrom<RetValue, Error = E>, + O: TryFrom<RetValue, Error = errors::Error>, { fn to_boxed_fn(func: &'static Function) -> Box<Self> { Box::new(move |a: A| { @@ -71,12 +69,11 @@ where } } -impl<E, A, B, O> ToBoxedFn for dyn Fn(A, B) -> Result<O> +impl<A, B, O> ToBoxedFn for dyn Fn(A, B) -> Result<O> where - E: std::error::Error + Send + Sync + 'static, A: Into<ArgValue<'static>>, B: Into<ArgValue<'static>>, - O: TryFrom<RetValue, Error = E>, + O: TryFrom<RetValue, Error = errors::Error>, { fn to_boxed_fn(func: &'static Function) -> Box<Self> { Box::new(move |a: A, b: B| { @@ -90,13 +87,12 @@ where } } -impl<E, A, B, C, O> ToBoxedFn for dyn Fn(A, B, C) -> Result<O> +impl<A, B, C, O> ToBoxedFn for dyn Fn(A, B, C) -> Result<O> where - E: std::error::Error + Send + Sync + 'static, A: Into<ArgValue<'static>>, B: Into<ArgValue<'static>>, C: Into<ArgValue<'static>>, - O: TryFrom<RetValue, Error = E>, + O: TryFrom<RetValue, Error = errors::Error>, { fn to_boxed_fn(func: &'static Function) -> Box<Self> { Box::new(move |a: A, b: B, c: C| { @@ -111,14 +107,13 @@ where } } -impl<E, A, B, C, D, O> ToBoxedFn for dyn Fn(A, B, C, D) -> Result<O> +impl<A, B, C, D, O> ToBoxedFn for dyn Fn(A, B, C, D) -> Result<O> where - E: std::error::Error + Send + Sync + 'static, A: Into<ArgValue<'static>>, B: Into<ArgValue<'static>>, C: Into<ArgValue<'static>>, D: Into<ArgValue<'static>>, - O: TryFrom<RetValue, Error = E>, + O: TryFrom<RetValue, Error = errors::Error>, { fn to_boxed_fn(func: &'static Function) -> Box<Self> { Box::new(move |a: A, b: B, c: C, d: D| { @@ -183,7 +178,7 @@ impl<'a, 'm> Builder<'a, 'm> { self } - /// Sets an output for a function that requirs a mutable output to be provided. + /// Sets an output for a function that requires a mutable output to be provided. /// See the `basics` in tests for an example. pub fn set_output<T>(&mut self, ret: T) -> &mut Self where @@ -214,8 +209,7 @@ impl<'a, 'm> From<&'m mut Module> for Builder<'a, 'm> { } #[cfg(test)] mod tests { - use crate::function::{self, Function}; - use anyhow::Result; + use crate::function::{self, Function, Result}; #[test] fn to_boxed_fn0() {