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#[derive(Default, Copy, Clone, Eq, PartialEq, Hash)]
13pub struct Axes<T> {
14 pub x: T,
16 pub y: T,
18}
19
20impl<T> Axes<T> {
21 pub const fn new(x: T, y: T) -> Self {
23 Self { x, y }
24 }
25
26 pub fn splat(v: T) -> Self
28 where
29 T: Clone,
30 {
31 Self { x: v.clone(), y: v }
32 }
33
34 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 pub fn as_ref(&self) -> Axes<&T> {
44 Axes { x: &self.x, y: &self.y }
45 }
46
47 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 pub fn as_mut(&mut self) -> Axes<&mut T> {
57 Axes { x: &mut self.x, y: &mut self.y }
58 }
59
60 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 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 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 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 pub fn with_x(x: T) -> Self {
93 Self { x, y: T::default() }
94 }
95
96 pub fn with_y(y: T) -> Self {
98 Self { x: T::default(), y }
99 }
100}
101
102impl<T: Ord> Axes<T> {
103 pub fn min(self, other: Self) -> Self {
105 Self { x: self.x.min(other.x), y: self.y.min(other.y) }
106 }
107
108 pub fn max(self, other: Self) -> Self {
110 Self { x: self.x.max(other.x), y: self.y.max(other.y) }
111 }
112
113 pub fn min_by_side(self) -> T {
115 self.x.min(self.y)
116 }
117
118 pub fn max_by_side(self) -> T {
120 self.x.max(self.y)
121 }
122}
123
124impl Axes<Rel<Abs>> {
125 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#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
167pub enum Axis {
168 X,
170 Y,
172}
173
174impl Axis {
175 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 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 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 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}