use crate::{Axis, AxisMap};
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub(crate) enum Extent {
Static(usize),
Dynamic,
}
impl Extent {
pub(crate) fn get(self) -> usize {
match self {
Extent::Static(n) => n,
Extent::Dynamic => {
panic!("Extent::get: this axis is Dynamic; its size is only known at runtime")
}
}
}
pub(crate) fn is_dynamic(self) -> bool {
matches!(self, Extent::Dynamic)
}
pub(crate) fn broadcast(self, other: Extent) -> Extent {
match (self, other) {
(Extent::Static(1), b) => b,
(a, Extent::Static(1)) => a,
(Extent::Dynamic, _) | (_, Extent::Dynamic) => Extent::Dynamic,
(Extent::Static(a), Extent::Static(b)) if a == b => Extent::Static(a),
_ => panic!("Space::merge: axis appears with conflicting extents"),
}
}
}
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct Shape {
extents: AxisMap<Extent>,
}
impl Shape {
pub(crate) fn new(extents: &[(Axis, Extent)]) -> Self {
Shape {
extents: AxisMap::new(extents),
}
}
pub fn rank(&self) -> usize {
self.extents.len()
}
pub fn axis_at(&self, i: usize) -> Axis {
self.extents.axis_at(i)
}
pub fn position(&self, axis: Axis) -> usize {
self.extents.position(axis)
}
pub fn contains(&self, axis: Axis) -> bool {
self.extents.contains(axis)
}
pub fn axes(&self) -> impl Iterator<Item = Axis> + '_ {
self.extents.axes()
}
pub(crate) fn extent_raw(&self, axis: Axis) -> Extent {
self.extents.get(axis)
}
pub fn extent(&self, axis: Axis) -> usize {
self.extent_raw(axis).get()
}
pub fn extent_at(&self, i: usize) -> usize {
self.extent(self.axis_at(i))
}
pub fn is_dynamic(&self, axis: Axis) -> bool {
self.extent_raw(axis).is_dynamic()
}
pub(crate) fn is_static(&self) -> bool {
self.axes().all(|axis| !self.is_dynamic(axis))
}
pub(crate) fn subspace(&self, axes: &[Axis]) -> Shape {
let entries: Vec<_> = axes.iter().map(|&a| (a, self.extent_raw(a))).collect();
Shape::new(&entries)
}
}