Skip to main content

devela/data/layout/array/
define.rs

1// devela/src/data/layout/array/define.rs
2//
3//! Array views over generic backing storage.
4//
5
6use crate::{ArrayCoordIter, ArrayLayout, ArrayShape};
7
8#[doc = crate::_tags!(data_structure mem)]
9/// A logical array over backing storage.
10#[doc = crate::_doc_meta!{
11    location("data/layout/array", struct Array),
12    #[cfg(target_pointer_width = "32")]
13    test_size_of(Array<[u8; 6], 1> = 20|160; niche !Option),
14    #[cfg(target_pointer_width = "32")]
15    test_size_of(Array<[u8; 6], 2> = 28|224; niche !Option),
16    #[cfg(target_pointer_width = "32")]
17    test_size_of(Array<[u8; 6], 3> = 36|288; niche !Option),
18    #[cfg(target_pointer_width = "64")]
19    test_size_of(Array<[u8; 6], 1> = 32|256; niche !Option),
20    #[cfg(target_pointer_width = "64")]
21    test_size_of(Array<[u8; 6], 2> = 48|384; niche !Option),
22    #[cfg(target_pointer_width = "64")]
23    test_size_of(Array<[u8; 6], 3> = 64|512; niche !Option),
24}]
25/// An array joins:
26/// - backing data of type `D`;
27/// - an [`ArrayLayout`] mapping logical coordinates into that data.
28///
29/// `D` determines whether the array borrows or owns its storage,
30/// whether access is shared or exclusive, and whether the
31/// storage length is fixed or dynamically determined.
32///
33/// # Invariant
34///
35/// Every physical storage position addressed by `layout`
36/// must be accessible through `data`.
37///
38/// The provided constructors preserve this relationship.
39///
40/// # Examples
41/// º
42/// ```
43/// use devela::{ArrayLayout, ArrayShape, Array};
44///
45/// let storage = [0, 1, 2, 3, 4, 5];
46/// let shape = ArrayShape::new([2, 3]);
47/// let layout = ArrayLayout::dense_last(shape)?;
48/// let view = Array::try_from_slice_ref(&storage, layout)?;
49///
50/// assert_eq!(view.get([1, 2]).copied(), Some(5));
51/// # Ok::<(), Box<dyn core::error::Error>>(())
52/// ```
53#[must_use]
54#[derive(Clone, Copy, Debug)]
55pub struct Array<D, const RANK: usize> {
56    /// The backing data providing physical element storage.
57    ///
58    /// Its accessible storage must cover every position addressed by `layout`.
59    pub(super) data: D,
60
61    /// The logical shape and coordinate-to-storage mapping.
62    ///
63    /// Every physical position addressed by this layout must be valid for `data`.
64    pub(super) layout: ArrayLayout<RANK>,
65}
66#[rustfmt::skip]
67impl<D, const RANK: usize> Array<D, RANK> {
68
69    /// Returns a shared reference to the backing data.
70    pub const fn data(&self) -> &D { &self.data }
71
72    /// Returns the array layout.
73    pub const fn layout(&self) -> ArrayLayout<RANK> { self.layout }
74
75    /// Consumes the array and returns its backing data.
76    pub fn into_data(self) -> D {
77        self.data
78    }
79    /// Decomposes the array into its backing data and layout.
80    pub fn into_parts(self) -> (D, ArrayLayout<RANK>) {
81        (self.data, self.layout)
82    }
83
84    /// Returns the logical shape.
85    pub const fn shape(&self) -> ArrayShape<RANK> { self.layout.shape() }
86
87    /// Returns the number of logical axes.
88    pub const fn rank(&self) -> usize { RANK }
89
90    /// Returns the number of logical elements.
91    pub const fn element_count(&self) -> usize { self.layout.element_count() }
92
93    /// Returns whether the logical array has no elements.
94    pub const fn is_empty(&self) -> bool { self.layout.is_empty() }
95
96    /// Returns an iterator over every logical coordinate of this array.
97    ///
98    /// Coordinates are independent of physical offset, strides,
99    /// backing-storage order, and ownership.
100    pub const fn coords(&self) -> ArrayCoordIter<RANK> {
101        self.layout.coords()
102    }
103}