use std::pin::Pin;
use executorch_sys as sys;
use crate::memory::{MemoryAllocator, MemoryAllocatorExt, Storable, Storage};
use crate::tensor::{RawTensor, TensorAny, TensorBase};
use crate::util::{
ArrayRef, Destroy, FfiChar, IntoCpp, IntoRust, NonTriviallyMovable, __ArrayRefImpl, chars2str,
};
use crate::{Error, Result};
#[repr(u32)]
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub enum Tag {
None = sys::Tag::Tag_None as u32,
Tensor = sys::Tag::Tag_Tensor as u32,
String = sys::Tag::Tag_String as u32,
Double = sys::Tag::Tag_Double as u32,
Int = sys::Tag::Tag_Int as u32,
Bool = sys::Tag::Tag_Bool as u32,
ListBool = sys::Tag::Tag_ListBool as u32,
ListDouble = sys::Tag::Tag_ListDouble as u32,
ListInt = sys::Tag::Tag_ListInt as u32,
ListTensor = sys::Tag::Tag_ListTensor as u32,
ListScalar = sys::Tag::Tag_ListScalar as u32,
ListOptionalTensor = sys::Tag::Tag_ListOptionalTensor as u32,
}
impl IntoRust for sys::Tag {
type RsType = Tag;
fn rs(self) -> Self::RsType {
match self {
sys::Tag::Tag_None => Tag::None,
sys::Tag::Tag_Tensor => Tag::Tensor,
sys::Tag::Tag_String => Tag::String,
sys::Tag::Tag_Double => Tag::Double,
sys::Tag::Tag_Int => Tag::Int,
sys::Tag::Tag_Bool => Tag::Bool,
sys::Tag::Tag_ListBool => Tag::ListBool,
sys::Tag::Tag_ListDouble => Tag::ListDouble,
sys::Tag::Tag_ListInt => Tag::ListInt,
sys::Tag::Tag_ListTensor => Tag::ListTensor,
sys::Tag::Tag_ListScalar => Tag::ListScalar,
sys::Tag::Tag_ListOptionalTensor => Tag::ListOptionalTensor,
}
}
}
pub struct EValue<'a>(NonTriviallyMovable<'a, sys::EValueStorage>);
impl<'a> EValue<'a> {
#[cfg(feature = "alloc")]
unsafe fn new_impl(init: impl FnOnce(sys::EValueRefMut)) -> Self {
let init = |ptr: *mut sys::EValueStorage| init(sys::EValueRefMut { ptr: ptr as *mut _ });
Self(unsafe { NonTriviallyMovable::new_boxed(init) })
}
#[cfg(feature = "alloc")]
pub fn new(value: impl IntoEValue<'a>) -> Self {
value.into_evalue()
}
unsafe fn new_in_storage_impl(
init: impl FnOnce(sys::EValueRefMut),
storage: Pin<&'a mut Storage<EValue>>,
) -> Self {
let init = |ptr: *mut sys::EValueStorage| init(sys::EValueRefMut { ptr: ptr as *mut _ });
Self(unsafe { NonTriviallyMovable::new_in_storage(init, storage) })
}
pub fn new_in_storage(
value: impl IntoEValue<'a>,
storage: Pin<&'a mut Storage<EValue>>,
) -> Self {
value.into_evalue_in_storage(storage)
}
pub fn new_in_allocator(
value: impl IntoEValue<'a>,
allocator: &'a dyn MemoryAllocator<'a>,
) -> Self {
let storage = allocator
.allocate_pinned()
.ok_or(Error::MemoryAllocationFailed)
.unwrap();
Self::new_in_storage(value, storage)
}
pub(crate) unsafe fn from_inner_ref(value: sys::EValueRef) -> Self {
let value = value.ptr as *const sys::EValueStorage;
assert!(!value.is_null());
let value = unsafe { &*value };
Self(NonTriviallyMovable::from_ref(value))
}
#[cfg(feature = "alloc")]
#[allow(unused)]
pub(crate) unsafe fn move_from(value: sys::EValueRefMut) -> Self {
Self(unsafe {
NonTriviallyMovable::new_boxed(|p: *mut sys::EValueStorage| {
sys::executorch_EValue_move(value, sys::EValueRefMut { ptr: p as *mut _ })
})
})
}
#[cfg(feature = "alloc")]
pub fn none() -> Self {
unsafe { EValue::new_impl(|p| sys::executorch_EValue_new_none(p)) }
}
pub fn none_in_storage(storage: Pin<&'a mut Storage<EValue>>) -> Self {
unsafe { EValue::new_in_storage_impl(|p| sys::executorch_EValue_new_none(p), storage) }
}
pub fn is_none(&self) -> bool {
self.tag() == Tag::None
}
#[inline]
#[track_caller]
pub fn as_i64(&self) -> i64 {
self.try_into().unwrap()
}
#[inline]
#[track_caller]
pub fn as_i64_list(&self) -> &[i64] {
self.try_into().unwrap()
}
#[inline]
#[track_caller]
pub fn as_f64(&self) -> f64 {
self.try_into().unwrap()
}
#[inline]
#[track_caller]
pub fn as_f64_list(&self) -> &[f64] {
self.try_into().unwrap()
}
#[inline]
#[track_caller]
pub fn as_bool(&self) -> bool {
self.try_into().unwrap()
}
#[inline]
#[track_caller]
pub fn as_bool_list(&self) -> &[bool] {
self.try_into().unwrap()
}
#[inline]
#[track_caller]
pub fn as_chars(&self) -> &[std::ffi::c_char] {
self.try_into().unwrap()
}
#[inline]
#[track_caller]
pub fn as_str(&self) -> &str {
self.try_into().unwrap()
}
#[cfg(feature = "std")]
#[inline]
#[track_caller]
pub fn to_cstr(&self) -> std::ffi::CString {
self.try_into().unwrap()
}
#[inline]
#[track_caller]
pub fn as_tensor(&self) -> TensorAny<'_> {
self.try_into().unwrap()
}
#[inline]
#[track_caller]
pub fn as_tensor_list(&self) -> TensorList<'_> {
self.try_into().unwrap()
}
#[inline]
#[track_caller]
pub fn as_optional_tensor_list(&self) -> OptionalTensorList<'_> {
self.try_into().unwrap()
}
pub fn tag(&self) -> Tag {
unsafe { sys::executorch_EValue_tag(self.cpp()) }.rs()
}
}
impl Destroy for sys::EValueStorage {
unsafe fn destroy(&mut self) {
unsafe {
sys::executorch_EValue_destructor(sys::EValueRefMut {
ptr: self as *mut Self as *mut _,
})
}
}
}
impl IntoCpp for &EValue<'_> {
type CppType = sys::EValueRef;
fn cpp(self) -> Self::CppType {
sys::EValueRef {
ptr: self.0.as_ref() as *const sys::EValueStorage as *const _,
}
}
}
impl Storable for EValue<'_> {
type __Storage = sys::EValueStorage;
}
pub trait IntoEValue<'a> {
#[cfg(feature = "alloc")]
fn into_evalue(self) -> EValue<'a>;
fn into_evalue_in_storage(self, storage: Pin<&'a mut Storage<EValue>>) -> EValue<'a>;
}
impl<'a> IntoEValue<'a> for i64 {
#[cfg(feature = "alloc")]
fn into_evalue(self) -> EValue<'a> {
unsafe { EValue::new_impl(|p| sys::executorch_EValue_new_from_i64(p, self)) }
}
fn into_evalue_in_storage(self, storage: Pin<&'a mut Storage<EValue>>) -> EValue<'a> {
unsafe {
EValue::new_in_storage_impl(|p| sys::executorch_EValue_new_from_i64(p, self), storage)
}
}
}
impl<'a> IntoEValue<'a> for &'a BoxedEvalueList<'_, i64> {
#[cfg(feature = "alloc")]
fn into_evalue(self) -> EValue<'a> {
unsafe { EValue::new_impl(|p| sys::executorch_EValue_new_from_i64_list(p, &self.0)) }
}
fn into_evalue_in_storage(self, storage: Pin<&'a mut Storage<EValue>>) -> EValue<'a> {
unsafe {
EValue::new_in_storage_impl(
|p| sys::executorch_EValue_new_from_i64_list(p, &self.0),
storage,
)
}
}
}
impl<'a> IntoEValue<'a> for f64 {
#[cfg(feature = "alloc")]
fn into_evalue(self) -> EValue<'a> {
unsafe { EValue::new_impl(|p| sys::executorch_EValue_new_from_f64(p, self)) }
}
fn into_evalue_in_storage(self, storage: Pin<&'a mut Storage<EValue>>) -> EValue<'a> {
unsafe {
EValue::new_in_storage_impl(|p| sys::executorch_EValue_new_from_f64(p, self), storage)
}
}
}
impl<'a> IntoEValue<'a> for &'a ArrayRef<'_, f64> {
#[cfg(feature = "alloc")]
fn into_evalue(self) -> EValue<'a> {
unsafe { EValue::new_impl(|p| sys::executorch_EValue_new_from_f64_list(p, &self.0)) }
}
fn into_evalue_in_storage(self, storage: Pin<&'a mut Storage<EValue>>) -> EValue<'a> {
unsafe {
EValue::new_in_storage_impl(
|p| sys::executorch_EValue_new_from_f64_list(p, &self.0),
storage,
)
}
}
}
impl<'a> IntoEValue<'a> for bool {
#[cfg(feature = "alloc")]
fn into_evalue(self) -> EValue<'a> {
unsafe { EValue::new_impl(|p| sys::executorch_EValue_new_from_bool(p, self)) }
}
fn into_evalue_in_storage(self, storage: Pin<&'a mut Storage<EValue>>) -> EValue<'a> {
unsafe {
EValue::new_in_storage_impl(|p| sys::executorch_EValue_new_from_bool(p, self), storage)
}
}
}
impl<'a> IntoEValue<'a> for &'a ArrayRef<'_, bool> {
#[cfg(feature = "alloc")]
fn into_evalue(self) -> EValue<'a> {
unsafe { EValue::new_impl(|p| sys::executorch_EValue_new_from_bool_list(p, &self.0)) }
}
fn into_evalue_in_storage(self, storage: Pin<&'a mut Storage<EValue>>) -> EValue<'a> {
unsafe {
EValue::new_in_storage_impl(
|p| sys::executorch_EValue_new_from_bool_list(p, &self.0),
storage,
)
}
}
}
impl<'a> IntoEValue<'a> for &'a ArrayRef<'_, FfiChar> {
#[cfg(feature = "alloc")]
fn into_evalue(self) -> EValue<'a> {
unsafe { EValue::new_impl(|p| sys::executorch_EValue_new_from_string(p, &self.0)) }
}
fn into_evalue_in_storage(self, storage: Pin<&'a mut Storage<EValue>>) -> EValue<'a> {
unsafe {
EValue::new_in_storage_impl(
|p| sys::executorch_EValue_new_from_string(p, &self.0),
storage,
)
}
}
}
impl<'a> IntoEValue<'a> for RawTensor<'a> {
#[cfg(feature = "alloc")]
fn into_evalue(self) -> EValue<'a> {
unsafe { EValue::new_impl(|p| sys::executorch_EValue_new_from_tensor(p, self.as_cpp())) }
}
fn into_evalue_in_storage(self, storage: Pin<&'a mut Storage<EValue>>) -> EValue<'a> {
unsafe {
EValue::new_in_storage_impl(
|p| sys::executorch_EValue_new_from_tensor(p, self.as_cpp()),
storage,
)
}
}
}
impl<'a> IntoEValue<'a> for &'a RawTensor<'_> {
#[cfg(feature = "alloc")]
fn into_evalue(self) -> EValue<'a> {
unsafe { EValue::new_impl(|p| sys::executorch_EValue_new_from_tensor(p, self.as_cpp())) }
}
fn into_evalue_in_storage(self, storage: Pin<&'a mut Storage<EValue>>) -> EValue<'a> {
unsafe {
EValue::new_in_storage_impl(
|p| sys::executorch_EValue_new_from_tensor(p, self.as_cpp()),
storage,
)
}
}
}
impl<'a, D> IntoEValue<'a> for TensorBase<'a, D> {
#[cfg(feature = "alloc")]
fn into_evalue(self) -> EValue<'a> {
self.0.into_evalue()
}
fn into_evalue_in_storage(self, storage: Pin<&'a mut Storage<EValue>>) -> EValue<'a> {
self.0.into_evalue_in_storage(storage)
}
}
impl<'a, D> IntoEValue<'a> for &'a TensorBase<'_, D> {
#[cfg(feature = "alloc")]
fn into_evalue(self) -> EValue<'a> {
(&self.0).into_evalue()
}
fn into_evalue_in_storage(self, storage: Pin<&'a mut Storage<EValue>>) -> EValue<'a> {
(&self.0).into_evalue_in_storage(storage)
}
}
#[cfg(feature = "tensor-ptr")]
impl<'a, D: crate::tensor::Data> IntoEValue<'a> for &'a crate::tensor::TensorPtr<'_, D> {
#[cfg(feature = "alloc")]
fn into_evalue(self) -> EValue<'a> {
self.as_tensor().into_evalue()
}
fn into_evalue_in_storage(self, storage: Pin<&'a mut Storage<EValue>>) -> EValue<'a> {
self.as_tensor().into_evalue_in_storage(storage)
}
}
impl<'a> IntoEValue<'a> for &'a BoxedEvalueList<'a, TensorAny<'a>> {
#[cfg(feature = "alloc")]
fn into_evalue(self) -> EValue<'a> {
unsafe { EValue::new_impl(|p| sys::executorch_EValue_new_from_tensor_list(p, &self.0)) }
}
fn into_evalue_in_storage(self, storage: Pin<&'a mut Storage<EValue>>) -> EValue<'a> {
unsafe {
EValue::new_in_storage_impl(
|p| sys::executorch_EValue_new_from_tensor_list(p, &self.0),
storage,
)
}
}
}
impl<'a> IntoEValue<'a> for &'a BoxedEvalueList<'a, Option<TensorAny<'a>>> {
#[cfg(feature = "alloc")]
fn into_evalue(self) -> EValue<'a> {
unsafe {
EValue::new_impl(|p| sys::executorch_EValue_new_from_optional_tensor_list(p, &self.0))
}
}
fn into_evalue_in_storage(self, storage: Pin<&'a mut Storage<EValue>>) -> EValue<'a> {
unsafe {
EValue::new_in_storage_impl(
|p| sys::executorch_EValue_new_from_optional_tensor_list(p, &self.0),
storage,
)
}
}
}
#[cfg(feature = "alloc")]
impl<'a, T> From<T> for EValue<'a>
where
T: IntoEValue<'a>,
{
fn from(val: T) -> Self {
val.into_evalue()
}
}
impl TryFrom<&EValue<'_>> for i64 {
type Error = Error;
fn try_from(value: &EValue) -> Result<Self> {
if value.tag() == Tag::Int {
Ok(unsafe { sys::executorch_EValue_as_i64(value.cpp()) })
} else {
Err(Error::InvalidType)
}
}
}
impl<'a> TryFrom<&'a EValue<'_>> for &'a [i64] {
type Error = Error;
fn try_from(value: &'a EValue) -> Result<Self> {
if value.tag() == Tag::ListInt {
Ok(unsafe { sys::executorch_EValue_as_i64_list(value.cpp()).as_slice() })
} else {
Err(Error::InvalidType)
}
}
}
impl TryFrom<&EValue<'_>> for f64 {
type Error = Error;
fn try_from(value: &EValue) -> Result<Self> {
if value.tag() == Tag::Double {
Ok(unsafe { sys::executorch_EValue_as_f64(value.cpp()) })
} else {
Err(Error::InvalidType)
}
}
}
impl<'a> TryFrom<&'a EValue<'_>> for &'a [f64] {
type Error = Error;
fn try_from(value: &'a EValue) -> Result<Self> {
if value.tag() == Tag::ListDouble {
Ok(unsafe { sys::executorch_EValue_as_f64_list(value.cpp()).as_slice() })
} else {
Err(Error::InvalidType)
}
}
}
impl TryFrom<&EValue<'_>> for bool {
type Error = Error;
fn try_from(value: &EValue) -> Result<Self> {
if value.tag() == Tag::Bool {
Ok(unsafe { sys::executorch_EValue_as_bool(value.cpp()) })
} else {
Err(Error::InvalidType)
}
}
}
impl<'a> TryFrom<&'a EValue<'_>> for &'a [bool] {
type Error = Error;
fn try_from(value: &'a EValue) -> Result<Self> {
if value.tag() == Tag::ListBool {
Ok(unsafe { sys::executorch_EValue_as_bool_list(value.cpp()).as_slice() })
} else {
Err(Error::InvalidType)
}
}
}
impl<'a> TryFrom<&'a EValue<'_>> for &'a [std::ffi::c_char] {
type Error = Error;
fn try_from(value: &'a EValue) -> Result<Self> {
if value.tag() == Tag::String {
let chars = unsafe { sys::executorch_EValue_as_string(value.cpp()).as_slice() };
let chars = FfiChar::slice_to_ffi(chars);
Ok(chars)
} else {
Err(Error::InvalidType)
}
}
}
impl<'a> TryFrom<&'a EValue<'_>> for &'a str {
type Error = Error;
fn try_from(value: &'a EValue) -> Result<Self> {
let chars: &[std::ffi::c_char] = value.try_into()?;
chars2str(chars).map_err(|_| Error::InvalidString)
}
}
#[cfg(feature = "std")]
impl<'a> TryFrom<&'a EValue<'_>> for std::ffi::CString {
type Error = Error;
fn try_from(value: &'a EValue) -> Result<Self> {
let chars: &[std::ffi::c_char] = value.try_into()?;
crate::util::chars2cstring(chars).ok_or(Error::InvalidString)
}
}
impl<'a> TryFrom<&'a EValue<'_>> for TensorAny<'a> {
type Error = Error;
fn try_from(value: &'a EValue) -> Result<Self> {
if value.tag() == Tag::Tensor {
let tensor = unsafe { sys::executorch_EValue_as_tensor(value.cpp()) };
Ok(unsafe { TensorAny::from_inner_ref(tensor) })
} else {
Err(Error::InvalidType)
}
}
}
impl<'a> TryFrom<&'a EValue<'_>> for TensorList<'a> {
type Error = Error;
fn try_from(value: &'a EValue) -> Result<Self> {
if value.tag() == Tag::ListTensor {
let list = unsafe { sys::executorch_EValue_as_tensor_list(value.cpp()) };
Ok(unsafe { Self::from_array_ref(list) })
} else {
Err(Error::InvalidType)
}
}
}
impl<'a> TryFrom<&'a EValue<'_>> for OptionalTensorList<'a> {
type Error = Error;
fn try_from(value: &'a EValue) -> Result<Self> {
if value.tag() == Tag::ListOptionalTensor {
let list = unsafe { sys::executorch_EValue_as_optional_tensor_list(value.cpp()) };
Ok(unsafe { Self::from_array_ref(list) })
} else {
Err(Error::InvalidType)
}
}
}
#[cfg(feature = "ndarray")]
impl std::fmt::Debug for EValue<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let mut st = f.debug_struct("EValue");
st.field("tag", &self.tag());
match self.tag() {
Tag::Int => st.field("value", &self.as_i64()),
Tag::Double => st.field("value", &self.as_f64()),
Tag::Bool => st.field("value", &self.as_bool()),
Tag::Tensor => st.field("value", &self.as_tensor()),
Tag::String => st.field("value", &self.as_chars()),
Tag::ListInt => st.field("value", &self.as_i64_list()),
Tag::ListDouble => st.field("value", &self.as_f64_list()),
Tag::ListBool => st.field("value", &self.as_bool_list()),
Tag::ListTensor => st.field("value", &self.as_tensor_list()),
Tag::ListOptionalTensor => st.field("value", &self.as_optional_tensor_list()),
Tag::ListScalar => st.field("value", &"Unsupported type: ListScalar"),
Tag::None => st.field("value", &"None"),
};
st.finish()
}
}
pub struct TensorList<'a>(&'a [sys::TensorStorage]);
impl TensorList<'_> {
unsafe fn from_array_ref(array: sys::ArrayRefTensor) -> Self {
let data = array.data.ptr as *const sys::TensorStorage;
Self(unsafe { std::slice::from_raw_parts(data, array.len) })
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn get(&self, index: usize) -> Option<TensorAny<'_>> {
self.0.get(index).map(|t| unsafe {
TensorAny::from_inner_ref(sys::TensorRef {
ptr: t as *const sys::TensorStorage as *const _,
})
})
}
}
#[cfg(feature = "ndarray")]
impl std::fmt::Debug for TensorList<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let mut l = f.debug_list();
for i in 0..self.len() {
l.entry(&self.get(i).unwrap());
}
l.finish()
}
}
pub struct OptionalTensorList<'a>(&'a [sys::OptionalTensorStorage]);
impl OptionalTensorList<'_> {
unsafe fn from_array_ref(array: sys::ArrayRefOptionalTensor) -> Self {
let data = array.data.ptr as *const sys::OptionalTensorStorage;
Self(unsafe { std::slice::from_raw_parts(data, array.len) })
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn get(&self, index: usize) -> Option<Option<TensorAny<'_>>> {
self.0.get(index).map(|tensor| {
let tensor = sys::OptionalTensorRef {
ptr: tensor as *const sys::OptionalTensorStorage as *const _,
};
let tensor = unsafe { sys::executorch_OptionalTensor_get(tensor) };
if tensor.ptr.is_null() {
return None;
}
Some(unsafe { TensorAny::from_inner_ref(tensor) })
})
}
}
#[cfg(feature = "ndarray")]
impl std::fmt::Debug for OptionalTensorList<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let mut l = f.debug_list();
for i in 0..self.len() {
l.entry(&self.get(i).unwrap());
}
l.finish()
}
}
mod boxed_list;
pub use boxed_list::*;
#[cfg(test)]
mod tests {
use crate::memory::BufferMemoryAllocator;
use crate::storage;
#[cfg(feature = "tensor-ptr")]
use crate::tensor::TensorPtr;
use crate::tensor::{SizesType, Tensor, TensorImpl};
use crate::tests::{check_send, check_sync};
use super::*;
#[test]
fn none() {
#[cfg(feature = "alloc")]
{
let evalue = EValue::none();
assert_eq!(evalue.tag(), Tag::None);
assert!(evalue.is_none());
}
{
let storage = storage!(EValue);
let evalue = EValue::none_in_storage(storage);
assert_eq!(evalue.tag(), Tag::None);
assert!(evalue.is_none());
}
}
#[test]
fn i64() {
#[cfg(feature = "alloc")]
{
let evalue = EValue::new(42);
assert_eq!(evalue.tag(), Tag::Int);
assert_eq!(evalue.as_i64(), 42);
let evalue: EValue = 17.into();
assert_eq!(evalue.tag(), Tag::Int);
assert_eq!(evalue.as_i64(), 17);
test_try_from_evalue(Tag::Int);
}
{
let storage = storage!(EValue);
let evalue = EValue::new_in_storage(17, storage);
assert_eq!(evalue.tag(), Tag::Int);
assert_eq!(evalue.as_i64(), 17);
}
}
#[test]
fn i64_list() {
#[cfg(feature = "alloc")]
{
let (evalue1, evalue2, evalue3) = (EValue::new(42), EValue::new(17), EValue::new(6));
let wrapped_vals = EValuePtrList::new([&evalue1, &evalue2, &evalue3]);
let mut unwrapped_vals = storage!(i64, (3));
let list = BoxedEvalueList::new(&wrapped_vals, unwrapped_vals.as_mut()).unwrap();
let evalue = EValue::new(&list);
assert_eq!(evalue.tag(), Tag::ListInt);
assert_eq!(evalue.as_i64_list(), &[42, 17, 6]);
test_try_from_evalue(Tag::ListInt);
}
{
let evalue1_storage = storage!(EValue);
let evalue2_storage = storage!(EValue);
let evalue3_storage = storage!(EValue);
let evalue1 = EValue::new_in_storage(42, evalue1_storage);
let evalue2 = EValue::new_in_storage(17, evalue2_storage);
let evalue3 = EValue::new_in_storage(6, evalue3_storage);
let wrapped_vals_storage = storage!(EValuePtrListElem, [3]);
let wrapped_vals =
EValuePtrList::new_in_storage([&evalue1, &evalue2, &evalue3], wrapped_vals_storage);
let unwrapped_vals = storage!(i64, [3]);
let list = BoxedEvalueList::new(&wrapped_vals, unwrapped_vals).unwrap();
let evalue_storage = storage!(EValue);
let evalue = EValue::new_in_storage(&list, evalue_storage);
assert_eq!(evalue.tag(), Tag::ListInt);
assert_eq!(evalue.as_i64_list(), &[42, 17, 6]);
}
}
#[test]
fn f64() {
#[cfg(feature = "alloc")]
{
let evalue = EValue::new(42.0);
assert_eq!(evalue.tag(), Tag::Double);
assert_eq!(evalue.as_f64(), 42.0);
test_try_from_evalue(Tag::Double);
}
{
let storage = storage!(EValue);
let evalue = EValue::new_in_storage(17.0, storage);
assert_eq!(evalue.tag(), Tag::Double);
assert_eq!(evalue.as_f64(), 17.0);
}
}
#[test]
fn f64_list() {
let list = [42.0, 17.0, 6.0];
let list = ArrayRef::from_slice(list.as_slice());
#[cfg(feature = "alloc")]
{
let evalue = EValue::new(&list);
assert_eq!(evalue.tag(), Tag::ListDouble);
assert_eq!(evalue.as_f64_list(), [42.0, 17.0, 6.0]);
test_try_from_evalue(Tag::ListDouble);
}
{
let storage = storage!(EValue);
let evalue = EValue::new_in_storage(&list, storage);
assert_eq!(evalue.tag(), Tag::ListDouble);
assert_eq!(evalue.as_f64_list(), [42.0, 17.0, 6.0]);
}
}
#[test]
fn bool() {
#[cfg(feature = "alloc")]
{
let evalue = EValue::new(true);
assert_eq!(evalue.tag(), Tag::Bool);
assert!(evalue.as_bool());
test_try_from_evalue(Tag::Bool);
}
{
let storage = storage!(EValue);
let evalue = EValue::new_in_storage(false, storage);
assert_eq!(evalue.tag(), Tag::Bool);
assert!(!evalue.as_bool());
}
}
#[test]
fn bool_list() {
let list = [true, false, true];
let list = ArrayRef::from_slice(list.as_slice());
#[cfg(feature = "alloc")]
{
let evalue = EValue::new(&list);
assert_eq!(evalue.tag(), Tag::ListBool);
assert_eq!(evalue.as_bool_list(), [true, false, true]);
test_try_from_evalue(Tag::ListBool);
}
{
let storage = storage!(EValue);
let evalue = EValue::new_in_storage(&list, storage);
assert_eq!(evalue.tag(), Tag::ListBool);
assert_eq!(evalue.as_bool_list(), [true, false, true]);
}
}
#[test]
fn string() {
let string = c"hello world!";
let chars = crate::util::cstr2chars(string);
let chars_ref = ArrayRef::from_chars(chars);
#[cfg(feature = "alloc")]
{
let evalue = EValue::new(&chars_ref);
assert_eq!(evalue.tag(), Tag::String);
assert_eq!(evalue.to_cstr().as_c_str(), string);
assert_eq!(evalue.as_str(), string.to_str().unwrap());
assert_eq!(evalue.as_chars(), chars);
test_try_from_evalue(Tag::String);
}
{
let storage = storage!(EValue);
let evalue = EValue::new_in_storage(&chars_ref, storage);
assert_eq!(evalue.tag(), Tag::String);
assert_eq!(evalue.as_str(), string.to_str().unwrap());
assert_eq!(evalue.as_chars(), chars);
}
}
#[test]
fn tensor() {
let data: [i32; 3] = [42, 17, 6];
#[cfg(feature = "alloc")]
{
let sizes = [data.len() as SizesType];
let dim_order = [0];
let strides = [1];
let tensor_impl = TensorImpl::from_slice(&sizes, &data, &dim_order, &strides).unwrap();
let tensor = Tensor::new(&tensor_impl);
let evalue = EValue::new(&tensor);
assert_eq!(evalue.tag(), Tag::Tensor);
let tensor = evalue.as_tensor().into_typed::<i32>();
let tensor_data =
unsafe { std::slice::from_raw_parts(tensor.as_data_ptr(), data.len()) };
assert_eq!(tensor_data, data);
let evalue = EValue::new(tensor);
assert_eq!(evalue.tag(), Tag::Tensor);
let tensor = evalue.as_tensor().into_typed::<i32>();
let tensor_data =
unsafe { std::slice::from_raw_parts(tensor.as_data_ptr(), data.len()) };
assert_eq!(tensor_data, data);
test_try_from_evalue(Tag::Tensor);
}
#[cfg(feature = "tensor-ptr")]
{
let tensor = TensorPtr::from_slice(&data);
let evalue = EValue::new(&tensor);
assert_eq!(evalue.tag(), Tag::Tensor);
let tensor = evalue.as_tensor().into_typed::<i32>();
let tensor_data =
unsafe { std::slice::from_raw_parts(tensor.as_data_ptr(), data.len()) };
assert_eq!(tensor_data, data);
let tensor = TensorPtr::from_slice(&data);
let evalue_storage = storage!(EValue);
let evalue = EValue::new_in_storage(&tensor, evalue_storage);
assert_eq!(evalue.tag(), Tag::Tensor);
let tensor = evalue.as_tensor().into_typed::<i32>();
let tensor_data =
unsafe { std::slice::from_raw_parts(tensor.as_data_ptr(), data.len()) };
assert_eq!(tensor_data, data);
}
{
let sizes = [data.len() as SizesType];
let dim_order = [0];
let strides = [1];
let tensor_impl = TensorImpl::from_slice(&sizes, &data, &dim_order, &strides).unwrap();
let tensor_storage = storage!(Tensor<i32>);
let tensor = Tensor::new_in_storage(&tensor_impl, tensor_storage);
let evalue_storage = storage!(EValue);
let evalue = EValue::new_in_storage(&tensor, evalue_storage);
assert_eq!(evalue.tag(), Tag::Tensor);
let tensor = evalue.as_tensor().into_typed::<i32>();
let tensor_data =
unsafe { std::slice::from_raw_parts(tensor.as_data_ptr(), data.len()) };
assert_eq!(tensor_data, data);
let evalue_storage = storage!(EValue);
let evalue = EValue::new_in_storage(tensor, evalue_storage);
assert_eq!(evalue.tag(), Tag::Tensor);
let tensor = evalue.as_tensor().into_typed::<i32>();
let tensor_data =
unsafe { std::slice::from_raw_parts(tensor.as_data_ptr(), data.len()) };
assert_eq!(tensor_data, data);
}
}
#[test]
fn tensor_list() {
let data1: [i32; 3] = [42, 17, 6];
let data2: [i32; 2] = [55, 8];
let data3: [i32; 2] = [106, 144];
#[cfg(feature = "alloc")]
{
let sizes = [data1.len() as SizesType];
let dim_order = [0];
let strides = [1];
let tensor_impl = TensorImpl::from_slice(&sizes, &data1, &dim_order, &strides).unwrap();
let tensor1 = Tensor::new(&tensor_impl);
let sizes = [data2.len() as SizesType];
let dim_order = [0];
let strides = [1];
let tensor_impl = TensorImpl::from_slice(&sizes, &data2, &dim_order, &strides).unwrap();
let tensor2 = Tensor::new(&tensor_impl);
let sizes = [data3.len() as SizesType];
let dim_order = [0];
let strides = [1];
let tensor_impl = TensorImpl::from_slice(&sizes, &data3, &dim_order, &strides).unwrap();
let tensor3 = Tensor::new(&tensor_impl);
let evalue1 = EValue::new(tensor1);
let evalue2 = EValue::new(tensor2);
let evalue3 = EValue::new(tensor3);
let wrapped_vals = EValuePtrList::new([&evalue1, &evalue2, &evalue3]);
let unwrapped_vals = storage!(TensorAny, [3]);
let list = BoxedEvalueList::new(&wrapped_vals, unwrapped_vals).unwrap();
let evalue = EValue::new(&list);
assert_eq!(evalue.tag(), Tag::ListTensor);
let tensor_list = evalue.as_tensor_list();
assert_eq!(tensor_list.len(), 3);
assert!(!tensor_list.is_empty());
for (i, data) in [data1.as_slice(), &data2, &data3].iter().enumerate() {
let tensor = tensor_list.get(i).unwrap().into_typed::<i32>();
let tensor_data =
unsafe { std::slice::from_raw_parts(tensor.as_data_ptr(), data.len()) };
assert_eq!(&tensor_data, data);
}
test_try_from_evalue(Tag::ListTensor);
}
#[cfg(feature = "tensor-ptr")]
{
let tensor1 = TensorPtr::from_slice(&data1);
let tensor2 = TensorPtr::from_slice(&data2);
let tensor3 = TensorPtr::from_slice(&data3);
let evalue1 = EValue::new(&tensor1);
let evalue2 = EValue::new(&tensor2);
let evalue3 = EValue::new(&tensor3);
let wrapped_vals = EValuePtrList::new([&evalue1, &evalue2, &evalue3]);
let unwrapped_vals = storage!(TensorAny, [3]);
let list = BoxedEvalueList::new(&wrapped_vals, unwrapped_vals).unwrap();
let evalue = EValue::new(&list);
assert_eq!(evalue.tag(), Tag::ListTensor);
let tensor_list = evalue.as_tensor_list();
assert_eq!(tensor_list.len(), 3);
assert!(!tensor_list.is_empty());
for (i, data) in [data1.as_slice(), &data2, &data3].iter().enumerate() {
let tensor = tensor_list.get(i).unwrap().into_typed::<i32>();
let tensor_data =
unsafe { std::slice::from_raw_parts(tensor.as_data_ptr(), data.len()) };
assert_eq!(&tensor_data, data);
}
}
{
let sizes = [data1.len() as SizesType];
let dim_order = [0];
let strides = [1];
let tensor_impl = TensorImpl::from_slice(&sizes, &data1, &dim_order, &strides).unwrap();
let tensor_storage = storage!(Tensor<i32>);
let tensor1 = Tensor::new_in_storage(&tensor_impl, tensor_storage);
let sizes = [data2.len() as SizesType];
let dim_order = [0];
let strides = [1];
let tensor_impl = TensorImpl::from_slice(&sizes, &data2, &dim_order, &strides).unwrap();
let tensor_storage = storage!(Tensor<i32>);
let tensor2 = Tensor::new_in_storage(&tensor_impl, tensor_storage);
let sizes = [data3.len() as SizesType];
let dim_order = [0];
let strides = [1];
let tensor_impl = TensorImpl::from_slice(&sizes, &data3, &dim_order, &strides).unwrap();
let tensor_storage = storage!(Tensor<i32>);
let tensor3 = Tensor::new_in_storage(&tensor_impl, tensor_storage);
let evalue_storage = storage!(EValue);
let evalue1 = EValue::new_in_storage(&tensor1, evalue_storage);
let evalue_storage = storage!(EValue);
let evalue2 = EValue::new_in_storage(&tensor2, evalue_storage);
let evalue_storage = storage!(EValue);
let evalue3 = EValue::new_in_storage(&tensor3, evalue_storage);
let wrapped_vals_storage = storage!(EValuePtrListElem, [3]);
let wrapped_vals =
EValuePtrList::new_in_storage([&evalue1, &evalue2, &evalue3], wrapped_vals_storage);
let unwrapped_vals = storage!(TensorAny, [3]);
let list = BoxedEvalueList::new(&wrapped_vals, unwrapped_vals).unwrap();
let evalue_storage = storage!(EValue);
let evalue = EValue::new_in_storage(&list, evalue_storage);
assert_eq!(evalue.tag(), Tag::ListTensor);
let tensor_list = evalue.as_tensor_list();
assert_eq!(tensor_list.len(), 3);
assert!(!tensor_list.is_empty());
for (i, data) in [data1.as_slice(), &data2, &data3].iter().enumerate() {
let tensor = tensor_list.get(i).unwrap().into_typed::<i32>();
let tensor_data =
unsafe { std::slice::from_raw_parts(tensor.as_data_ptr(), data.len()) };
assert_eq!(&tensor_data, data);
}
}
}
#[test]
fn optional_tensor_list() {
let data1: [i32; 3] = [42, 17, 6];
let data2: [i32; 2] = [55, 8];
let data4: [i32; 2] = [106, 144];
#[cfg(feature = "alloc")]
{
let sizes = [data1.len() as SizesType];
let dim_order = [0];
let strides = [1];
let tensor_impl = TensorImpl::from_slice(&sizes, &data1, &dim_order, &strides).unwrap();
let tensor1 = Tensor::new(&tensor_impl);
let sizes = [data2.len() as SizesType];
let dim_order = [0];
let strides = [1];
let tensor_impl = TensorImpl::from_slice(&sizes, &data2, &dim_order, &strides).unwrap();
let tensor2 = Tensor::new(&tensor_impl);
let sizes = [data4.len() as SizesType];
let dim_order = [0];
let strides = [1];
let tensor_impl = TensorImpl::from_slice(&sizes, &data4, &dim_order, &strides).unwrap();
let tensor4 = Tensor::new(&tensor_impl);
let evalue1 = EValue::new(tensor1);
let evalue2 = EValue::new(tensor2);
let evalue3 = None;
let evalue4 = EValue::new(tensor4);
let wrapped_vals = EValuePtrList::new_optional([
Some(&evalue1),
Some(&evalue2),
evalue3,
Some(&evalue4),
]);
let unwrapped_vals = storage!(Option<TensorAny>, [4]);
let list = BoxedEvalueList::new(&wrapped_vals, unwrapped_vals).unwrap();
let evalue = EValue::new(&list);
assert_eq!(evalue.tag(), Tag::ListOptionalTensor);
let tensor_list = evalue.as_optional_tensor_list();
assert_eq!(tensor_list.len(), 4);
assert!(!tensor_list.is_empty());
for (i, data) in [Some(data1.as_slice()), Some(&data2), None, Some(&data4)]
.iter()
.enumerate()
{
let tensor = tensor_list.get(i).unwrap();
assert_eq!(tensor.is_some(), data.is_some());
match (tensor, data) {
(None, None) => {}
(Some(tensor), Some(data)) => {
let tensor_data = unsafe {
std::slice::from_raw_parts(
tensor.into_typed::<i32>().as_data_ptr(),
data.len(),
)
};
assert_eq!(&tensor_data, data);
}
_ => unreachable!(),
}
}
test_try_from_evalue(Tag::ListOptionalTensor);
}
#[cfg(feature = "tensor-ptr")]
{
let tensor1 = TensorPtr::from_slice(&data1);
let tensor2 = TensorPtr::from_slice(&data2);
let tensor4 = TensorPtr::from_slice(&data4);
let evalue1 = EValue::new(&tensor1);
let evalue2 = EValue::new(&tensor2);
let evalue3 = None;
let evalue4 = EValue::new(&tensor4);
let wrapped_vals = EValuePtrList::new_optional([
Some(&evalue1),
Some(&evalue2),
evalue3,
Some(&evalue4),
]);
let unwrapped_vals = storage!(Option<TensorAny>, [4]);
let list = BoxedEvalueList::new(&wrapped_vals, unwrapped_vals).unwrap();
let evalue = EValue::new(&list);
assert_eq!(evalue.tag(), Tag::ListOptionalTensor);
let tensor_list = evalue.as_optional_tensor_list();
assert_eq!(tensor_list.len(), 4);
assert!(!tensor_list.is_empty());
for (i, data) in [Some(data1.as_slice()), Some(&data2), None, Some(&data4)]
.iter()
.enumerate()
{
let tensor = tensor_list.get(i).unwrap();
assert_eq!(tensor.is_some(), data.is_some());
match (tensor, data) {
(None, None) => {}
(Some(tensor), Some(data)) => {
let tensor_data = unsafe {
std::slice::from_raw_parts(
tensor.into_typed::<i32>().as_data_ptr(),
data.len(),
)
};
assert_eq!(&tensor_data, data);
}
_ => unreachable!(),
}
}
}
{
let sizes = [data1.len() as SizesType];
let dim_order = [0];
let strides = [1];
let tensor_impl = TensorImpl::from_slice(&sizes, &data1, &dim_order, &strides).unwrap();
let tensor_storage = storage!(Tensor<i32>);
let tensor1 = Tensor::new_in_storage(&tensor_impl, tensor_storage);
let sizes = [data2.len() as SizesType];
let dim_order = [0];
let strides = [1];
let tensor_impl = TensorImpl::from_slice(&sizes, &data2, &dim_order, &strides).unwrap();
let tensor_storage = storage!(Tensor<i32>);
let tensor2 = Tensor::new_in_storage(&tensor_impl, tensor_storage);
let sizes = [data4.len() as SizesType];
let dim_order = [0];
let strides = [1];
let tensor_impl = TensorImpl::from_slice(&sizes, &data4, &dim_order, &strides).unwrap();
let tensor_storage = storage!(Tensor<i32>);
let tensor4 = Tensor::new_in_storage(&tensor_impl, tensor_storage);
let evalue_storage = storage!(EValue);
let evalue1 = EValue::new_in_storage(&tensor1, evalue_storage);
let evalue_storage = storage!(EValue);
let evalue2 = EValue::new_in_storage(&tensor2, evalue_storage);
let evalue3 = None;
let evalue_storage = storage!(EValue);
let evalue4 = EValue::new_in_storage(&tensor4, evalue_storage);
let wrapped_vals_storage = storage!(EValuePtrListElem, [4]);
let wrapped_vals = EValuePtrList::new_optional_in_storage(
[Some(&evalue1), Some(&evalue2), evalue3, Some(&evalue4)],
wrapped_vals_storage,
);
let unwrapped_vals = storage!(Option<TensorAny>, [4]);
let list = BoxedEvalueList::new(&wrapped_vals, unwrapped_vals).unwrap();
let evalue_storage = storage!(EValue);
let evalue = EValue::new_in_storage(&list, evalue_storage);
assert_eq!(evalue.tag(), Tag::ListOptionalTensor);
let tensor_list = evalue.as_optional_tensor_list();
assert_eq!(tensor_list.len(), 4);
assert!(!tensor_list.is_empty());
for (i, data) in [Some(data1.as_slice()), Some(&data2), None, Some(&data4)]
.iter()
.enumerate()
{
let tensor = tensor_list.get(i).unwrap();
assert_eq!(tensor.is_some(), data.is_some());
match (tensor, data) {
(None, None) => {}
(Some(tensor), Some(data)) => {
let tensor_data = unsafe {
std::slice::from_raw_parts(
tensor.into_typed::<i32>().as_data_ptr(),
data.len(),
)
};
assert_eq!(&tensor_data, data);
}
_ => unreachable!(),
}
}
}
}
#[cfg(feature = "alloc")]
fn test_try_from_evalue(tag: Tag) {
let tags = [
Tag::None,
Tag::Tensor,
Tag::String,
Tag::Double,
Tag::Int,
Tag::Bool,
Tag::ListBool,
Tag::ListDouble,
Tag::ListInt,
Tag::ListTensor,
Tag::ListOptionalTensor,
];
for actual_tag in tags {
let check_evalue = |evalue: EValue<'_>| {
let same_tag = actual_tag == tag;
match tag {
Tag::None => unimplemented!(),
Tag::Tensor => assert_eq!(
same_tag,
<TensorAny as TryFrom<&EValue>>::try_from(&evalue).is_ok()
),
Tag::String => {
assert_eq!(
same_tag,
<&[std::ffi::c_char] as TryFrom<&EValue>>::try_from(&evalue).is_ok()
);
assert_eq!(
same_tag,
<&str as TryFrom<&EValue>>::try_from(&evalue).is_ok()
);
assert_eq!(
same_tag,
<std::ffi::CString as TryFrom<&EValue>>::try_from(&evalue).is_ok()
);
}
Tag::Double => assert_eq!(
same_tag,
<f64 as TryFrom<&EValue>>::try_from(&evalue).is_ok()
),
Tag::Int => assert_eq!(
same_tag,
<i64 as TryFrom<&EValue>>::try_from(&evalue).is_ok()
),
Tag::Bool => assert_eq!(
same_tag,
<bool as TryFrom<&EValue>>::try_from(&evalue).is_ok()
),
Tag::ListBool => assert_eq!(
same_tag,
<&[bool] as TryFrom<&EValue>>::try_from(&evalue).is_ok()
),
Tag::ListDouble => assert_eq!(
same_tag,
<&[f64] as TryFrom<&EValue>>::try_from(&evalue).is_ok()
),
Tag::ListInt => assert_eq!(
same_tag,
<&[i64] as TryFrom<&EValue>>::try_from(&evalue).is_ok()
),
Tag::ListTensor => assert_eq!(
same_tag,
<TensorList as TryFrom<&EValue>>::try_from(&evalue).is_ok()
),
Tag::ListOptionalTensor => assert_eq!(
same_tag,
<OptionalTensorList as TryFrom<&EValue>>::try_from(&evalue).is_ok()
),
Tag::ListScalar => unimplemented!(),
}
};
match actual_tag {
Tag::None => check_evalue(EValue::none()),
Tag::Tensor => {
let data: [i32; 3] = [42, 17, 6];
let sizes = [data.len() as SizesType];
let dim_order = [0];
let strides = [1];
let tensor_impl =
TensorImpl::from_slice(&sizes, &data, &dim_order, &strides).unwrap();
check_evalue(EValue::new(Tensor::new(&tensor_impl)));
}
Tag::String => {
let chars = ArrayRef::from_cstr(c"hello world!");
check_evalue(EValue::new(&chars))
}
Tag::Double => check_evalue(EValue::new(42.6)),
Tag::Int => check_evalue(EValue::new(17)),
Tag::Bool => check_evalue(EValue::new(true)),
Tag::ListBool => {
let bool_list = [true, false, false, true, true];
let bool_list = ArrayRef::from_slice(bool_list.as_slice());
check_evalue(EValue::new(&bool_list))
}
Tag::ListDouble => {
let f64_list = [42.2_f64, 17.6, 55.9];
let f64_list = ArrayRef::from_slice(f64_list.as_slice());
check_evalue(EValue::new(&f64_list))
}
Tag::ListInt => {
let values = [42_i64, 17, 99].map(EValue::new);
let wrapped_vals = EValuePtrList::new([&values[0], &values[1], &values[2]]);
let mut unwrapped_vals = storage!(i64, (3));
let list =
BoxedEvalueList::new(&wrapped_vals, unwrapped_vals.as_mut()).unwrap();
check_evalue(EValue::new(&list));
}
Tag::ListTensor => {
let data1: [i32; 3] = [42, 17, 6];
let sizes = [data1.len() as SizesType];
let dim_order = [0];
let strides = [1];
let tensor_impl =
TensorImpl::from_slice(&sizes, &data1, &dim_order, &strides).unwrap();
let tensor1 = Tensor::new(&tensor_impl);
let data2: [i32; 2] = [55, 8];
let sizes = [data2.len() as SizesType];
let dim_order = [0];
let strides = [1];
let tensor_impl =
TensorImpl::from_slice(&sizes, &data2, &dim_order, &strides).unwrap();
let tensor2 = Tensor::new(&tensor_impl);
let data3: [i32; 2] = [106, 144];
let sizes = [data3.len() as SizesType];
let dim_order = [0];
let strides = [1];
let tensor_impl =
TensorImpl::from_slice(&sizes, &data3, &dim_order, &strides).unwrap();
let tensor3 = Tensor::new(&tensor_impl);
let evalue1 = EValue::new(tensor1);
let evalue2 = EValue::new(tensor2);
let evalue3 = EValue::new(tensor3);
let wrapped_vals = EValuePtrList::new([&evalue1, &evalue2, &evalue3]);
let unwrapped_vals = storage!(TensorAny, [3]);
let list = BoxedEvalueList::new(&wrapped_vals, unwrapped_vals).unwrap();
check_evalue(EValue::new(&list));
}
Tag::ListOptionalTensor => {
let data1: [i32; 3] = [42, 17, 6];
let sizes = [data1.len() as SizesType];
let dim_order = [0];
let strides = [1];
let tensor_impl =
TensorImpl::from_slice(&sizes, &data1, &dim_order, &strides).unwrap();
let tensor1 = Tensor::new(&tensor_impl);
let data2: [i32; 2] = [55, 8];
let sizes = [data2.len() as SizesType];
let dim_order = [0];
let strides = [1];
let tensor_impl =
TensorImpl::from_slice(&sizes, &data2, &dim_order, &strides).unwrap();
let tensor2 = Tensor::new(&tensor_impl);
let data4: [i32; 2] = [106, 144];
let sizes = [data4.len() as SizesType];
let dim_order = [0];
let strides = [1];
let tensor_impl =
TensorImpl::from_slice(&sizes, &data4, &dim_order, &strides).unwrap();
let tensor4 = Tensor::new(&tensor_impl);
let evalue1 = EValue::new(tensor1);
let evalue2 = EValue::new(tensor2);
let evalue3 = None;
let evalue4 = EValue::new(tensor4);
let wrapped_vals = EValuePtrList::new_optional([
Some(&evalue1),
Some(&evalue2),
evalue3,
Some(&evalue4),
]);
let unwrapped_vals = storage!(Option<TensorAny>, [4]);
let list = BoxedEvalueList::new(&wrapped_vals, unwrapped_vals).unwrap();
check_evalue(EValue::new(&list));
}
Tag::ListScalar => unimplemented!(),
}
}
}
#[test]
fn new_in_allocator() {
let mut allocator_buf = [0_u8; 512];
let allocator = BufferMemoryAllocator::new(&mut allocator_buf);
let evalue_int = EValue::new_in_allocator(17, &allocator);
let evalue_float = EValue::new_in_allocator(42.6, &allocator);
assert_eq!(evalue_int.as_i64(), 17);
assert_eq!(evalue_float.as_f64(), 42.6);
}
#[test]
fn evalue_send() {
check_send::<EValue<'_>>();
}
#[test]
fn evalue_sync() {
check_sync::<EValue<'_>>();
}
}