use std::fmt;
use std::io;
use std::sync::Arc;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum DType {
F64,
F32,
F16,
BF16,
I64,
I32,
I16,
I8,
U64,
U32,
U16,
U8,
Bool,
}
impl DType {
pub const fn size(self) -> usize {
match self {
DType::F64 | DType::I64 | DType::U64 => 8,
DType::F32 | DType::I32 | DType::U32 => 4,
DType::F16 | DType::BF16 | DType::I16 | DType::U16 => 2,
DType::I8 | DType::U8 | DType::Bool => 1,
}
}
}
#[derive(Clone)]
pub struct Tensor {
pub name: String,
dtype: DType,
shape: Vec<usize>,
read: Arc<dyn Fn() -> io::Result<Vec<u8>> + Send + Sync>,
}
impl Tensor {
pub(crate) fn new(
name: String,
dtype: DType,
shape: Vec<usize>,
read: impl Fn() -> io::Result<Vec<u8>> + Send + Sync + 'static,
) -> Self {
Self {
name,
dtype,
shape,
read: Arc::new(read),
}
}
pub fn dtype(&self) -> DType {
self.dtype
}
pub fn shape(&self) -> &[usize] {
&self.shape
}
pub fn num_elements(&self) -> usize {
self.shape.iter().product()
}
pub fn byte_len(&self) -> usize {
self.num_elements() * self.dtype.size()
}
pub fn read(&self) -> io::Result<Vec<u8>> {
(self.read)().map_err(|err| named(&self.name, err))
}
pub fn into_parts(
self,
) -> (
String,
DType,
Vec<usize>,
impl Fn() -> io::Result<Vec<u8>> + Send + Sync + 'static,
) {
let Self {
name,
dtype,
shape,
read,
} = self;
let context = name.clone();
(name, dtype, shape, move || {
read().map_err(|err| named(&context, err))
})
}
}
impl fmt::Debug for Tensor {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Tensor")
.field("name", &self.name)
.field("dtype", &self.dtype)
.field("shape", &self.shape)
.finish_non_exhaustive()
}
}
fn named(name: &str, err: io::Error) -> io::Error {
if name.is_empty() {
return err;
}
io::Error::new(err.kind(), format!("tensor '{name}': {err}"))
}