Skip to main content

rustymath_core/
array.rs

1//! Borrowed array storage, layouts and positional reads.
2use crate::agreement::{Binding, Mapping, Missing, Read, ReadPlan};
3use crate::buffer::{Buffer, DType, Element, Items, View};
4use crate::error::{Error, Kind};
5use crate::layout::Layout;
6use std::borrow::Cow;
7
8/// Sources lent for one operation. The plan carries positions, never data or a materialization cache.
9#[derive(Clone)]
10pub struct ArrayView<'a> { layout: &'a Layout, sources: Vec<Binding<'a>>, plan: ReadPlan }
11
12impl<'a> ArrayView<'a> {
13    pub fn new(layout: &'a Layout, sources: Vec<Binding<'a>>, plan: ReadPlan) -> Result<Self, Error> {
14        if layout.count() != plan.len() { return Err(Error::new(Kind::Length, "read plan doesn't fit its layout")); }
15        Ok(Self { layout, sources, plan })
16    }
17    pub fn compact(layout: &'a Layout, storage: View<'a>) -> Self {
18        Self { layout, sources: vec![Binding::full(storage)], plan: ReadPlan::input(0, storage.len()) }
19    }
20    pub fn layout(&self) -> &'a Layout { self.layout }
21    pub fn dtype(&self) -> DType { self.sources[0].view.dtype() }
22    pub fn len(&self) -> usize { self.plan.len() }
23    pub fn is_empty(&self) -> bool { self.plan.is_empty() }
24    pub fn read(&self) -> Read<'_> { Read { sources: &self.sources, plan: &self.plan } }
25    pub fn plan(&self) -> &ReadPlan { &self.plan }
26    pub fn sources(&self) -> &[Binding<'a>] { &self.sources }
27    /// Changes metadata, retaining the logical sequence.
28    pub fn with_layout<'b>(&self, layout: &'b Layout) -> Result<ArrayView<'b>, Error> where 'a: 'b {
29        ArrayView::new(layout, self.sources.clone(), self.plan.clone())
30    }
31    /// Composes a call's positional read. Missing positions read the prototype (`Missing::prototype`).
32    pub fn remapped(&self, mapping: Mapping, items: usize) -> Self {
33        let mut sources = self.sources.clone();
34        let missing = Missing::prototype(self.dtype(), &mut sources);
35        Self { layout: self.layout, sources, plan: self.plan.remapped(mapping, items, missing) }
36    }
37    pub fn contiguous(&self) -> Option<View<'a>> {
38        if self.is_empty() { return Some(self.sources[0].view.slice(0..0)); }
39        let (source, range) = self.plan.contiguous(0..self.len())?;
40        self.sources.get(source)?.borrow(range)
41    }
42    pub fn affine(&self) -> Option<(View<'a>, usize, Vec<isize>)> {
43        let (source, mapping) = self.plan.positional(self.layout.shape())?;
44        let (base, strides) = mapping.affine(self.layout.shape())?;
45        let (view, base) = self.sources.get(source)?.affine(base, &strides, self.layout.shape())?;
46        Some((view, base, strides))
47    }
48    /// Borrows a contiguous read at its dtype, otherwise prepares exactly these logical items.
49    pub fn cast(&self, dtype: DType) -> Result<Items<'a>, Error> {
50        if dtype == self.dtype() && let Some(view) = self.contiguous() { return Ok(Items::Borrowed(view)); }
51        let mut buffer = Buffer::with_capacity(dtype, self.len());
52        self.read().read_into(0..self.len(), dtype, true, &mut buffer)?;
53        Ok(Items::Owned(buffer))
54    }
55    pub fn items<T: Element>(&self) -> Result<Cow<'a, [T]>, Error> { Ok(self.cast(T::DTYPE)?.items()) }
56}