Skip to main content

rustymath_core/
layout.rs

1//! Array shapes, axis keys and names, and their limits.
2use crate::error::{Error, Kind};
3use crate::hashing::{HashMap, HashMapExt, HashSet, HashSetExt};
4use std::{borrow::Cow, fmt, sync::Arc};
5
6/// The most axes an array can have.
7pub const MAX_RANK: usize = 128;
8/// The most items in an array that a function makes.
9pub const MAX_GENERATED_ELEMENTS: usize = 1_000_000_000;
10
11/// The number of items in an array of `shape` that already exists. Unlike `element_count`, it checks neither the rank nor overflow. Ranks 0 to 2 compute it inline.
12#[inline]
13pub fn count(shape: &[usize]) -> usize { match *shape { [] => 1, [n] => n, [m, n] => m * n, _ => shape.iter().product() } }
14
15/// The number of items in an array of `shape`. A Limit error when `shape` has more than `MAX_RANK` axes, or more items than a `usize` counts.
16#[inline]
17pub fn element_count(shape: &[usize]) -> Result<usize, Error> {
18    if shape.len() > MAX_RANK { return Err(Error::new(Kind::Limit, format!("an array has at most {MAX_RANK} axes"))); }
19    shape.iter().try_fold(1usize, |n, &d| n.checked_mul(d)).or_else(|| shape.contains(&0).then_some(0))
20        .ok_or_else(|| Error::new(Kind::Limit, "an array of this shape has too many items to count"))
21}
22
23/// The number of items in an array of `shape` that a function makes. A Limit error past `MAX_GENERATED_ELEMENTS`, or where the array would take the process past its memory guard's limit ([`memory::admit`](crate::memory::admit)).
24#[inline]
25pub fn generated_len(shape: &[usize]) -> Result<usize, Error> {
26    let len = element_count(shape)?;
27    if len > MAX_GENERATED_ELEMENTS { return Err(Error::new(Kind::Limit, format!("an array has at most {MAX_GENERATED_ELEMENTS} items"))); }
28    crate::memory::admit(len)?;
29    Ok(len)
30}
31
32/// The distance between neighbouring items along each axis of an array of `shape`.
33#[inline]
34pub fn strides(shape: &[usize]) -> Vec<usize> {
35    let mut strides = vec![1; shape.len()];
36    for a in (1..shape.len()).rev() { strides[a - 1] = strides[a] * shape[a]; }
37    strides
38}
39
40/// The offsets of parts of `sizes` laid end to end, each the sum of the sizes before it.
41pub fn exclusive_sums(sizes: impl IntoIterator<Item = usize>) -> Vec<usize> {
42    let mut at = 0;
43    sizes.into_iter().map(|n| {
44        let start = at;
45        at += n;
46        start
47    }).collect()
48}
49
50/// Each axis's coordinate of flat position `flat`, from the last axis to the first. `flat` must be within the shape.
51#[inline]
52pub fn coordinates(mut flat: usize, shape: &[usize]) -> impl Iterator<Item = (usize, usize)> + '_ {
53    shape.iter().enumerate().rev().map(move |(axis, &len)| {
54        let coordinate = flat % len;
55        flat /= len;
56        (axis, coordinate)
57    })
58}
59
60/// The position among `len` that `n` gives, counting from the end when negative. `None` outside the range.
61#[inline]
62pub fn position(n: i64, len: usize) -> Option<usize> { let i = if n < 0 { len as i64 + n } else { n }; usize::try_from(i).ok().filter(|&i| i < len) }
63
64/// An array's items as lanes along one axis: `outer` lanes before it, each `len` items long, with `inner` items between neighbours along it.
65#[derive(Clone, Copy, Debug)]
66pub struct Lanes { pub outer: usize, pub len: usize, pub inner: usize }
67
68impl Lanes {
69    /// The lanes along `axis` of an array of `shape`. A Rank error when `axis` is outside the rank, and a Limit error where `element_count` gives one.
70    #[inline]
71    pub fn new(shape: &[usize], axis: usize) -> Result<Self, Error> {
72        let &len = shape.get(axis).ok_or_else(|| Error::new(Kind::Rank, format!("axis {axis} is outside an array of rank {}", shape.len())))?;
73        Ok(Self { outer: element_count(&shape[..axis])?, len, inner: element_count(&shape[axis + 1..])? })
74    }
75    /// The offset of item `j` along the axis, in the lane at outer index `i` and inner index `k`.
76    #[inline]
77    pub fn offset(&self, i: usize, j: usize, k: usize) -> usize { (i * self.len + j) * self.inner + k }
78    /// The lanes as rustymath's axis functions take them: `[outer, len, inner]`.
79    #[inline]
80    pub fn dims(&self) -> [usize; 3] { [self.outer, self.len, self.inner] }
81}
82
83/// The value that every present item of `values` equals. Absent items don't count. Two different values give none.
84pub fn agreed<'a, T: PartialEq + Clone + 'a>(values: impl IntoIterator<Item = Option<&'a T>>) -> Option<T> {
85    let mut found = None;
86    for value in values.into_iter().flatten() {
87        if found.is_some_and(|f| f != value) { return None; }
88        found = Some(value);
89    }
90    found.cloned()
91}
92
93/// The first name that appears more than once in `names`.
94pub fn repeated_name(names: &[Option<Arc<str>>]) -> Option<&Arc<str>> { let mut seen = HashSet::new(); names.iter().flatten().find(|n| !seen.insert(*n)) }
95
96/// Whether an axis name is hidden: it starts with `_`. Hidden and visible names are separate namespaces.
97#[inline]
98pub fn hidden(name: &str) -> bool { name.starts_with('_') }
99
100/// The character between a fresh name's stem and its random part. [`shown`] cuts a hidden name after it.
101pub const FRESH: char = '·';
102
103/// `name` as messages and display show it: a hidden name that holds [`FRESH`] cut after the last one, as in `_b·…`. Any other name stays as it is.
104pub fn shown(name: &str) -> Cow<'_, str> {
105    match name.rfind(FRESH) { Some(i) if hidden(name) => format!("{}…", &name[..i + FRESH.len_utf8()]).into(), _ => name.into() }
106}
107
108/// Whether two axis names conflict: both are names, they differ, and they're in the same namespace. A name meets a name from the other namespace as if that axis were unnamed.
109#[inline]
110pub fn names_conflict(a: Option<&str>, b: Option<&str>) -> bool { matches!((a, b), (Some(a), Some(b)) if a != b && hidden(a) == hidden(b)) }
111
112/// An array's shape: the length of each axis. Ranks 0 to 2 are held inline with no allocation, and higher ranks in one allocation of exactly their length. Convert a `Vec`, an array or a slice of lengths into one, or collect it from lengths.
113#[derive(Clone)]
114pub struct Shape(Repr);
115
116#[derive(Clone)]
117enum Repr { Small(u8, [usize; 2]), Large(Box<[usize]>) }
118
119impl Shape {
120    /// The shape of a rank-0 array.
121    pub const EMPTY: Self = Self(Repr::Small(0, [0; 2]));
122    /// The lengths of `parts`, one after another.
123    fn spliced(parts: [&[usize]; 3]) -> Self {
124        let len: usize = parts.iter().map(|p| p.len()).sum();
125        if len > 2 { return Self(Repr::Large(parts.concat().into_boxed_slice())); }
126        let mut small = [0; 2];
127        for (slot, &n) in small.iter_mut().zip(parts.into_iter().flatten()) { *slot = n; }
128        Self(Repr::Small(len as u8, small))
129    }
130}
131impl Default for Shape {
132    #[inline]
133    fn default() -> Self { Self::EMPTY }
134}
135impl std::ops::Deref for Shape {
136    type Target = [usize];
137    #[inline]
138    fn deref(&self) -> &[usize] { match &self.0 { Repr::Small(n, lengths) => &lengths[..usize::from(*n)], Repr::Large(lengths) => &lengths[..] } }
139}
140impl std::ops::DerefMut for Shape {
141    #[inline]
142    fn deref_mut(&mut self) -> &mut [usize] {
143        match &mut self.0 { Repr::Small(n, lengths) => &mut lengths[..usize::from(*n)], Repr::Large(lengths) => &mut lengths[..] }
144    }
145}
146impl PartialEq for Shape {
147    #[inline]
148    fn eq(&self, other: &Self) -> bool { **self == **other }
149}
150impl Eq for Shape {}
151impl fmt::Debug for Shape { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&**self, f) } }
152impl From<&[usize]> for Shape {
153    #[inline]
154    fn from(lengths: &[usize]) -> Self {
155        match *lengths {
156            [] => Self::EMPTY, [a] => Self(Repr::Small(1, [a, 0])), [a, b] => Self(Repr::Small(2, [a, b])), _ => Self(Repr::Large(lengths.into()))
157        }
158    }
159}
160impl From<Vec<usize>> for Shape {
161    #[inline]
162    fn from(lengths: Vec<usize>) -> Self { if lengths.len() > 2 { Self(Repr::Large(lengths.into_boxed_slice())) } else { Self::from(lengths.as_slice()) } }
163}
164impl<const N: usize> From<[usize; N]> for Shape { fn from(lengths: [usize; N]) -> Self { Self::from(lengths.as_slice()) } }
165impl FromIterator<usize> for Shape {
166    fn from_iter<I: IntoIterator<Item = usize>>(lengths: I) -> Self {
167        let mut lengths = lengths.into_iter();
168        let mut small = [0; 2];
169        for n in 0..2 {
170            let Some(len) = lengths.next() else { return Self(Repr::Small(n, small)) };
171            small[usize::from(n)] = len;
172        }
173        match lengths.next() {
174            None => Self(Repr::Small(2, small)), Some(third) => Self(Repr::Large(small.into_iter().chain([third]).chain(lengths).collect()))
175        }
176    }
177}
178
179/// Names for the positions on one axis. A position may have no name. The names that are present are unique.
180#[derive(Clone, Debug, Default)]
181pub struct Keys { names: Vec<Option<Arc<str>>>, index: HashMap<Arc<str>, usize> }
182
183// Two keys are equal when they hold the same names in the same order.
184impl PartialEq for Keys { fn eq(&self, other: &Self) -> bool { self.names == other.names } }
185impl Eq for Keys {}
186
187/// How the positions of one axis's keys lie along those of a result axis, as [`Keys::aligned`] and [`Keys::union`] give it.
188#[derive(Clone, Debug)]
189pub enum Alignment {
190    /// The same positions, in the same order.
191    Same,
192    /// The positions in order, at the result's first positions. The result's other positions read a fill.
193    Leading,
194    /// The position of each of the result's positions, or `None` where it reads a fill.
195    Table(Vec<Option<usize>>),
196}
197
198impl Keys {
199    /// Keys from `names`, where `None` marks a position with no name. A Domain error when a name appears twice.
200    pub fn partial(names: Vec<Option<Arc<str>>>) -> Result<Arc<Self>, Error> {
201        let mut index = HashMap::with_capacity(names.len());
202        for (i, name) in names.iter().enumerate() {
203            let Some(name) = name else { continue };
204            if index.insert(name.clone(), i).is_some() { return Err(duplicate(name)); }
205        }
206        Ok(Arc::new(Self { names, index }))
207    }
208    #[inline]
209    pub fn names(&self) -> &[Option<Arc<str>>] { &self.names }
210    #[inline]
211    pub fn len(&self) -> usize { self.names.len() }
212    #[inline]
213    pub fn is_empty(&self) -> bool { self.names.is_empty() }
214    /// Whether every position has a name.
215    #[inline]
216    pub fn complete(&self) -> bool { self.index.len() == self.names.len() }
217    /// Whether no position has a name. An axis like that carries no keys.
218    #[inline]
219    pub fn blank(&self) -> bool { self.index.is_empty() && !self.is_empty() }
220    #[inline]
221    pub fn position(&self, name: &str) -> Option<usize> { self.index.get(name).copied() }
222    /// Adds positions at the end, named by `names`. A Domain error, with no position added, when a name is already here or appears twice in `names`.
223    pub fn extend(&mut self, names: &[Option<Arc<str>>]) -> Result<(), Error> {
224        let mut new = HashSet::new();
225        if let Some(name) = names.iter().flatten().find(|n| self.position(n).is_some() || !new.insert(*n)) { return Err(duplicate(name)); }
226        for name in names {
227            if let Some(name) = name { self.index.insert(name.clone(), self.names.len()); }
228            self.names.push(name.clone());
229        }
230        Ok(())
231    }
232    /// For each position of `wanted`, the matching position here. Named positions match by name. Unnamed positions match in order.
233    pub fn align(&self, wanted: &Self) -> Vec<Option<usize>> {
234        let mut gaps = self.names.iter().enumerate().filter(|(_, n)| n.is_none()).map(|(i, _)| i);
235        wanted.names.iter().map(|n| match n { Some(n) => self.position(n), None => gaps.next() }).collect()
236    }
237    /// For each position of `wanted`, the matching position here. With `subset`, `wanted` may have fewer positions, and one with no match is an Index error. Otherwise both need the same positions, and a mismatch is a Length error.
238    pub fn positions(&self, wanted: &Self, subset: bool) -> Result<Vec<usize>, Error> {
239        let kind = if subset { Kind::Index } else { Kind::Length };
240        if !subset && self.len() != wanted.len() {
241            return Err(Error::new(kind, format!("keyed axes of lengths {} and {} don't pair", self.len(), wanted.len())));
242        }
243        self.align(wanted).into_iter().zip(&wanted.names).map(|(p, name)| {
244            p.ok_or_else(|| match name {
245                Some(name) => Error::new(kind, format!("missing key: {}", shown(name))), None => Error::new(kind, "too few positions without keys")
246            })
247        }).collect()
248    }
249    /// Keys at source positions, in the order given. A position with no source has no name.
250    pub fn select(&self, positions: impl IntoIterator<Item = Option<usize>>) -> Result<Arc<Self>, Error> {
251        Self::partial(positions.into_iter().map(|i| i.and_then(|i| self.names[i].clone())).collect())
252    }
253    /// How these positions lie along those of `wanted`: as the same positions, at its first positions, or as [`Keys::align`] finds them.
254    pub fn aligned(self: &Arc<Self>, wanted: &Arc<Self>) -> Alignment {
255        if Arc::ptr_eq(self, wanted) || self == wanted { Alignment::Same }
256        else if wanted.names.starts_with(&self.names) { Alignment::Leading }
257        else { Alignment::Table(self.align(wanted)) }
258    }
259    /// These positions, then the named positions of `other` that these lack, with how these positions and `other`'s lie along them. Unnamed positions pair in order. Both sides need the same number of them.
260    pub fn union(self: &Arc<Self>, other: &Arc<Self>) -> Result<(Arc<Self>, [Alignment; 2]), Error> {
261        if Arc::ptr_eq(self, other) { return Ok((self.clone(), [Alignment::Same, Alignment::Same])); }
262        let (a, b) = (self.len() - self.index.len(), other.len() - other.index.len());
263        if a != b { return Err(Error::new(Kind::Length, format!("axes with {a} and {b} positions without keys don't align"))); }
264        if self == other { return Ok((self.clone(), [Alignment::Same, Alignment::Same])); }
265        if other.names.starts_with(&self.names) { return Ok((other.clone(), [Alignment::Leading, Alignment::Same])); }
266        if self.names.starts_with(&other.names) { return Ok((self.clone(), [Alignment::Same, Alignment::Leading])); }
267        let places = self.align(other);
268        // `places` holds the position here of each of `other`'s positions. `other`'s table is its inverse, with each key that these lack appended after these.
269        let mut table = vec![None; self.len()];
270        for (j, &p) in places.iter().enumerate() { match p { Some(p) => table[p] = Some(j), None => table.push(Some(j)) } }
271        if table.len() == self.len() { return Ok((self.clone(), [Alignment::Same, Alignment::Table(table)])); }
272        let keys = Self::partial(self.names.iter().chain(other.names.iter().zip(&places).filter(|(_, p)| p.is_none()).map(|(k, _)| k)).cloned().collect())?;
273        Ok((keys, [Alignment::Leading, Alignment::Table(table)]))
274    }
275}
276
277/// The Domain error for a key that appears twice on one axis.
278fn duplicate(key: &str) -> Error { Error::new(Kind::Domain, format!("duplicate key: {}", shown(key))) }
279
280/// An array's shape, with optional keys and a name for each axis. A layout with no keys or names holds no `Meta`.
281#[derive(Clone, Debug, Default, PartialEq, Eq)]
282pub struct Layout { shape: Shape, meta: Option<Box<Meta>> }
283
284/// The keys and names of a layout's axes. An empty list means none on any axis.
285#[derive(Clone, Debug, Default, PartialEq, Eq)]
286struct Meta { keys: Vec<Option<Arc<Keys>>>, names: Vec<Option<Arc<str>>> }
287
288impl<S: Into<Shape>> From<S> for Layout {
289    #[inline]
290    fn from(shape: S) -> Self { Self { shape: shape.into(), meta: None } }
291}
292impl Layout {
293    /// The layout of a rank-0 array.
294    pub const EMPTY: Self = Self { shape: Shape::EMPTY, meta: None };
295    #[inline]
296    pub fn shape(&self) -> &[usize] { &self.shape }
297    /// The number of items in an array of this layout (`count`).
298    #[inline]
299    pub fn count(&self) -> usize { count(&self.shape) }
300    /// The name of each axis, with `None` for an axis without one. Empty when no axis has a name (`has_names`).
301    #[inline]
302    pub fn names(&self) -> &[Option<Arc<str>>] { self.meta.as_ref().map_or(&[], |l| &l.names) }
303    #[inline]
304    pub fn name(&self, axis: usize) -> Option<&Arc<str>> { self.names().get(axis).and_then(Option::as_ref) }
305    /// The axis named `name`, if there is one.
306    #[inline]
307    pub fn axis_named(&self, name: &str) -> Option<usize> { self.names().iter().position(|n| n.as_deref() == Some(name)) }
308    fn meta_mut(&mut self) -> &mut Meta { self.meta.get_or_insert_with(Default::default) }
309    /// The layout without an empty `Meta`.
310    fn tidy(mut self) -> Self { if self.meta.as_deref() == Some(&Meta::default()) { self.meta = None; } self }
311    /// The layout with `set` applied to its `Meta`. `empty` says that the new entry needs no `Meta`.
312    fn edit(mut self, empty: bool, set: impl FnOnce(&mut Meta)) -> Self {
313        if empty && self.meta.is_none() { return self; }
314        set(self.meta_mut());
315        self.tidy()
316    }
317    /// The layout with `names` on its axes. A Rank error when the count differs from the rank, and a Domain error when a name repeats.
318    pub fn with_names(self, names: Vec<Option<Arc<str>>>) -> Result<Self, Error> {
319        if !names.is_empty() && names.len() != self.shape.len() {
320            return Err(Error::new(Kind::Rank, format!("{} names for {} axes", names.len(), self.shape.len())));
321        }
322        if let Some(name) = repeated_name(&names) { return Err(Error::new(Kind::Domain, format!("the result would have two axes named {}", shown(name)))); }
323        Ok(self.inherit_names(names))
324    }
325    /// The layout with `names`, which the caller has checked: one for each axis, or none.
326    pub fn inherit_names(self, names: Vec<Option<Arc<str>>>) -> Self {
327        assert!(names.is_empty() || names.len() == self.shape.len());
328        let empty = names.iter().all(Option::is_none);
329        self.edit(empty, |m| m.names = if empty { vec![] } else { names })
330    }
331    /// The layout without any name that appears on more than one axis.
332    pub fn unique_names(mut self) -> Self {
333        let Some(meta) = self.meta.as_mut() else { return self };
334        let mut counts = HashMap::new();
335        for name in meta.names.iter().flatten() { *counts.entry(name.clone()).or_insert(0) += 1; }
336        for name in &mut meta.names { if name.as_ref().is_some_and(|n| counts[n] > 1) { *name = None; } }
337        if meta.names.iter().all(Option::is_none) { meta.names.clear(); }
338        self.tidy()
339    }
340    #[inline]
341    fn key_list(&self) -> &[Option<Arc<Keys>>] { self.meta.as_ref().map_or(&[], |l| &l.keys) }
342    #[inline]
343    pub fn has_keys(&self) -> bool { !self.key_list().is_empty() }
344    /// Whether any axis has a name.
345    #[inline]
346    pub fn has_names(&self) -> bool { !self.names().is_empty() }
347    /// Whether the layout has no keys or names.
348    #[inline]
349    pub fn plain(&self) -> bool { self.meta.is_none() }
350    #[inline]
351    pub fn keys(&self, axis: usize) -> Option<&Arc<Keys>> { self.key_list().get(axis).and_then(Option::as_ref) }
352    /// The keys of every axis, with `None` for an axis without them.
353    pub fn all_keys(&self) -> Vec<Option<Arc<Keys>>> { (0..self.shape.len()).map(|a| self.keys(a).cloned()).collect() }
354    /// Whether shapes, assigned axis names and assigned keys match. An unlabelled axis matches either label set.
355    pub fn matches(&self, other: &Self) -> bool {
356        self.shape == other.shape && (0..self.shape.len()).all(|a| {
357            !names_conflict(self.name(a).map(AsRef::as_ref), other.name(a).map(AsRef::as_ref)) && match (self.keys(a), other.keys(a)) {
358                (Some(x), Some(y)) => !y.align(x).contains(&None), _ => true
359            }
360        })
361    }
362    /// The layout without keys on `axis`.
363    pub fn without_keys(self, axis: usize) -> Self {
364        if self.keys(axis).is_none() { return self; }
365        let mut keys = self.all_keys();
366        keys[axis] = None;
367        self.with_keys(keys).unwrap()
368    }
369    /// The layout with `keys` on its axes. A Rank error when the count differs from the rank, and a Length error when an axis's keys differ from its length.
370    pub fn with_keys(self, keys: Vec<Option<Arc<Keys>>>) -> Result<Self, Error> {
371        if !keys.is_empty() && keys.len() != self.shape.len() {
372            return Err(Error::new(Kind::Rank, format!("keys for {} axes of an array with {} axes", keys.len(), self.shape.len())));
373        }
374        if let Some((k, n)) = keys.iter().zip(self.shape.iter()).find_map(|(k, &n)| k.as_ref().filter(|k| k.len() != n).map(|k| (k.len(), n))) {
375            return Err(Error::new(Kind::Length, format!("{k} keys for an axis of length {n}")));
376        }
377        let keys: Vec<_> = keys.into_iter().map(|k| k.filter(|k| !k.blank())).collect();
378        let empty = keys.iter().all(Option::is_none);
379        Ok(self.edit(empty, |m| m.keys = if empty { vec![] } else { keys }))
380    }
381    /// A layout with one axis for each of `sources`: a layout and one of its axes, whose length, keys and name the new axis takes.
382    fn gathered<'a>(sources: impl Iterator<Item = (&'a Self, usize)> + Clone) -> Self {
383        let shape: Shape = sources.clone().map(|(l, a)| l.shape[a]).collect();
384        if sources.clone().all(|(l, _)| l.plain()) { return Self::from(shape); }
385        let keys = sources.clone().map(|(l, a)| l.keys(a).cloned()).collect();
386        let names = sources.map(|(l, a)| l.name(a).cloned()).collect();
387        Self::from(shape).with_keys(keys).unwrap().inherit_names(names)
388    }
389    /// The layout of `axes`, in that order.
390    pub fn axes(&self, axes: impl Iterator<Item = usize> + Clone) -> Self { Self::gathered(axes.map(|a| (self, a))) }
391    /// This layout's axes, then `other`'s.
392    pub fn concat(&self, other: &Self) -> Self { Self::gathered((0..self.shape.len()).map(|a| (self, a)).chain((0..other.shape.len()).map(|a| (other, a)))) }
393    /// The layout of a product such as `+.×`, which contracts the last axis of a left argument of this layout with the first axis of a right argument of `right`.
394    pub fn contracted(&self, right: &Self) -> Self { self.axes(0..self.shape.len().saturating_sub(1)).concat(&right.axes(1..right.shape.len())) }
395    /// The layout with the axes in `axes` merged into one axis of `len` positions, which has no keys or name. An empty range adds that axis.
396    pub fn merged(&self, axes: std::ops::Range<usize>, len: usize) -> Self {
397        let shape = Shape::spliced([&self.shape[..axes.start], &[len], &self.shape[axes.end..]]);
398        if self.plain() { return Self::from(shape); }
399        let source = |a: usize| match a.cmp(&axes.start) {
400            std::cmp::Ordering::Less => Some(a), std::cmp::Ordering::Equal => None, std::cmp::Ordering::Greater => Some(a - 1 + axes.len())
401        };
402        let keys = (0..shape.len()).map(|a| source(a).and_then(|s| self.keys(s).cloned())).collect();
403        let names = (0..shape.len()).map(|a| source(a).and_then(|s| self.name(s).cloned())).collect();
404        Self::from(shape).with_keys(keys).unwrap().inherit_names(names)
405    }
406    /// The layout with `axis` holding the positions it reads at `positions`, keeping their keys. `None` reads no position and has no key. A repeated key leaves the axis without keys.
407    pub fn select(&self, axis: usize, positions: impl ExactSizeIterator<Item = Option<usize>>) -> Result<Self, Error> {
408        let mut layout = self.clone();
409        layout.shape[axis] = positions.len();
410        let Some(keys) = self.keys(axis) else { return Ok(layout) };
411        let mut all = self.all_keys();
412        all[axis] = keys.select(positions).ok();
413        layout.with_keys(all)
414    }
415    /// Grows the first axis by `len` positions. `names` gives their keys. A Domain error, with the layout unchanged, when one of them is already on that axis or appears twice.
416    pub fn append(&mut self, len: usize, names: Option<&[Option<Arc<str>>]>) -> Result<(), Error> {
417        let (old, rank) = (self.shape[0], self.shape.len());
418        if let Some(names) = names {
419            match self.meta.as_mut().and_then(|m| m.keys.first_mut()).and_then(Option::as_mut) {
420                Some(keys) => Arc::make_mut(keys).extend(names)?,
421                None => {
422                    let keys = Keys::partial(std::iter::repeat_n(None, old).chain(names.iter().cloned()).collect())?;
423                    let meta = self.meta_mut();
424                    if meta.keys.is_empty() { meta.keys = vec![None; rank]; }
425                    meta.keys[0] = Some(keys);
426                }
427            }
428        }
429        self.shape[0] += len;
430        Ok(())
431    }
432}