use std::{fmt, path::Path};
use cxx::SharedPtr;
use mirtal_sys::ffi;
use crate::{DType, Element, Error, Result, Shape, element};
#[derive(Clone)]
pub struct Array {
raw: SharedPtr<ffi::Array>,
}
impl Array {
pub fn from_slice<T: Element, const N: usize>(data: &[T], shape: [usize; N]) -> Result<Self> {
Self::from_shape(data, &Shape::try_from(shape)?)
}
pub fn from_shape<T: Element>(data: &[T], shape: &Shape) -> Result<Self> {
let elements = shape.elements()?;
if elements != data.len() {
return Err(Error::Shape {
shape: shape.dimensions().to_vec(),
elements,
data: data.len(),
});
}
Self::from_raw(element::create(data, &shape.native()?)?, "array")
}
pub fn shape(&self) -> Result<Shape> {
let dimensions = ffi::array_shape(self.native()?)?
.into_iter()
.map(usize::try_from)
.collect::<std::result::Result<Vec<_>, _>>()?;
Shape::new(dimensions)
}
pub fn dtype(&self) -> Result<DType> {
DType::try_from(ffi::array_dtype(self.native()?)?)
}
#[must_use]
pub fn len(&self) -> usize {
self.raw.as_ref().map_or(0, ffi::array_len)
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub(crate) fn from_raw(raw: SharedPtr<ffi::Array>, name: &'static str) -> Result<Self> {
if raw.is_null() {
return Err(Error::NullHandle(name));
}
Ok(Self { raw })
}
pub(crate) fn native(&self) -> Result<&ffi::Array> {
self.raw.as_ref().ok_or(Error::NullHandle("array"))
}
pub(crate) fn raw_clone(&self) -> SharedPtr<ffi::Array> {
self.raw.clone()
}
pub fn export_graph_dot(&self, path: &Path) -> Result<()> {
let path = path.to_str().ok_or_else(|| Error::InvalidPath(path.to_path_buf()))?;
Ok(mirtal_sys::graph::ffi::export_graph_dot(self.native()?, path)?)
}
pub fn async_eval(&self) -> Result<()> {
Ok(ffi::array_eval(self.native()?)?)
}
pub fn to_vec_f32(&self) -> Result<Vec<f32>> {
let mut output = vec![0.0; self.len()];
mirtal_sys::read::ffi::array_read_f32(self.native()?, &mut output)?;
Ok(output)
}
pub fn item_u32(&self) -> Result<u32> {
Ok(mirtal_sys::read::ffi::array_read_u32_scalar(self.native()?)?)
}
}
impl fmt::Debug for Array {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("Array")
.field("shape", &self.shape())
.field("dtype", &self.dtype())
.finish_non_exhaustive()
}
}