@@ -1292,6 +1292,92 @@ where S: RawData
12921292}
12931293
12941294/// A reference to the layout of an *n*-dimensional array.
1295+ ///
1296+ /// This type can be used to read and write to the layout of an array;
1297+ /// that is to say, its shape and strides. It does not provide any read
1298+ /// or write access to the array's underlying data. It is generic on two
1299+ /// types: `D`, its dimensionality, and `A`, the element type of its data.
1300+ ///
1301+ /// ## Example
1302+ /// Say we wanted to write a function that provides the aspect ratio
1303+ /// of any 2D array: the ratio of its width (number of columns) to its
1304+ /// height (number of rows). We would write that as follows:
1305+ /// ```rust
1306+ /// use ndarray::{LayoutRef2, array};
1307+ ///
1308+ /// fn aspect_ratio<T, A>(layout: &T) -> (usize, usize)
1309+ /// where T: AsRef<LayoutRef2<A>>
1310+ /// {
1311+ /// let layout = layout.as_ref();
1312+ /// (layout.ncols(), layout.nrows())
1313+ /// }
1314+ ///
1315+ /// let arr = array![[1, 2], [3, 4]];
1316+ /// assert_eq!(aspect_ratio(&arr), (2, 2));
1317+ /// ```
1318+ /// Similarly, new traits that provide functions that only depend on
1319+ /// or alter the layout of an array should do so via a blanket
1320+ /// implementation. Lets write a trait that both provides the aspect ratio
1321+ /// and lets users cut down arrays to a desired aspect ratio.
1322+ /// For simplicity, we'll panic if the user provides an aspect ratio
1323+ /// where either element is larger than the array's size.
1324+ /// ```rust
1325+ /// use ndarray::{LayoutRef2, array, s};
1326+ ///
1327+ /// trait Ratioable<A> {
1328+ /// fn aspect_ratio(&self) -> (usize, usize)
1329+ /// where Self: AsRef<LayoutRef2<A>>;
1330+ ///
1331+ /// fn cut_to_ratio(&mut self, ratio: (usize, usize))
1332+ /// where Self: AsMut<LayoutRef2<A>>;
1333+ /// }
1334+ ///
1335+ /// impl<T, A> Ratioable<A> for T
1336+ /// where T: AsRef<LayoutRef2<A>> + AsMut<LayoutRef2<A>>
1337+ /// {
1338+ /// fn aspect_ratio(&self) -> (usize, usize)
1339+ /// {
1340+ /// let layout = self.as_ref();
1341+ /// (layout.ncols(), layout.nrows())
1342+ /// }
1343+ ///
1344+ /// fn cut_to_ratio(&mut self, ratio: (usize, usize))
1345+ /// {
1346+ /// let layout = self.as_mut();
1347+ /// layout.slice_collapse(s![..ratio.1, ..ratio.0]);
1348+ /// }
1349+ /// }
1350+ ///
1351+ /// let mut arr = array![[1, 2, 3], [4, 5, 6]];
1352+ /// assert_eq!(arr.aspect_ratio(), (3, 2));
1353+ /// arr.cut_to_ratio((2, 2));
1354+ /// assert_eq!(arr, array![[1, 2], [4, 5]]);
1355+ /// ```
1356+ /// Continue reading for why we use `AsRef` instead of taking `&LayoutRef` directly.
1357+ ///
1358+ /// ## Writing Functions
1359+ /// Writing functions that accept `LayoutRef` is not as simple as taking
1360+ /// a `&LayoutRef` argument, as the above examples show. This is because
1361+ /// `LayoutRef` can be obtained either cheaply or expensively, depending
1362+ /// on the method used. `LayoutRef` can be obtained from all kinds of arrays
1363+ /// -- [owned](Array), [shared](ArcArray), [viewed](ArrayView), [referenced](ArrayRef),
1364+ /// and [raw referenced](RawRef) -- via `.as_ref()`. Critically, this way of
1365+ /// obtaining a `LayoutRef` is cheap, as it does not guarantee that the
1366+ /// underlying data is uniquely held.
1367+ ///
1368+ /// However, `LayoutRef`s can be obtained a second way: they sit at the bottom
1369+ /// of a "deref chain" going from shared arrays, through `ArrayRef`, through
1370+ /// `RawRef`, and finally to `LayoutRef`. As a result, `LayoutRef`s can also
1371+ /// be obtained via auto-dereferencing. When requesting a mutable reference --
1372+ /// `&mut LayoutRef` -- the `deref_mut` to `ArrayRef` triggers a (possibly
1373+ /// expensive) guarantee that the data is uniquely held (see [`ArrayRef`]
1374+ /// for more information).
1375+ ///
1376+ /// To help users avoid this error cost, functions that operate on `LayoutRef`s
1377+ /// should take their parameters as a generic type `T: AsRef<LayoutRef<A, D>>`,
1378+ /// as the above examples show. This aids the caller in two ways: they can pass
1379+ /// their arrays by reference (`&arr`) instead of explicitly calling `as_ref`,
1380+ /// and they will avoid paying a performance penalty for mutating the shape.
12951381//
12961382// # Safety for Implementors
12971383//
0 commit comments