cursive_core/
vec.rs

1//! Points on the 2D character grid.
2
3use std::cmp::{max, min, Ordering};
4use std::ops::{Add, Div, Mul, Sub};
5
6use num::traits::Zero;
7
8use crate::div;
9use crate::XY;
10
11/// Simple 2D size, in cells.
12///
13/// Note: due to a bug in rustdoc ([#32077]), the documentation for `Vec2` is
14/// currently shown on the [`XY`] page.
15///
16/// [#32077]: https://github.com/rust-lang/rust/issues/32077
17/// [`XY`]: crate::XY
18pub type Vec2 = XY<usize>;
19
20/// A signed 2D quantity, in cells.
21///
22/// Usually represents an offset.
23pub type Vec2i = XY<isize>;
24
25impl<T: PartialOrd> PartialOrd for XY<T> {
26    /// `a < b` <=> `a.x < b.x && a.y < b.y`
27    fn partial_cmp(&self, other: &XY<T>) -> Option<Ordering> {
28        if self == other {
29            Some(Ordering::Equal)
30        } else if self.x < other.x && self.y < other.y {
31            Some(Ordering::Less)
32        } else if self.x > other.x && self.y > other.y {
33            Some(Ordering::Greater)
34        } else {
35            None
36        }
37    }
38}
39
40impl XY<f32> {
41    /// Returns the given vector, rotated by an angle in radians.
42    pub fn rotated(self, angle_rad: f32) -> Self {
43        let c = angle_rad.cos();
44        let s = angle_rad.sin();
45
46        Self::new(self.x * c - self.y * s, self.x * s + self.y * c)
47    }
48}
49
50impl XY<usize> {
51    /// A `Vec2` with `usize::MAX` in each axis.
52    pub const MAX: XY<usize> = XY {
53        x: usize::MAX,
54        y: usize::MAX,
55    };
56
57    /// The origin, `{ x: 0, y: 0 }`.
58    pub const ZERO: XY<usize> = XY { x: 0, y: 0 };
59
60    /// The unit X vector `{ x: 1, y: 0 }`.
61    pub const X: XY<usize> = XY::new(1, 0);
62
63    /// The unit Y vector `{ x: 0, y: 1 }`.
64    pub const Y: XY<usize> = XY::new(0, 1);
65
66    /// Returns a `Vec2` with `usize::MAX` in each axis.
67    ///
68    /// # Examples
69    ///
70    /// ```rust
71    /// # use cursive_core::Vec2;
72    /// assert!(Vec2::new(9999, 9999) < Vec2::max_value());
73    /// ```
74    #[must_use]
75    pub const fn max_value() -> Self {
76        Self::new(usize::MAX, usize::MAX)
77    }
78
79    /// Saturating subtraction. Computes `self - other`, saturating at 0.
80    ///
81    /// Never panics.
82    ///
83    /// # Examples
84    ///
85    /// ```rust
86    /// # use cursive_core::Vec2;
87    /// let u = Vec2::new(1, 2);
88    /// let v = Vec2::new(2, 1);
89    /// assert_eq!(u.saturating_sub(v), Vec2::new(0, 1));
90    /// ```
91    #[must_use]
92    pub fn saturating_sub<O: Into<Self>>(&self, other: O) -> Self {
93        let other = other.into();
94        self.zip_map(other, usize::saturating_sub)
95    }
96
97    /// Saturating addition with a signed vec.
98    ///
99    /// Any coordinates saturates to 0.
100    ///
101    /// # Examples
102    ///
103    /// ```rust
104    /// # use cursive_core::Vec2;
105    /// # use cursive_core::XY;
106    /// let u = Vec2::new(1, 2);
107    /// let v = XY::<isize>::new(-2, 1);
108    /// assert_eq!(u.saturating_add(v), Vec2::new(0, 3));
109    /// ```
110    #[must_use]
111    pub fn saturating_add<O: Into<XY<isize>>>(&self, other: O) -> Self {
112        let other = other.into();
113
114        self.zip_map(other, |s, o| {
115            if o > 0 {
116                s.saturating_add(o as usize)
117            } else {
118                s.saturating_sub((-o) as usize)
119            }
120        })
121    }
122
123    /// Checked addition with a signed vec.
124    ///
125    /// Will return `None` if any coordinates exceeds bounds.
126    pub fn checked_add<O: Into<XY<isize>>>(&self, other: O) -> Option<Self> {
127        let other = other.into();
128        self.zip_map(other, |s, o| {
129            if o > 0 {
130                s.checked_add(o as usize)
131            } else {
132                s.checked_sub((-o) as usize)
133            }
134        })
135        .both()
136    }
137
138    /// Term-by-term integer division that rounds up.
139    ///
140    /// # Examples
141    ///
142    /// ```rust
143    /// # use cursive_core::Vec2;
144    /// let u = Vec2::new(1, 6);
145    /// let v = Vec2::new(2, 3);
146    /// assert_eq!(u.div_up(v), Vec2::new(1, 2));
147    /// ```
148    #[must_use]
149    pub fn div_up<O>(&self, other: O) -> Self
150    where
151        O: Into<Self>,
152    {
153        self.zip_map(other.into(), div::div_up)
154    }
155
156    /// Checked subtraction. Computes `self - other` if possible.
157    ///
158    /// Returns `None` if `self.x < other.x || self.y < other.y`.
159    ///
160    /// Never panics.
161    ///
162    /// # Examples
163    ///
164    /// ```rust
165    /// # use cursive_core::Vec2;
166    /// let xy = Vec2::new(1, 2);
167    /// assert_eq!(xy.checked_sub((1, 1)), Some(Vec2::new(0, 1)));
168    /// assert_eq!(xy.checked_sub((2, 2)), None);
169    /// ```
170    pub fn checked_sub<O: Into<Self>>(&self, other: O) -> Option<Self> {
171        let other = other.into();
172        if self.fits(other) {
173            Some(*self - other)
174        } else {
175            None
176        }
177    }
178
179    /// Returns a `XY<isize>` from `self`.
180    ///
181    /// # Examples
182    ///
183    /// ```rust
184    /// # use cursive_core::Vec2;
185    /// # use cursive_core::XY;
186    /// let v: XY<isize> = Vec2::new(1, 2).signed().map(|i| i - 5);
187    /// assert_eq!(v, XY::new(-4, -3));
188    ///
189    /// let u = Vec2::new(3, 4);
190    /// assert_eq!(u.saturating_add(v), Vec2::new(0, 1));
191    /// ```
192    pub const fn signed(self) -> XY<isize> {
193        XY::new(self.x as isize, self.y as isize)
194    }
195
196    /// Returns the square distance between `a` and `b`.
197    pub fn sq_distance(a: Self, b: Self) -> usize {
198        (a.signed() - b.signed()).map(|x| (x * x) as usize).sum()
199    }
200}
201
202impl<T: Sub<Output = T> + Mul<Output = T> + Add<Output = T> + Copy> XY<T> {
203    /// Returns the square distance between `a` and `b`.
204    pub fn sq_norm(self) -> T {
205        self.map(|x| (x * x)).sum()
206    }
207}
208
209impl<T: Ord> XY<T> {
210    /// Returns `true` if `self` could fit inside `other`.
211    ///
212    /// Shortcut for `self.x <= other.x && self.y <= other.y`.
213    ///
214    /// If this returns `true`, then `other - self` will not underflow.
215    ///
216    /// # Examples
217    ///
218    /// ```rust
219    /// # use cursive_core::Vec2;
220    /// let v = Vec2::new(1, 2);
221    /// assert!(v.fits_in((1, 2)));
222    /// assert!(v.fits_in((3, 3)));
223    /// assert!(!v.fits_in((2, 1)));
224    /// ```
225    pub fn fits_in<O: Into<Self>>(&self, other: O) -> bool {
226        let other = other.into();
227        self.x <= other.x && self.y <= other.y
228    }
229
230    /// Returns `true` if `other` could fit inside `self`.
231    ///
232    /// Shortcut for `self.x >= other.x && self.y >= other.y`.
233    ///
234    /// If this returns `true`, then `self - other` will not underflow.
235    ///
236    /// # Examples
237    ///
238    /// ```rust
239    /// # use cursive_core::Vec2;
240    /// let v = Vec2::new(1, 2);
241    /// assert!(v.fits((1, 2)));
242    /// assert!(v.fits((0, 0)));
243    /// assert!(!v.fits((2, 1)));
244    /// ```
245    pub fn fits<O: Into<Self>>(&self, other: O) -> bool {
246        let other = other.into();
247        self.x >= other.x && self.y >= other.y
248    }
249
250    /// Returns `true` if `other` is strictly less than `self` in each axis.
251    pub fn strictly_lt<O: Into<Self>>(&self, other: O) -> bool {
252        let other = other.into();
253        self < &other
254    }
255
256    /// Returns `true` if `other` is strictly greater than `self` in each axis.
257    pub fn strictly_gt<O: Into<Self>>(&self, other: O) -> bool {
258        let other = other.into();
259        self > &other
260    }
261
262    /// Returns a new Vec2 that is a maximum per coordinate.
263    ///
264    /// # Examples
265    ///
266    /// ```rust
267    /// # use cursive_core::Vec2;
268    /// assert_eq!(Vec2::max((1, 2), (3, 1)), Vec2::new(3, 2));
269    /// ```
270    #[must_use]
271    pub fn max<A: Into<XY<T>>, B: Into<XY<T>>>(a: A, b: B) -> Self {
272        let a = a.into();
273        let b = b.into();
274        a.zip_map(b, max)
275    }
276
277    /// Returns a new Vec2 that is no larger than any input in both dimensions.
278    ///
279    /// # Examples
280    ///
281    /// ```rust
282    /// # use cursive_core::Vec2;
283    /// assert_eq!(Vec2::min((1, 2), (3, 1)), Vec2::new(1, 1));
284    /// ```
285    #[must_use]
286    pub fn min<A: Into<XY<T>>, B: Into<XY<T>>>(a: A, b: B) -> Self {
287        let a = a.into();
288        let b = b.into();
289        a.zip_map(b, min)
290    }
291
292    /// Returns the minimum of `self` and `other`.
293    ///
294    /// This is equivalent to `Vec2::min(self, other)`.
295    #[must_use]
296    pub fn or_min<O: Into<XY<T>>>(self, other: O) -> Self {
297        Self::min(self, other)
298    }
299
300    /// Returns the maximum of `self` and `other`.
301    ///
302    /// This is equivalent to `Vec2::max(self, other)`.
303    #[must_use]
304    pub fn or_max<O: Into<XY<T>>>(self, other: O) -> Self {
305        Self::max(self, other)
306    }
307}
308
309impl<T: Ord + Add<Output = T> + Clone> XY<T> {
310    /// Returns (max(self.x,other.x), self.y+other.y)
311    #[must_use]
312    pub fn stack_vertical(&self, other: &Self) -> Self {
313        Self::new(
314            max(self.x.clone(), other.x.clone()),
315            self.y.clone() + other.y.clone(),
316        )
317    }
318
319    /// Returns (self.x+other.x, max(self.y,other.y))
320    #[must_use]
321    pub fn stack_horizontal(&self, other: &Self) -> Self {
322        Self::new(
323            self.x.clone() + other.x.clone(),
324            max(self.y.clone(), other.y.clone()),
325        )
326    }
327
328    /// Returns `true` if `self` fits in the given rectangle.
329    pub fn fits_in_rect<O1, O2>(&self, top_left: O1, size: O2) -> bool
330    where
331        O1: Into<Self>,
332        O2: Into<Self>,
333    {
334        let top_left = top_left.into();
335        self.fits(top_left.clone()) && self < &(top_left + size)
336    }
337}
338
339impl<T: Add> XY<T> {
340    /// Returns `self.x + self.y`.
341    pub fn sum(self) -> T::Output {
342        self.fold(std::ops::Add::add)
343    }
344}
345
346impl<T: Mul> XY<T> {
347    /// Returns `self.x * self.y`
348    pub fn product(self) -> T::Output {
349        self.fold(std::ops::Mul::mul)
350    }
351}
352
353impl<T: Zero + Clone> XY<T> {
354    /// Returns a vector with the X component of self, and y=0.
355    ///
356    /// # Examples
357    ///
358    /// ```rust
359    /// # use cursive_core::XY;
360    /// let xy = XY::new(1, 2);
361    /// assert_eq!(xy.keep_x(), XY::new(1, 0));
362    /// ```
363    #[must_use]
364    pub fn keep_x(&self) -> Self {
365        Self::new(self.x.clone(), T::zero())
366    }
367
368    /// Returns a vector with the Y component of self, and x=0.
369    ///
370    /// # Examples
371    ///
372    /// ```rust
373    /// # use cursive_core::XY;
374    /// let xy = XY::new(1, 2);
375    /// assert_eq!(xy.keep_y(), XY::new(0, 2));
376    /// ```
377    #[must_use]
378    pub fn keep_y(&self) -> Self {
379        Self::new(T::zero(), self.y.clone())
380    }
381}
382
383impl<T: Zero> XY<T> {
384    /// Alias for `Self::new(0,0)`.
385    ///
386    /// # Examples
387    ///
388    /// ```rust
389    /// # use cursive_core::Vec2;
390    /// assert_eq!(Vec2::zero(), Vec2::new(0, 0));
391    /// ```
392    #[must_use]
393    pub fn zero() -> Self {
394        Self::new(T::zero(), T::zero())
395    }
396}
397
398impl<'a, T> From<&'a XY<T>> for XY<T>
399where
400    T: Clone,
401{
402    /// Clone a XY
403    ///
404    /// # Examples
405    ///
406    /// ```rust
407    /// # use cursive_core::XY;
408    /// let xy = XY::new(String::from("a"), String::from("ab"));
409    /// assert_eq!(XY::from(&xy), xy);
410    /// ```
411    fn from(t: &'a XY<T>) -> Self {
412        t.clone()
413    }
414}
415
416// Anything that can become XY<usize> can also become XY<isize>
417impl<T> From<T> for XY<isize>
418where
419    T: Into<XY<usize>>,
420{
421    /// # Examples
422    ///
423    /// ```rust
424    /// # use cursive_core::XY;
425    /// # use cursive_core::Vec2;
426    /// let u = Vec2::new(1, 2);
427    /// let v: XY<isize> = XY::from(u);
428    /// assert_eq!(v, XY::new(1, 2));
429    /// ```
430    fn from(t: T) -> Self {
431        let other = t.into();
432        Self::new(other.x as isize, other.y as isize)
433    }
434}
435
436impl From<(i32, i32)> for XY<usize> {
437    /// # Examples
438    ///
439    /// ```rust
440    /// # use cursive_core::XY;
441    /// let xy: XY<isize> = XY::from((-1i32, -2i32));
442    /// assert_eq!(xy, XY::new(-1, -2));
443    /// ```
444    fn from((x, y): (i32, i32)) -> Self {
445        (x as usize, y as usize).into()
446    }
447}
448
449impl From<(u32, u32)> for XY<usize> {
450    /// # Examples
451    ///
452    /// ```rust
453    /// # use cursive_core::Vec2;
454    /// let v = Vec2::from((1u32, 2u32));
455    /// assert_eq!(v, Vec2::new(1, 2));
456    /// ```
457    fn from((x, y): (u32, u32)) -> Self {
458        (x as usize, y as usize).into()
459    }
460}
461
462impl From<(u8, u8)> for XY<usize> {
463    /// # Examples
464    ///
465    /// ```rust
466    /// # use cursive_core::Vec2;
467    /// let v = Vec2::from((1u8, 2u8));
468    /// assert_eq!(v, Vec2::new(1, 2));
469    /// ```
470    fn from((x, y): (u8, u8)) -> Self {
471        (x as usize, y as usize).into()
472    }
473}
474
475impl From<(u16, u16)> for XY<usize> {
476    /// # Examples
477    ///
478    /// ```rust
479    /// # use cursive_core::Vec2;
480    /// let v = Vec2::from((1u16, 2u16));
481    /// assert_eq!(v, Vec2::new(1, 2));
482    /// ```
483    fn from((x, y): (u16, u16)) -> Self {
484        (x as usize, y as usize).into()
485    }
486}
487
488// Allow xy + (into xy)
489impl<T, O> Add<O> for XY<T>
490where
491    T: Add<Output = T>,
492    O: Into<XY<T>>,
493{
494    type Output = Self;
495
496    /// # Examples
497    ///
498    /// ```rust
499    /// # use cursive_core::XY;
500    /// let xy = XY::new(1, 2);
501    /// assert_eq!(xy + (2, 3), XY::new(3, 5));
502    /// ```
503    fn add(self, other: O) -> Self {
504        self.zip_map(other.into(), Add::add)
505    }
506}
507
508impl<T, O> Sub<O> for XY<T>
509where
510    T: Sub<Output = T>,
511    O: Into<XY<T>>,
512{
513    type Output = Self;
514
515    /// # Examples
516    ///
517    /// ```rust
518    /// # use cursive_core::XY;
519    /// let xy = XY::new(1, 2);
520    /// assert_eq!(xy - (1, 0), XY::new(0, 2));
521    /// ```
522    fn sub(self, other: O) -> Self {
523        self.zip_map(other.into(), Sub::sub)
524    }
525}
526
527impl<T: Clone + Div<Output = T>> Div<T> for XY<T> {
528    type Output = Self;
529
530    /// # Examples
531    ///
532    /// ```rust
533    /// # use cursive_core::XY;
534    /// let xy = XY::new(1, 4);
535    /// assert_eq!(xy / 2, XY::new(0, 2));
536    /// ```
537    fn div(self, other: T) -> Self {
538        self.map(|s| s / other.clone())
539    }
540}
541
542impl Mul<usize> for XY<usize> {
543    type Output = Vec2;
544
545    /// # Examples
546    ///
547    /// ```rust
548    /// # use cursive_core::Vec2;
549    /// let v = Vec2::new(1, 2);
550    /// assert_eq!(v * 2, Vec2::new(2, 4));
551    /// ```
552    fn mul(self, other: usize) -> Vec2 {
553        self.map(|s| s * other)
554    }
555}
556
557impl<T> Mul<XY<T>> for XY<T>
558where
559    T: Mul<T>,
560{
561    type Output = XY<T::Output>;
562
563    /// # Examples
564    ///
565    /// ```rust
566    /// # use cursive_core::XY;
567    /// let u = XY::new(1, 2);
568    /// let v = XY::new(2, 3);
569    /// assert_eq!(u * v, XY::new(2, 6));
570    /// ```
571    fn mul(self, other: XY<T>) -> Self::Output {
572        self.zip_map(other, |s, o| s * o)
573    }
574}
575impl<T> Div<XY<T>> for XY<T>
576where
577    T: Div<T>,
578{
579    type Output = XY<T::Output>;
580
581    /// # Examples
582    ///
583    /// ```rust
584    /// # use cursive_core::XY;
585    /// let u = XY::new(2, 3);
586    /// let v = XY::new(1, 2);
587    /// assert_eq!(u / v, XY::new(2, 1));
588    /// ```
589    fn div(self, other: XY<T>) -> Self::Output {
590        self.zip_map(other, |s, o| s / o)
591    }
592}
593
594#[cfg(test)]
595mod tests {
596    use super::Vec2;
597
598    #[test]
599    fn test_from() {
600        let vi32 = Vec2::from((4i32, 5i32));
601        let vu32 = Vec2::from((4u32, 5u32));
602
603        let vusize = Vec2::from((4usize, 5usize));
604        let vvec = Vec2::new(4, 5);
605
606        assert_eq!(vi32 - vu32, vusize - vvec);
607    }
608}