1use std::any::Any;
4use std::sync::Arc;
5
6use oxmera_core::{DType, Device, Error, Result};
7
8#[derive(Debug, Clone)]
13pub enum CpuStorage {
14 F32(Vec<f32>),
16 I64(Vec<i64>),
18 U8(Vec<u8>),
20}
21
22impl CpuStorage {
23 pub fn dtype(&self) -> DType {
25 match self {
26 CpuStorage::F32(_) => DType::F32,
27 CpuStorage::I64(_) => DType::I64,
28 CpuStorage::U8(_) => DType::U8,
29 }
30 }
31
32 pub fn len(&self) -> usize {
34 match self {
35 CpuStorage::F32(v) => v.len(),
36 CpuStorage::I64(v) => v.len(),
37 CpuStorage::U8(v) => v.len(),
38 }
39 }
40
41 pub fn is_empty(&self) -> bool {
43 self.len() == 0
44 }
45
46 pub fn f32s(&self) -> Result<&[f32]> {
48 match self {
49 CpuStorage::F32(v) => Ok(v),
50 other => Err(Error::DTypeMismatch {
51 expected: DType::F32,
52 got: other.dtype(),
53 op: "CpuStorage::f32s",
54 }),
55 }
56 }
57
58 pub fn i64s(&self) -> Result<&[i64]> {
60 match self {
61 CpuStorage::I64(v) => Ok(v),
62 other => Err(Error::DTypeMismatch {
63 expected: DType::I64,
64 got: other.dtype(),
65 op: "CpuStorage::i64s",
66 }),
67 }
68 }
69}
70
71#[cfg(target_os = "macos")]
75#[derive(Debug)]
76pub struct MetalBuffer {
77 buffer: metal::Buffer,
78 pub device_index: usize,
80}
81
82#[cfg(target_os = "macos")]
83impl MetalBuffer {
84 pub fn new(buffer: metal::Buffer, device_index: usize) -> Self {
86 Self {
87 buffer,
88 device_index,
89 }
90 }
91
92 pub fn buffer(&self) -> &metal::Buffer {
94 &self.buffer
95 }
96}
97
98#[cfg(target_os = "macos")]
104#[allow(unsafe_code)]
105unsafe impl Send for MetalBuffer {}
106#[cfg(target_os = "macos")]
109#[allow(unsafe_code)]
110unsafe impl Sync for MetalBuffer {}
111
112pub struct OpaqueBuffer {
117 inner: Arc<dyn Any + Send + Sync>,
118 len: usize,
119}
120
121impl OpaqueBuffer {
122 pub fn new(inner: Arc<dyn Any + Send + Sync>, len: usize) -> Self {
124 Self { inner, len }
125 }
126
127 pub fn inner(&self) -> &Arc<dyn Any + Send + Sync> {
129 &self.inner
130 }
131
132 pub fn len(&self) -> usize {
134 self.len
135 }
136
137 pub fn is_empty(&self) -> bool {
139 self.len == 0
140 }
141}
142
143impl std::fmt::Debug for OpaqueBuffer {
144 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
145 f.debug_struct("OpaqueBuffer")
146 .field("len", &self.len)
147 .finish_non_exhaustive()
148 }
149}
150
151#[derive(Debug)]
153pub enum StorageData {
154 Cpu(CpuStorage),
156 #[cfg(target_os = "macos")]
158 Metal(MetalBuffer),
159 Opaque(OpaqueBuffer),
161}
162
163#[derive(Debug)]
168pub struct Storage {
169 data: StorageData,
170 dtype: DType,
171 device: Device,
172}
173
174impl Storage {
175 pub fn cpu_f32_zeros(numel: usize) -> Self {
177 Self::from_f32_vec(vec![0.0; numel])
178 }
179
180 pub fn from_f32_vec(data: Vec<f32>) -> Self {
182 Self {
183 data: StorageData::Cpu(CpuStorage::F32(data)),
184 dtype: DType::F32,
185 device: Device::Cpu,
186 }
187 }
188
189 pub fn from_i64_vec(data: Vec<i64>) -> Self {
191 Self {
192 data: StorageData::Cpu(CpuStorage::I64(data)),
193 dtype: DType::I64,
194 device: Device::Cpu,
195 }
196 }
197
198 #[cfg(target_os = "macos")]
200 pub fn from_metal(buffer: MetalBuffer, dtype: DType) -> Self {
201 let device = Device::Metal {
202 index: buffer.device_index,
203 };
204 Self {
205 data: StorageData::Metal(buffer),
206 dtype,
207 device,
208 }
209 }
210
211 pub fn dtype(&self) -> DType {
213 self.dtype
214 }
215
216 pub fn device(&self) -> Device {
218 self.device
219 }
220
221 pub fn data(&self) -> &StorageData {
223 &self.data
224 }
225
226 pub fn cpu(&self) -> Result<&CpuStorage> {
229 match &self.data {
230 StorageData::Cpu(c) => Ok(c),
231 _ => Err(Error::DeviceMismatch {
232 lhs: self.device,
233 rhs: Device::Cpu,
234 op: "Storage::cpu",
235 }),
236 }
237 }
238
239 pub fn from_opaque(buffer: OpaqueBuffer, dtype: DType, device: Device) -> Self {
241 Self {
242 data: StorageData::Opaque(buffer),
243 dtype,
244 device,
245 }
246 }
247
248 pub fn opaque(&self) -> Option<&OpaqueBuffer> {
250 match &self.data {
251 StorageData::Opaque(b) => Some(b),
252 _ => None,
253 }
254 }
255}