use crate::{Device, FloatMeta, grad::TensorMeta};
use std::fmt::Debug;
pub trait DTypeKind<D: Device>: Sized {
type Scalar: Send + Sync + Clone + Copy + 'static;
type Storage: Storage<D, Self>;
type Meta: TensorMeta<D, Self>;
type DType: Send + Sync + Clone + Copy + 'static + PartialEq + Eq + Debug + Default;
const KIND: KindTag;
}
pub trait Storage<D: Device, K: DTypeKind<D>>: Send + Sync + 'static {
fn dtype(&self) -> K::DType;
fn device(&self) -> &D;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum DType {
F32,
F64,
I32,
U8,
U32,
Bool,
}
impl DType {
pub fn is_float(&self) -> bool {
matches!(self, DType::F32 | DType::F64)
}
pub fn is_int(&self) -> bool {
matches!(self, DType::I32 | DType::U8 | DType::U32)
}
pub fn is_bool(&self) -> bool {
matches!(self, DType::Bool)
}
pub fn kind(&self) -> KindTag {
match self {
DType::F32 | DType::F64 => KindTag::Float,
DType::I32 | DType::U8 | DType::U32 => KindTag::Int,
DType::Bool => KindTag::Bool,
}
}
pub fn size_in_bytes(&self) -> usize {
match self {
DType::F32 => 4,
DType::F64 => 8,
DType::I32 => 4,
DType::U8 => 1,
DType::U32 => 4,
DType::Bool => 1,
}
}
pub fn as_float(&self) -> FloatDType {
match self {
DType::F32 => FloatDType::F32,
DType::F64 => FloatDType::F64,
_ => panic!("DType::{:?} is not a float dtype", self),
}
}
pub fn as_int(&self) -> IntDType {
match self {
DType::I32 => IntDType::I32,
DType::U8 => IntDType::U8,
DType::U32 => IntDType::U32,
_ => panic!("DType::{:?} is not an int dtype", self),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum KindTag {
Float,
Int,
Bool,
}
pub struct Float;
pub struct Int;
pub struct Bool;
impl<D: Device> DTypeKind<D> for Float {
type Scalar = f64;
type Storage = D::FloatStorage;
type Meta = FloatMeta<D>;
type DType = FloatDType;
const KIND: KindTag = KindTag::Float;
}
impl<D: Device> DTypeKind<D> for Int {
type Scalar = i64;
type Storage = D::IntStorage;
type Meta = ();
type DType = IntDType;
const KIND: KindTag = KindTag::Int;
}
impl<D: Device> DTypeKind<D> for Bool {
type Scalar = bool;
type Storage = D::BoolStorage;
type Meta = ();
type DType = BoolDType;
const KIND: KindTag = KindTag::Bool;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum FloatDType {
#[default]
F32,
F64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum IntDType {
#[default]
I32,
U8,
U32,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum BoolDType {
#[default]
Bool,
}
impl Into<DType> for FloatDType {
fn into(self) -> DType {
match self {
FloatDType::F32 => DType::F32,
FloatDType::F64 => DType::F64,
}
}
}
impl Into<DType> for IntDType {
fn into(self) -> DType {
match self {
IntDType::I32 => DType::I32,
IntDType::U8 => DType::U8,
IntDType::U32 => DType::U32,
}
}
}
impl Into<DType> for BoolDType {
fn into(self) -> DType {
match self {
BoolDType::Bool => DType::Bool,
}
}
}