typst_library/layout/
axes.rs

1use std::any::Any;
2use std::fmt::{self, Debug, Formatter};
3use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, Deref, Not};
4
5use typst_utils::Get;
6
7use crate::diag::bail;
8use crate::foundations::{array, cast, Array, Resolve, Smart, StyleChain};
9use crate::layout::{Abs, Dir, Length, Ratio, Rel, Size};
10
11/// A container with a horizontal and vertical component.
12#[derive(Default, Copy, Clone, Eq, PartialEq, Hash)]
13pub struct Axes<T> {
14    /// The horizontal component.
15    pub x: T,
16    /// The vertical component.
17    pub y: T,
18}
19
20impl<T> Axes<T> {
21    /// Create a new instance from the two components.
22    pub const fn new(x: T, y: T) -> Self {
23        Self { x, y }
24    }
25
26    /// Create a new instance with two equal components.
27    pub fn splat(v: T) -> Self
28    where
29        T: Clone,
30    {
31        Self { x: v.clone(), y: v }
32    }
33
34    /// Map the individual fields with `f`.
35    pub fn map<F, U>(self, mut f: F) -> Axes<U>
36    where
37        F: FnMut(T) -> U,
38    {
39        Axes { x: f(self.x), y: f(self.y) }
40    }
41
42    /// Convert from `&Axes<T>` to `Axes<&T>`.
43    pub fn as_ref(&self) -> Axes<&T> {
44        Axes { x: &self.x, y: &self.y }
45    }
46
47    /// Convert from `&Axes<T>` to `Axes<&<T as Deref>::Target>`.
48    pub fn as_deref(&self) -> Axes<&T::Target>
49    where
50        T: Deref,
51    {
52        Axes { x: &self.x, y: &self.y }
53    }
54
55    /// Convert from `&mut Axes<T>` to `Axes<&mut T>`.
56    pub fn as_mut(&mut self) -> Axes<&mut T> {
57        Axes { x: &mut self.x, y: &mut self.y }
58    }
59
60    /// Zip two instances into an instance over a tuple.
61    pub fn zip<U>(self, other: Axes<U>) -> Axes<(T, U)> {
62        Axes { x: (self.x, other.x), y: (self.y, other.y) }
63    }
64
65    /// Apply a function to this and another-instance componentwise.
66    pub fn zip_map<F, V, U>(self, other: Axes<V>, mut f: F) -> Axes<U>
67    where
68        F: FnMut(T, V) -> U,
69    {
70        Axes { x: f(self.x, other.x), y: f(self.y, other.y) }
71    }
72
73    /// Whether a condition is true for at least one of fields.
74    pub fn any<F>(self, mut f: F) -> bool
75    where
76        F: FnMut(&T) -> bool,
77    {
78        f(&self.x) || f(&self.y)
79    }
80
81    /// Whether a condition is true for both fields.
82    pub fn all<F>(self, mut f: F) -> bool
83    where
84        F: FnMut(&T) -> bool,
85    {
86        f(&self.x) && f(&self.y)
87    }
88}
89
90impl<T: Default> Axes<T> {
91    /// Create a new instance with y set to its default value.
92    pub fn with_x(x: T) -> Self {
93        Self { x, y: T::default() }
94    }
95
96    /// Create a new instance with x set to its default value.
97    pub fn with_y(y: T) -> Self {
98        Self { x: T::default(), y }
99    }
100}
101
102impl<T: Ord> Axes<T> {
103    /// The component-wise minimum of this and another instance.
104    pub fn min(self, other: Self) -> Self {
105        Self { x: self.x.min(other.x), y: self.y.min(other.y) }
106    }
107
108    /// The component-wise minimum of this and another instance.
109    pub fn max(self, other: Self) -> Self {
110        Self { x: self.x.max(other.x), y: self.y.max(other.y) }
111    }
112
113    /// The minimum of width and height.
114    pub fn min_by_side(self) -> T {
115        self.x.min(self.y)
116    }
117
118    /// The minimum of width and height.
119    pub fn max_by_side(self) -> T {
120        self.x.max(self.y)
121    }
122}
123
124impl Axes<Rel<Abs>> {
125    /// Evaluate the axes relative to the given `size`.
126    pub fn relative_to(&self, size: Size) -> Size {
127        Size {
128            x: self.x.relative_to(size.x),
129            y: self.y.relative_to(size.y),
130        }
131    }
132}
133
134impl<T> Get<Axis> for Axes<T> {
135    type Component = T;
136
137    fn get_ref(&self, axis: Axis) -> &T {
138        match axis {
139            Axis::X => &self.x,
140            Axis::Y => &self.y,
141        }
142    }
143
144    fn get_mut(&mut self, axis: Axis) -> &mut T {
145        match axis {
146            Axis::X => &mut self.x,
147            Axis::Y => &mut self.y,
148        }
149    }
150}
151
152impl<T> Debug for Axes<T>
153where
154    T: Debug + 'static,
155{
156    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
157        if (&self.x as &dyn Any).is::<Abs>() {
158            write!(f, "Size({:?}, {:?})", self.x, self.y)
159        } else {
160            write!(f, "Axes({:?}, {:?})", self.x, self.y)
161        }
162    }
163}
164
165/// The two layouting axes.
166#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
167pub enum Axis {
168    /// The horizontal axis.
169    X,
170    /// The vertical  axis.
171    Y,
172}
173
174impl Axis {
175    /// The direction with the given positivity for this axis.
176    pub fn dir(self, positive: bool) -> Dir {
177        match (self, positive) {
178            (Self::X, true) => Dir::LTR,
179            (Self::X, false) => Dir::RTL,
180            (Self::Y, true) => Dir::TTB,
181            (Self::Y, false) => Dir::BTT,
182        }
183    }
184
185    /// The other axis.
186    pub fn other(self) -> Self {
187        match self {
188            Self::X => Self::Y,
189            Self::Y => Self::X,
190        }
191    }
192}
193
194cast! {
195    Axis,
196    self => match self {
197        Self::X => "horizontal".into_value(),
198        Self::Y => "vertical".into_value(),
199    },
200    "horizontal" => Self::X,
201    "vertical" => Self::Y,
202}
203
204impl<T> Axes<Smart<T>> {
205    /// Unwrap the individual fields.
206    pub fn unwrap_or(self, other: Axes<T>) -> Axes<T> {
207        Axes {
208            x: self.x.unwrap_or(other.x),
209            y: self.y.unwrap_or(other.y),
210        }
211    }
212}
213
214impl Axes<bool> {
215    /// Select `t.x` if `self.x` is true and `f.x` otherwise and same for `y`.
216    pub fn select<T>(self, t: Axes<T>, f: Axes<T>) -> Axes<T> {
217        Axes {
218            x: if self.x { t.x } else { f.x },
219            y: if self.y { t.y } else { f.y },
220        }
221    }
222}
223
224impl Not for Axes<bool> {
225    type Output = Self;
226
227    fn not(self) -> Self::Output {
228        Self { x: !self.x, y: !self.y }
229    }
230}
231
232impl BitOr for Axes<bool> {
233    type Output = Self;
234
235    fn bitor(self, rhs: Self) -> Self::Output {
236        Self { x: self.x | rhs.x, y: self.y | rhs.y }
237    }
238}
239
240impl BitOr<bool> for Axes<bool> {
241    type Output = Self;
242
243    fn bitor(self, rhs: bool) -> Self::Output {
244        Self { x: self.x | rhs, y: self.y | rhs }
245    }
246}
247
248impl BitAnd for Axes<bool> {
249    type Output = Self;
250
251    fn bitand(self, rhs: Self) -> Self::Output {
252        Self { x: self.x & rhs.x, y: self.y & rhs.y }
253    }
254}
255
256impl BitAnd<bool> for Axes<bool> {
257    type Output = Self;
258
259    fn bitand(self, rhs: bool) -> Self::Output {
260        Self { x: self.x & rhs, y: self.y & rhs }
261    }
262}
263
264impl BitOrAssign for Axes<bool> {
265    fn bitor_assign(&mut self, rhs: Self) {
266        self.x |= rhs.x;
267        self.y |= rhs.y;
268    }
269}
270
271impl BitAndAssign for Axes<bool> {
272    fn bitand_assign(&mut self, rhs: Self) {
273        self.x &= rhs.x;
274        self.y &= rhs.y;
275    }
276}
277
278cast! {
279    Axes<Rel<Length>>,
280    self => array![self.x, self.y].into_value(),
281    array: Array => {
282        let mut iter = array.into_iter();
283        match (iter.next(), iter.next(), iter.next()) {
284            (Some(a), Some(b), None) => Axes::new(a.cast()?, b.cast()?),
285            _ => bail!("point array must contain exactly two entries"),
286        }
287    },
288}
289
290cast! {
291    Axes<Ratio>,
292    self => array![self.x, self.y].into_value(),
293    array: Array => {
294        let mut iter = array.into_iter();
295        match (iter.next(), iter.next(), iter.next()) {
296            (Some(a), Some(b), None) => Axes::new(a.cast()?, b.cast()?),
297            _ => bail!("ratio array must contain exactly two entries"),
298        }
299    },
300}
301
302cast! {
303    Axes<Length>,
304    self => array![self.x, self.y].into_value(),
305    array: Array => {
306        let mut iter = array.into_iter();
307        match (iter.next(), iter.next(), iter.next()) {
308            (Some(a), Some(b), None) => Axes::new(a.cast()?, b.cast()?),
309            _ => bail!("length array must contain exactly two entries"),
310        }
311    },
312}
313
314impl<T: Resolve> Resolve for Axes<T> {
315    type Output = Axes<T::Output>;
316
317    fn resolve(self, styles: StyleChain) -> Self::Output {
318        self.map(|v| v.resolve(styles))
319    }
320}