use crate::dimension::Dimension;
use crate::dtype::Element;
use crate::layout::MemoryLayout;
use super::ArrayFlags;
use super::owned::Array;
use super::view::ArrayView;
pub enum CowArray<'a, T: Element, D: Dimension> {
Borrowed(ArrayView<'a, T, D>),
Owned(Array<T, D>),
}
impl<'a, T: Element, D: Dimension> CowArray<'a, T, D> {
pub const fn from_view(view: ArrayView<'a, T, D>) -> Self {
Self::Borrowed(view)
}
pub const fn from_owned(arr: Array<T, D>) -> Self {
Self::Owned(arr)
}
#[inline]
pub fn shape(&self) -> &[usize] {
match self {
Self::Borrowed(v) => v.shape(),
Self::Owned(a) => a.shape(),
}
}
#[inline]
pub fn ndim(&self) -> usize {
match self {
Self::Borrowed(v) => v.ndim(),
Self::Owned(a) => a.ndim(),
}
}
#[inline]
pub fn size(&self) -> usize {
match self {
Self::Borrowed(v) => v.size(),
Self::Owned(a) => a.size(),
}
}
#[inline]
pub fn is_empty(&self) -> bool {
self.size() == 0
}
pub fn layout(&self) -> MemoryLayout {
match self {
Self::Borrowed(v) => v.layout(),
Self::Owned(a) => a.layout(),
}
}
pub const fn is_borrowed(&self) -> bool {
matches!(self, Self::Borrowed(_))
}
pub const fn is_owned(&self) -> bool {
matches!(self, Self::Owned(_))
}
pub fn into_owned(self) -> Array<T, D> {
match self {
Self::Borrowed(v) => v.to_owned(),
Self::Owned(a) => a,
}
}
pub fn to_mut(&mut self) -> &mut Array<T, D> {
if let Self::Borrowed(v) = self {
*self = Self::Owned(v.to_owned());
}
match self {
Self::Owned(a) => a,
Self::Borrowed(_) => unreachable!(),
}
}
pub fn view(&self) -> ArrayView<'_, T, D> {
match self {
Self::Borrowed(v) => {
ArrayView::from_ndarray(v.inner.view())
}
Self::Owned(a) => a.view(),
}
}
#[inline]
pub fn as_ptr(&self) -> *const T {
match self {
Self::Borrowed(v) => v.as_ptr(),
Self::Owned(a) => a.as_ptr(),
}
}
pub fn flags(&self) -> ArrayFlags {
match self {
Self::Borrowed(v) => v.flags(),
Self::Owned(a) => {
let layout = a.layout();
ArrayFlags {
c_contiguous: layout.is_c_contiguous(),
f_contiguous: layout.is_f_contiguous(),
owndata: true,
writeable: true,
aligned: true,
}
}
}
}
}
impl<T: Element, D: Dimension> Clone for CowArray<'_, T, D> {
fn clone(&self) -> Self {
match self {
Self::Borrowed(v) => Self::Borrowed(v.clone()),
Self::Owned(a) => Self::Owned(a.clone()),
}
}
}
impl<T: Element, D: Dimension> From<Array<T, D>> for CowArray<'_, T, D> {
fn from(arr: Array<T, D>) -> Self {
Self::Owned(arr)
}
}
impl<'a, T: Element, D: Dimension> From<ArrayView<'a, T, D>> for CowArray<'a, T, D> {
fn from(view: ArrayView<'a, T, D>) -> Self {
Self::Borrowed(view)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::dimension::Ix1;
#[test]
fn cow_from_view() {
let arr = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
let view = arr.view();
let cow = CowArray::from_view(view);
assert!(cow.is_borrowed());
assert!(!cow.is_owned());
assert_eq!(cow.shape(), &[3]);
}
#[test]
fn cow_from_owned() {
let arr = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
let cow = CowArray::from_owned(arr);
assert!(cow.is_owned());
assert!(!cow.is_borrowed());
}
#[test]
fn cow_to_mut_clones_when_borrowed() {
let arr = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
let view = arr.view();
let mut cow = CowArray::from_view(view);
assert!(cow.is_borrowed());
let owned = cow.to_mut();
assert_eq!(owned.shape(), &[3]);
assert!(cow.is_owned());
}
#[test]
fn cow_into_owned() {
let arr = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
let view = arr.view();
let cow = CowArray::from_view(view);
let owned = cow.into_owned();
assert_eq!(owned.as_slice().unwrap(), &[1.0, 2.0, 3.0]);
}
}