use crate::any::{Any, AnyView, ArgTryFromAnyView};
use crate::error::{Error, Result, INTERNAL_ERROR};
use crate::function::FunctionObj;
use crate::object::{ObjectCore, ObjectRefCore};
use crate::rvalue_ref::RValueRef;
use crate::string::{Bytes, String};
use crate::type_traits::{AnyCompatible, ContainerElement, TypeSchema};
use tvm_ffi_sys::{TVMFFIAny, TVMFFIByteArray, TVMFFIStringFromByteArray};
#[doc(hidden)]
pub fn panic_to_error(payload: Box<dyn std::any::Any + Send>) -> Error {
let message = payload
.downcast_ref::<&str>()
.copied()
.or_else(|| {
payload
.downcast_ref::<std::string::String>()
.map(|s| s.as_str())
})
.unwrap_or("unknown payload");
Error::new(INTERNAL_ERROR, &format!("panicked: {message}"), "")
}
pub trait AsPackedCallable<I, O> {
fn call_packed(&self, packed_args: &[AnyView]) -> Result<Any>;
fn type_schema() -> std::string::String
where
Self: Sized,
{
crate::type_traits::type_schema(FunctionObj::TYPE_KEY, &[])
}
}
#[inline]
pub fn type_schema_of<Fun, I, O>(_func: &Fun) -> std::string::String
where
Fun: AsPackedCallable<I, O>,
{
Fun::type_schema()
}
#[doc(hidden)]
pub unsafe fn write_exported_str(text: Result<std::string::String>, result: *mut TVMFFIAny) -> i32 {
match text {
Ok(text) => {
let text = TVMFFIByteArray::from_str(&text);
TVMFFIStringFromByteArray(&text, result)
}
Err(error) => {
Error::set_raised(&error);
-1
}
}
}
#[doc(hidden)]
pub fn exported_metadata<Fun, I, O>(func: &Fun) -> Result<std::string::String>
where
Fun: AsPackedCallable<I, O>,
{
let type_schema = type_schema_of(func);
Ok(crate::type_traits::type_schema_metadata(&type_schema))
}
#[inline]
pub fn call_packed_callable<Fun, I, O>(func: Fun, packed_args: &[AnyView]) -> Result<Any>
where
Fun: AsPackedCallable<I, O>,
{
func.call_packed(packed_args)
}
macro_rules! impl_as_packed_callable {
($len:literal; $($t:ident),*) => {
impl<Fun, $($t,)* Out> AsPackedCallable<($($t,)*), Out> for Fun
where
Fun: Fn($($t,)*) -> Result<Out> + 'static,
Any: From<Out>,
Out: TypeSchema,
$($t: ArgTryFromAnyView),*
{
fn type_schema() -> std::string::String {
let params: &[std::string::String] = &[$(<$t as TypeSchema>::type_schema()),*];
format!(
r#"{{"type":"{}","named_args":{{"return":[{}],"params":[{}]}}}}"#,
FunctionObj::TYPE_KEY,
Out::type_schema(),
params.join(","),
)
}
fn call_packed(&self, packed_args: &[AnyView]) -> Result<Any>
{
crate::ensure!(
packed_args.len() == $len, crate::error::VALUE_ERROR,
"Expected {} arguments, got {}", $len, packed_args.len()
);
let mut _arg_iter = packed_args.iter().enumerate();
let ret_value = self(
$({
let (i, view) = _arg_iter.next().unwrap();
$t::try_from_any_view(view, i)?
}),*
)?;
Ok(Any::from(ret_value))
}
}
}
}
impl_as_packed_callable!(0;);
impl_as_packed_callable!(1; T0);
impl_as_packed_callable!(2; T0, T1);
impl_as_packed_callable!(3; T0, T1, T2);
impl_as_packed_callable!(4; T0, T1, T2, T3);
impl_as_packed_callable!(5; T0, T1, T2, T3, T4);
impl_as_packed_callable!(6; T0, T1, T2, T3, T4, T5);
impl_as_packed_callable!(7; T0, T1, T2, T3, T4, T5, T6);
impl_as_packed_callable!(8; T0, T1, T2, T3, T4, T5, T6, T7);
pub trait IntoArgHolder {
type Target;
fn into_arg_holder(self) -> Self::Target;
}
crate::impl_into_arg_holder_default!(
(),
bool,
i8,
i16,
i32,
i64,
isize,
u8,
u16,
u32,
u64,
usize,
f32,
f64,
String,
Bytes,
crate::big_int::BigInt,
Any,
crate::DLDataType,
crate::DLDevice
);
impl IntoArgHolder for &str {
type Target = String;
fn into_arg_holder(self) -> Self::Target {
String::from(self)
}
}
impl IntoArgHolder for &[u8] {
type Target = Bytes;
fn into_arg_holder(self) -> Self::Target {
Bytes::from(self)
}
}
pub trait IntoArgHolderTuple {
type Target;
fn into_arg_holder_tuple(self) -> Self::Target;
}
macro_rules! impl_into_arg_holder_tuple {
( $($T:ident),* ; $($idx:tt),* ) => {
impl<$($T),*> $crate::function_internal::IntoArgHolderTuple for ($($T,)*)
where
$($T: IntoArgHolder),* {
type Target = ($($T::Target,)*);
fn into_arg_holder_tuple(self) -> Self::Target {
($(self.$idx.into_arg_holder(),)*)
}
}
};
}
impl_into_arg_holder_tuple!(;);
impl_into_arg_holder_tuple!(T0; 0);
impl_into_arg_holder_tuple!(T0, T1; 0, 1);
impl_into_arg_holder_tuple!(T0, T1, T2; 0, 1, 2);
impl_into_arg_holder_tuple!(T0, T1, T2, T3; 0, 1, 2, 3);
impl_into_arg_holder_tuple!(T0, T1, T2, T3, T4; 0, 1, 2, 3, 4);
impl_into_arg_holder_tuple!(T0, T1, T2, T3, T4, T5; 0, 1, 2, 3, 4, 5);
impl_into_arg_holder_tuple!(T0, T1, T2, T3, T4, T5, T6; 0, 1, 2, 3, 4, 5, 6);
impl_into_arg_holder_tuple!(T0, T1, T2, T3, T4, T5, T6, T7; 0, 1, 2, 3, 4, 5, 6, 7);
pub trait ArgIntoRef {
type Target;
fn to_ref(&self) -> &Self::Target;
}
#[doc(hidden)]
pub trait PackedArg {
fn as_packed_arg(&self) -> AnyView<'_>;
}
impl<T: AnyCompatible> PackedArg for T {
#[inline]
fn as_packed_arg(&self) -> AnyView<'_> {
AnyView::from(self)
}
}
impl PackedArg for Any {
#[inline]
fn as_packed_arg(&self) -> AnyView<'_> {
AnyView::from(self)
}
}
impl<T> PackedArg for RValueRef<T>
where
T: ObjectRefCore + AnyCompatible,
{
#[inline]
fn as_packed_arg(&self) -> AnyView<'_> {
AnyView::from(self)
}
}
crate::impl_arg_into_ref!(
(),
bool,
i8,
i16,
i32,
i64,
isize,
u8,
u16,
u32,
u64,
usize,
f32,
f64,
String,
Bytes,
crate::big_int::BigInt,
Any,
crate::DLDataType,
crate::DLDevice
);
impl<T: AnyCompatible> IntoArgHolder for Option<T> {
type Target = Self;
fn into_arg_holder(self) -> Self::Target {
self
}
}
impl<'a, T: AnyCompatible> IntoArgHolder for &'a Option<T> {
type Target = &'a Option<T>;
fn into_arg_holder(self) -> Self::Target {
self
}
}
impl<T: AnyCompatible> ArgIntoRef for Option<T> {
type Target = Self;
fn to_ref(&self) -> &Self::Target {
self
}
}
impl<T: AnyCompatible> ArgIntoRef for &Option<T> {
type Target = Option<T>;
fn to_ref(&self) -> &Self::Target {
self
}
}
impl<T: ContainerElement + Clone> IntoArgHolder for crate::Array<T> {
type Target = crate::Array<T>;
fn into_arg_holder(self) -> Self::Target {
self
}
}
impl<'a, T: ContainerElement + Clone> IntoArgHolder for &'a crate::Array<T> {
type Target = &'a crate::Array<T>;
fn into_arg_holder(self) -> Self::Target {
self
}
}
impl<T: ContainerElement + Clone> ArgIntoRef for crate::Array<T> {
type Target = crate::Array<T>;
fn to_ref(&self) -> &Self::Target {
self
}
}
impl<T: ContainerElement + Clone> ArgIntoRef for &crate::Array<T> {
type Target = crate::Array<T>;
fn to_ref(&self) -> &Self::Target {
self
}
}
impl<T> IntoArgHolder for RValueRef<T>
where
T: ObjectRefCore + AnyCompatible,
{
type Target = Self;
fn into_arg_holder(self) -> Self::Target {
self
}
}
impl<T> ArgIntoRef for RValueRef<T>
where
T: ObjectRefCore + AnyCompatible,
{
type Target = Self;
fn to_ref(&self) -> &Self::Target {
self
}
}
impl<K: ContainerElement, V: ContainerElement> IntoArgHolder for crate::Map<K, V> {
type Target = crate::Map<K, V>;
fn into_arg_holder(self) -> Self::Target {
self
}
}
impl<'a, K: ContainerElement, V: ContainerElement> IntoArgHolder for &'a crate::Map<K, V> {
type Target = &'a crate::Map<K, V>;
fn into_arg_holder(self) -> Self::Target {
self
}
}
impl<K: ContainerElement, V: ContainerElement> ArgIntoRef for crate::Map<K, V> {
type Target = crate::Map<K, V>;
fn to_ref(&self) -> &Self::Target {
self
}
}
impl<K: ContainerElement, V: ContainerElement> ArgIntoRef for &crate::Map<K, V> {
type Target = crate::Map<K, V>;
fn to_ref(&self) -> &Self::Target {
self
}
}
impl<T: ContainerElement> IntoArgHolder for crate::List<T> {
type Target = crate::List<T>;
fn into_arg_holder(self) -> Self::Target {
self
}
}
impl<'a, T: ContainerElement> IntoArgHolder for &'a crate::List<T> {
type Target = &'a crate::List<T>;
fn into_arg_holder(self) -> Self::Target {
self
}
}
impl<T: ContainerElement> ArgIntoRef for crate::List<T> {
type Target = crate::List<T>;
fn to_ref(&self) -> &Self::Target {
self
}
}
impl<T: ContainerElement> ArgIntoRef for &crate::List<T> {
type Target = crate::List<T>;
fn to_ref(&self) -> &Self::Target {
self
}
}
pub trait TupleAsPackedArgs {
const LEN: usize;
fn fill_any_view<'a>(&'a self, any_view: &mut [AnyView<'a>]);
}
macro_rules! impl_tuple_as_packed_args {
( $len:expr; $($T:ident),* ; $($idx:tt),* ) => {
impl<$($T),*> TupleAsPackedArgs for ($($T,)*)
where
$(
$T: ArgIntoRef,
$T::Target: PackedArg,
)*
{
const LEN: usize = $len;
fn fill_any_view<'a>(&'a self, _any_view: &mut [AnyView<'a>]) {
$(
_any_view[$idx] = self.$idx.to_ref().as_packed_arg();
)*
}
}
};
}
impl_tuple_as_packed_args!(0;;);
impl_tuple_as_packed_args!(1; T0; 0);
impl_tuple_as_packed_args!(2; T0, T1; 0, 1);
impl_tuple_as_packed_args!(3; T0, T1, T2; 0, 1, 2);
impl_tuple_as_packed_args!(4; T0, T1, T2, T3; 0, 1, 2, 3);
impl_tuple_as_packed_args!(5; T0, T1, T2, T3, T4; 0, 1, 2, 3, 4);
impl_tuple_as_packed_args!(6; T0, T1, T2, T3, T4, T5; 0, 1, 2, 3, 4, 5);
impl_tuple_as_packed_args!(7; T0, T1, T2, T3, T4, T5, T6; 0, 1, 2, 3, 4, 5, 6);
impl_tuple_as_packed_args!(8; T0, T1, T2, T3, T4, T5, T6, T7; 0, 1, 2, 3, 4, 5, 6, 7);