Skip to main content

tenferro_ops/
shape_extent.rs

1//! Shape extent metadata with exactness guarantees.
2
3/// A dimension expression plus the guarantee it provides.
4///
5/// `Exact` means the expression is the runtime size. `UpperBound` means the
6/// runtime size is no larger than the expression. `Unknown` preserves rank
7/// when no useful bound is available.
8///
9/// # Examples
10///
11/// ```
12/// use tenferro_ops::shape_extent::ShapeExtent;
13///
14/// let extent = ShapeExtent::exact(4usize);
15/// assert_eq!(extent.as_exact(), Some(&4));
16/// ```
17#[derive(Clone, Debug, PartialEq, Eq, Hash)]
18pub enum ShapeExtent<D> {
19    /// The dimension expression is exact.
20    Exact(D),
21    /// The dimension expression is an upper bound.
22    UpperBound(D),
23    /// The dimension is rank-known but otherwise unknown.
24    Unknown,
25}
26
27impl<D> ShapeExtent<D> {
28    /// Construct an exact extent.
29    ///
30    /// # Examples
31    ///
32    /// ```
33    /// use tenferro_ops::shape_extent::ShapeExtent;
34    ///
35    /// let extent = ShapeExtent::exact(3usize);
36    /// assert!(extent.is_exact());
37    /// ```
38    pub fn exact(dim: D) -> Self {
39        Self::Exact(dim)
40    }
41
42    /// Construct an upper-bound extent.
43    ///
44    /// # Examples
45    ///
46    /// ```
47    /// use tenferro_ops::shape_extent::ShapeExtent;
48    ///
49    /// let extent = ShapeExtent::upper_bound(3usize);
50    /// assert!(!extent.is_exact());
51    /// ```
52    pub fn upper_bound(dim: D) -> Self {
53        Self::UpperBound(dim)
54    }
55
56    /// Construct an unknown extent.
57    ///
58    /// # Examples
59    ///
60    /// ```
61    /// use tenferro_ops::shape_extent::ShapeExtent;
62    ///
63    /// let extent: ShapeExtent<usize> = ShapeExtent::unknown();
64    /// assert_eq!(extent.bound_expr(), None);
65    /// ```
66    pub fn unknown() -> Self {
67        Self::Unknown
68    }
69
70    /// Return true when this extent is exact.
71    ///
72    /// # Examples
73    ///
74    /// ```
75    /// use tenferro_ops::shape_extent::ShapeExtent;
76    ///
77    /// assert!(ShapeExtent::exact(2usize).is_exact());
78    /// assert!(!ShapeExtent::upper_bound(2usize).is_exact());
79    /// ```
80    pub fn is_exact(&self) -> bool {
81        matches!(self, Self::Exact(_))
82    }
83
84    /// Return the exact dimension expression, if this extent is exact.
85    ///
86    /// # Examples
87    ///
88    /// ```
89    /// use tenferro_ops::shape_extent::ShapeExtent;
90    ///
91    /// assert_eq!(ShapeExtent::exact(5usize).as_exact(), Some(&5));
92    /// assert_eq!(ShapeExtent::upper_bound(5usize).as_exact(), None);
93    /// ```
94    pub fn as_exact(&self) -> Option<&D> {
95        match self {
96            Self::Exact(dim) => Some(dim),
97            Self::UpperBound(_) | Self::Unknown => None,
98        }
99    }
100
101    /// Return the known bound expression, if any.
102    ///
103    /// # Examples
104    ///
105    /// ```
106    /// use tenferro_ops::shape_extent::ShapeExtent;
107    ///
108    /// assert_eq!(ShapeExtent::upper_bound(5usize).bound_expr(), Some(&5));
109    /// ```
110    pub fn bound_expr(&self) -> Option<&D> {
111        match self {
112            Self::Exact(dim) | Self::UpperBound(dim) => Some(dim),
113            Self::Unknown => None,
114        }
115    }
116
117    /// Map the contained dimension expression while preserving exactness.
118    ///
119    /// # Examples
120    ///
121    /// ```
122    /// use tenferro_ops::shape_extent::ShapeExtent;
123    ///
124    /// let extent = ShapeExtent::upper_bound(5usize).map(|dim| dim + 1);
125    /// assert_eq!(extent.bound_expr(), Some(&6));
126    /// ```
127    pub fn map<E>(self, f: impl FnOnce(D) -> E) -> ShapeExtent<E> {
128        match self {
129            Self::Exact(dim) => ShapeExtent::Exact(f(dim)),
130            Self::UpperBound(dim) => ShapeExtent::UpperBound(f(dim)),
131            Self::Unknown => ShapeExtent::Unknown,
132        }
133    }
134}