pub use carton_macros::{for_each_carton_type, for_each_numeric_carton_type};
use serde::{de::Visitor, Deserialize, Serialize};
use std::collections::HashMap;
use crate::conversion_utils::{ConvertFromWithContext, ConvertIntoWithContext};
use lunchbox::types::{MaybeSend, MaybeSync};
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub struct SealHandle(pub(crate) u64);
#[derive(Default, Serialize, Deserialize)]
pub struct LoadOpts {
pub override_runner_name: Option<String>,
pub override_required_framework_version: Option<String>,
pub override_runner_opts: Option<HashMap<String, RunnerOpt>>,
pub visible_device: Device,
}
pub type RunnerOpt = crate::info::RunnerOpt;
#[derive(Debug, Clone)]
pub enum Device {
CPU,
GPU {
uuid: Option<String>,
},
}
impl Default for Device {
#[cfg(not(target_family = "wasm"))]
fn default() -> Self {
Device::maybe_from_index(0)
}
#[cfg(target_family = "wasm")]
fn default() -> Self {
Device::GPU { uuid: None }
}
}
impl Device {
#[cfg(target_family = "wasm")]
pub fn maybe_from_str(s: &str) -> crate::error::Result<Self> {
if s.to_lowercase() == "cpu" {
Ok(Device::CPU)
} else {
Ok(Device::GPU { uuid: None })
}
}
#[cfg(not(target_family = "wasm"))]
pub fn maybe_from_str(s: &str) -> crate::error::Result<Self> {
use crate::error::CartonError;
if let Ok(index) = s.parse::<u32>() {
return Ok(Self::maybe_from_index(index));
}
if s.to_lowercase() == "cpu" {
return Ok(Device::CPU);
}
if s.starts_with("GPU-") || s.starts_with("MIG-GPU-") {
return Ok(Device::GPU {
uuid: Some(s.to_string()),
});
}
Err(CartonError::InvalidDeviceFormat(s.to_string()))
}
#[cfg(not(target_family = "wasm"))]
pub fn maybe_from_index(i: u32) -> Self {
match crate::cuda::get_uuid_for_device(i) {
Some(uuid) => Device::GPU { uuid: Some(uuid) },
None => Device::CPU,
}
}
}
impl ToString for Device {
fn to_string(&self) -> String {
match self {
Device::CPU => "cpu".into(),
Device::GPU { uuid } => uuid.as_ref().unwrap_or(&"gpu".into()).to_owned(),
}
}
}
impl Serialize for Device {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(&self.to_string())
}
}
struct DeviceDeserializeVisitor;
impl<'de> Visitor<'de> for DeviceDeserializeVisitor {
type Value = Device;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a string that identifies a device")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Device::maybe_from_str(v).map_err(|e| E::custom(e))
}
}
impl<'de> Deserialize<'de> for Device {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
deserializer.deserialize_str(DeviceDeserializeVisitor)
}
}
pub type PackOpts<T> = crate::info::PackOpts<T>;
pub type CartonInfo<T> = crate::info::CartonInfo<T>;
for_each_numeric_carton_type! {
pub enum Tensor<Storage> where Storage: TensorStorage {
$($CartonType(Storage::TypedStorage::<$RustType>),)*
String(Storage::TypedStringStorage),
NestedTensor(Vec<Tensor<Storage>>)
}
}
for_each_carton_type! {
impl Clone for Tensor<GenericStorage> {
fn clone(&self) -> Self {
match self {
$(
Self::$CartonType(item) => Self::$CartonType(item.clone()),
)*
Self::NestedTensor(item) => Self::NestedTensor(item.clone()),
}
}
}
}
for_each_numeric_carton_type! {
impl<T, U, C> ConvertFromWithContext<Tensor<T>, C> for Tensor<U>
where
T: TensorStorage,
U: TensorStorage,
C: Copy,
U::TypedStringStorage: ConvertFromWithContext<T::TypedStringStorage, C>,
$(
U::TypedStorage<$RustType>: ConvertFromWithContext<T::TypedStorage<$RustType>, C>,
)*
{
fn from(item: Tensor<T>, context: C) -> Self {
match item {
$(
Tensor::$CartonType(item) => Self::$CartonType(item.convert_into_with_context(context)),
)*
Tensor::String(item) => Self::String(item.convert_into_with_context(context)),
Tensor::NestedTensor(item) => Self::NestedTensor(item.convert_into_with_context(context))
}
}
}
}
for_each_carton_type! {
impl<Storage: TensorStorage> std::fmt::Debug for Tensor<Storage> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
$(
Self::$CartonType(item) => f.debug_tuple(stringify!($CartonType)).field(&item.view()).finish(),
)*
Self::NestedTensor(item) => f.debug_tuple("NestedTensor").field(item).finish(),
}
}
}
}
for_each_carton_type! {
impl<Storage: TensorStorage, Storage2: TensorStorage> PartialEq<Tensor<Storage2>> for Tensor<Storage> {
fn eq(&self, other: &Tensor<Storage2>) -> bool {
match (self, other) {
$(
(Self::$CartonType(me), Tensor::<Storage2>::$CartonType(other)) => me.view() == other.view(),
)*
(Self::NestedTensor(me), Tensor::<Storage2>::NestedTensor(other)) => std::iter::zip(me, other).map(|(a, b)| a == b).all(|v| v),
_ => false,
}
}
}
}
pub trait TensorStorage {
type TypedStorage<T>: TypedStorage<T> + MaybeSend + MaybeSync
where
T: MaybeSend + MaybeSync;
type TypedStringStorage: TypedStorage<String> + MaybeSend + MaybeSync;
}
pub trait TypedStorage<T> {
fn view(&self) -> ndarray::ArrayViewD<T>;
fn view_mut(&mut self) -> ndarray::ArrayViewMutD<T>;
}
pub type DataType = crate::info::DataType;
pub struct GenericStorage;
impl TensorStorage for GenericStorage {
type TypedStorage<T> = ndarray::ArrayD<T> where T: MaybeSend + MaybeSync;
type TypedStringStorage = ndarray::ArrayD<String>;
}
impl<T> TypedStorage<T> for ndarray::ArrayD<T> {
fn view(&self) -> ndarray::ArrayViewD<T> {
self.view()
}
fn view_mut(&mut self) -> ndarray::ArrayViewMutD<T> {
self.view_mut()
}
}
impl<Other, T, C> ConvertFromWithContext<Other, C> for ndarray::ArrayD<T>
where
Other: TypedStorage<T>,
T: Clone,
C: Copy,
{
fn from(value: Other, _context: C) -> Self {
value.view().to_owned()
}
}