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::{HintedStrResult, bail};
8use crate::foundations::{
9 Array, CastInfo, FromValue, IntoValue, Reflect, Resolve, Smart, StyleChain, Value,
10 array, cast,
11};
12use crate::layout::{Abs, Dir, Rel, Size};
13
14#[derive(Default, Copy, Clone, Eq, PartialEq, Hash)]
16pub struct Axes<T> {
17 pub x: T,
19 pub y: T,
21}
22
23impl<T> Axes<T> {
24 pub const fn new(x: T, y: T) -> Self {
26 Self { x, y }
27 }
28
29 pub fn splat(v: T) -> Self
31 where
32 T: Clone,
33 {
34 Self { x: v.clone(), y: v }
35 }
36
37 pub fn map<F, U>(self, mut f: F) -> Axes<U>
39 where
40 F: FnMut(T) -> U,
41 {
42 Axes { x: f(self.x), y: f(self.y) }
43 }
44
45 pub fn as_ref(&self) -> Axes<&T> {
47 Axes { x: &self.x, y: &self.y }
48 }
49
50 pub fn as_deref(&self) -> Axes<&T::Target>
52 where
53 T: Deref,
54 {
55 Axes { x: &self.x, y: &self.y }
56 }
57
58 pub fn as_mut(&mut self) -> Axes<&mut T> {
60 Axes { x: &mut self.x, y: &mut self.y }
61 }
62
63 pub fn zip<U>(self, other: Axes<U>) -> Axes<(T, U)> {
65 Axes { x: (self.x, other.x), y: (self.y, other.y) }
66 }
67
68 pub fn zip_map<F, V, U>(self, other: Axes<V>, mut f: F) -> Axes<U>
70 where
71 F: FnMut(T, V) -> U,
72 {
73 Axes { x: f(self.x, other.x), y: f(self.y, other.y) }
74 }
75
76 pub fn any<F>(self, mut f: F) -> bool
78 where
79 F: FnMut(&T) -> bool,
80 {
81 f(&self.x) || f(&self.y)
82 }
83
84 pub fn all<F>(self, mut f: F) -> bool
86 where
87 F: FnMut(&T) -> bool,
88 {
89 f(&self.x) && f(&self.y)
90 }
91}
92
93impl<T: Default> Axes<T> {
94 pub fn with_x(x: T) -> Self {
96 Self { x, y: T::default() }
97 }
98
99 pub fn with_y(y: T) -> Self {
101 Self { x: T::default(), y }
102 }
103}
104
105impl<T: Ord> Axes<T> {
106 pub fn min(self, other: Self) -> Self {
108 Self { x: self.x.min(other.x), y: self.y.min(other.y) }
109 }
110
111 pub fn max(self, other: Self) -> Self {
113 Self { x: self.x.max(other.x), y: self.y.max(other.y) }
114 }
115
116 pub fn min_by_side(self) -> T {
118 self.x.min(self.y)
119 }
120
121 pub fn max_by_side(self) -> T {
123 self.x.max(self.y)
124 }
125}
126
127impl Axes<Rel<Abs>> {
128 pub fn relative_to(&self, size: Size) -> Size {
130 Size {
131 x: self.x.relative_to(size.x),
132 y: self.y.relative_to(size.y),
133 }
134 }
135}
136
137impl<T> Get<Axis> for Axes<T> {
138 type Component = T;
139
140 fn get_ref(&self, axis: Axis) -> &T {
141 match axis {
142 Axis::X => &self.x,
143 Axis::Y => &self.y,
144 }
145 }
146
147 fn get_mut(&mut self, axis: Axis) -> &mut T {
148 match axis {
149 Axis::X => &mut self.x,
150 Axis::Y => &mut self.y,
151 }
152 }
153}
154
155impl<T> Debug for Axes<T>
156where
157 T: Debug + 'static,
158{
159 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
160 if (&self.x as &dyn Any).is::<Abs>() {
161 write!(f, "Size({:?}, {:?})", self.x, self.y)
162 } else {
163 write!(f, "Axes({:?}, {:?})", self.x, self.y)
164 }
165 }
166}
167
168#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
170pub enum Axis {
171 X,
173 Y,
175}
176
177impl Axis {
178 pub fn dir(self, positive: bool) -> Dir {
180 match (self, positive) {
181 (Self::X, true) => Dir::LTR,
182 (Self::X, false) => Dir::RTL,
183 (Self::Y, true) => Dir::TTB,
184 (Self::Y, false) => Dir::BTT,
185 }
186 }
187
188 pub fn other(self) -> Self {
190 match self {
191 Self::X => Self::Y,
192 Self::Y => Self::X,
193 }
194 }
195}
196
197cast! {
198 Axis,
199 self => match self {
200 Self::X => "horizontal".into_value(),
201 Self::Y => "vertical".into_value(),
202 },
203 "horizontal" => Self::X,
204 "vertical" => Self::Y,
205}
206
207impl<T> Axes<Smart<T>> {
208 pub fn unwrap_or(self, other: Axes<T>) -> Axes<T> {
210 Axes {
211 x: self.x.unwrap_or(other.x),
212 y: self.y.unwrap_or(other.y),
213 }
214 }
215}
216
217impl Axes<bool> {
218 pub fn select<T>(self, t: Axes<T>, f: Axes<T>) -> Axes<T> {
220 Axes {
221 x: if self.x { t.x } else { f.x },
222 y: if self.y { t.y } else { f.y },
223 }
224 }
225}
226
227impl Not for Axes<bool> {
228 type Output = Self;
229
230 fn not(self) -> Self::Output {
231 Self { x: !self.x, y: !self.y }
232 }
233}
234
235impl BitOr for Axes<bool> {
236 type Output = Self;
237
238 fn bitor(self, rhs: Self) -> Self::Output {
239 Self { x: self.x | rhs.x, y: self.y | rhs.y }
240 }
241}
242
243impl BitOr<bool> for Axes<bool> {
244 type Output = Self;
245
246 fn bitor(self, rhs: bool) -> Self::Output {
247 Self { x: self.x | rhs, y: self.y | rhs }
248 }
249}
250
251impl BitAnd for Axes<bool> {
252 type Output = Self;
253
254 fn bitand(self, rhs: Self) -> Self::Output {
255 Self { x: self.x & rhs.x, y: self.y & rhs.y }
256 }
257}
258
259impl BitAnd<bool> for Axes<bool> {
260 type Output = Self;
261
262 fn bitand(self, rhs: bool) -> Self::Output {
263 Self { x: self.x & rhs, y: self.y & rhs }
264 }
265}
266
267impl BitOrAssign for Axes<bool> {
268 fn bitor_assign(&mut self, rhs: Self) {
269 self.x |= rhs.x;
270 self.y |= rhs.y;
271 }
272}
273
274impl BitAndAssign for Axes<bool> {
275 fn bitand_assign(&mut self, rhs: Self) {
276 self.x &= rhs.x;
277 self.y &= rhs.y;
278 }
279}
280
281impl<T: Reflect> Reflect for Axes<T> {
282 fn input() -> CastInfo {
283 Array::input()
284 }
285
286 fn output() -> CastInfo {
287 Array::output()
288 }
289
290 fn castable(value: &Value) -> bool {
291 Array::castable(value)
292 }
293}
294
295impl<T: FromValue> FromValue for Axes<T> {
296 fn from_value(value: Value) -> HintedStrResult<Self> {
297 let array = value.cast::<Array>()?;
298 let mut iter = array.into_iter();
299 match (iter.next(), iter.next(), iter.next()) {
300 (Some(a), Some(b), None) => Ok(Axes::new(a.cast()?, b.cast()?)),
301 _ => bail!(
302 "array must contain exactly two items";
303 hint: "the first item determines the value for the X axis \
304 and the second item the value for the Y axis"
305 ),
306 }
307 }
308}
309
310impl<T: IntoValue> IntoValue for Axes<T> {
311 fn into_value(self) -> Value {
312 array![self.x.into_value(), self.y.into_value()].into_value()
313 }
314}
315
316impl<T: Resolve> Resolve for Axes<T> {
317 type Output = Axes<T::Output>;
318
319 fn resolve(self, styles: StyleChain) -> Self::Output {
320 self.map(|v| v.resolve(styles))
321 }
322}