use crate::dimension::Dimension;
use crate::dtype::{DType, Element};
use crate::error::{FerrayError, FerrayResult};
use super::ArrayFlags;
use super::owned::Array;
use super::view::ArrayView;
impl<T: Element, D: Dimension> Array<T, D> {
#[inline]
pub const fn itemsize(&self) -> usize {
std::mem::size_of::<T>()
}
#[inline]
pub fn nbytes(&self) -> usize {
self.size() * self.itemsize()
}
#[inline]
pub fn dtype(&self) -> DType {
T::dtype()
}
pub fn t(&self) -> ArrayView<'_, T, D> {
let transposed = self.inner.view().reversed_axes();
ArrayView::from_ndarray(transposed)
}
#[must_use]
pub fn copy(&self) -> Self {
Self {
inner: self.inner.clone(),
dim: self.dim.clone(),
}
}
pub fn to_vec_flat(&self) -> Vec<T> {
self.inner.iter().cloned().collect()
}
pub fn to_bytes(&self) -> FerrayResult<&[u8]>
where
T: Copy,
{
let slice = self.inner.as_slice().ok_or_else(|| {
FerrayError::invalid_value("array is not contiguous; cannot produce byte slice")
})?;
let ptr = slice.as_ptr().cast::<u8>();
let len = std::mem::size_of_val(slice);
Ok(unsafe { std::slice::from_raw_parts(ptr, len) })
}
pub fn flags(&self) -> ArrayFlags {
let layout = self.layout();
ArrayFlags {
c_contiguous: layout.is_c_contiguous(),
f_contiguous: layout.is_f_contiguous(),
owndata: true,
writeable: true,
}
}
}
impl<T: Element, D: Dimension> ArrayView<'_, T, D> {
#[inline]
pub const fn itemsize(&self) -> usize {
std::mem::size_of::<T>()
}
#[inline]
pub fn nbytes(&self) -> usize {
self.size() * self.itemsize()
}
#[inline]
pub fn dtype(&self) -> DType {
T::dtype()
}
pub fn t(&self) -> ArrayView<'_, T, D> {
let transposed = self.inner.clone().reversed_axes();
ArrayView::from_ndarray(transposed)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::dimension::{Ix1, Ix2};
#[test]
fn introspect_basics() {
let arr = Array::<f64, Ix2>::from_vec(Ix2::new([2, 3]), vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0])
.unwrap();
assert_eq!(arr.ndim(), 2);
assert_eq!(arr.size(), 6);
assert_eq!(arr.shape(), &[2, 3]);
assert_eq!(arr.itemsize(), 8); assert_eq!(arr.nbytes(), 48); assert_eq!(arr.dtype(), DType::F64);
assert!(!arr.is_empty());
}
#[test]
fn introspect_empty() {
let arr = Array::<f64, Ix1>::from_vec(Ix1::new([0]), vec![]).unwrap();
assert!(arr.is_empty());
assert_eq!(arr.size(), 0);
assert_eq!(arr.nbytes(), 0);
}
#[test]
fn flags_owned() {
let arr = Array::<f64, Ix2>::zeros(Ix2::new([3, 4])).unwrap();
let f = arr.flags();
assert!(f.c_contiguous);
assert!(f.owndata);
assert!(f.writeable);
}
#[test]
fn transpose_view() {
let arr = Array::<f64, Ix2>::from_vec(Ix2::new([2, 3]), vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0])
.unwrap();
let t = arr.t();
assert_eq!(t.shape(), &[3, 2]);
assert_eq!(t.size(), 6);
}
#[test]
fn copy_is_independent() {
let arr = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
let copy = arr.copy();
assert_eq!(copy.as_slice().unwrap(), arr.as_slice().unwrap());
assert_ne!(copy.as_ptr(), arr.as_ptr());
}
#[test]
fn to_vec_flat() {
let arr = Array::<i32, Ix2>::from_vec(Ix2::new([2, 2]), vec![1, 2, 3, 4]).unwrap();
assert_eq!(arr.to_vec_flat(), vec![1, 2, 3, 4]);
}
#[test]
fn to_bytes_contiguous() {
let arr = Array::<u8, Ix1>::from_vec(Ix1::new([4]), vec![0xDE, 0xAD, 0xBE, 0xEF]).unwrap();
let bytes = arr.to_bytes().unwrap();
assert_eq!(bytes, &[0xDE, 0xAD, 0xBE, 0xEF]);
}
#[test]
fn view_introspection() {
let arr = Array::<f64, Ix2>::from_vec(Ix2::new([2, 3]), vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0])
.unwrap();
let v = arr.view();
assert_eq!(v.itemsize(), 8);
assert_eq!(v.nbytes(), 48);
assert_eq!(v.dtype(), DType::F64);
}
#[test]
fn view_transpose() {
let arr = Array::<f64, Ix2>::from_vec(Ix2::new([2, 3]), vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0])
.unwrap();
let v = arr.view();
let vt = v.t();
assert_eq!(vt.shape(), &[3, 2]);
}
}