use oxmera_core::{DType, Device, Error, Result};
#[derive(Debug, Clone)]
pub enum CpuStorage {
F32(Vec<f32>),
I64(Vec<i64>),
U8(Vec<u8>),
}
impl CpuStorage {
pub fn dtype(&self) -> DType {
match self {
CpuStorage::F32(_) => DType::F32,
CpuStorage::I64(_) => DType::I64,
CpuStorage::U8(_) => DType::U8,
}
}
pub fn len(&self) -> usize {
match self {
CpuStorage::F32(v) => v.len(),
CpuStorage::I64(v) => v.len(),
CpuStorage::U8(v) => v.len(),
}
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn f32s(&self) -> Result<&[f32]> {
match self {
CpuStorage::F32(v) => Ok(v),
other => Err(Error::DTypeMismatch {
expected: DType::F32,
got: other.dtype(),
op: "CpuStorage::f32s",
}),
}
}
pub fn i64s(&self) -> Result<&[i64]> {
match self {
CpuStorage::I64(v) => Ok(v),
other => Err(Error::DTypeMismatch {
expected: DType::I64,
got: other.dtype(),
op: "CpuStorage::i64s",
}),
}
}
}
#[cfg(target_os = "macos")]
#[derive(Debug)]
pub struct MetalBuffer {
buffer: metal::Buffer,
pub device_index: usize,
}
#[cfg(target_os = "macos")]
impl MetalBuffer {
pub fn new(buffer: metal::Buffer, device_index: usize) -> Self {
Self {
buffer,
device_index,
}
}
pub fn buffer(&self) -> &metal::Buffer {
&self.buffer
}
}
#[cfg(target_os = "macos")]
#[allow(unsafe_code)]
unsafe impl Send for MetalBuffer {}
#[cfg(target_os = "macos")]
#[allow(unsafe_code)]
unsafe impl Sync for MetalBuffer {}
#[derive(Debug)]
pub enum StorageData {
Cpu(CpuStorage),
#[cfg(target_os = "macos")]
Metal(MetalBuffer),
}
#[derive(Debug)]
pub struct Storage {
data: StorageData,
dtype: DType,
device: Device,
}
impl Storage {
pub fn cpu_f32_zeros(numel: usize) -> Self {
Self::from_f32_vec(vec![0.0; numel])
}
pub fn from_f32_vec(data: Vec<f32>) -> Self {
Self {
data: StorageData::Cpu(CpuStorage::F32(data)),
dtype: DType::F32,
device: Device::Cpu,
}
}
pub fn from_i64_vec(data: Vec<i64>) -> Self {
Self {
data: StorageData::Cpu(CpuStorage::I64(data)),
dtype: DType::I64,
device: Device::Cpu,
}
}
#[cfg(target_os = "macos")]
pub fn from_metal(buffer: MetalBuffer, dtype: DType) -> Self {
let device = Device::Metal {
index: buffer.device_index,
};
Self {
data: StorageData::Metal(buffer),
dtype,
device,
}
}
pub fn dtype(&self) -> DType {
self.dtype
}
pub fn device(&self) -> Device {
self.device
}
pub fn data(&self) -> &StorageData {
&self.data
}
pub fn cpu(&self) -> Result<&CpuStorage> {
match &self.data {
StorageData::Cpu(c) => Ok(c),
#[cfg(target_os = "macos")]
StorageData::Metal(_) => Err(Error::DeviceMismatch {
lhs: self.device,
rhs: Device::Cpu,
op: "Storage::cpu",
}),
}
}
}