1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use direction::Orientation;
use std::iter;

/// A generic structure with a value for each axis.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct XY<T> {
    /// X-axis value
    pub x: T,
    /// Y-axis value
    pub y: T,
}

impl<T> XY<T> {
    /// Creates a new `XY` from the given values.
    pub fn new(x: T, y: T) -> Self {
        XY { x: x, y: y }
    }

    /// Creates a new `XY` by applying `f` to `x` and `y`.
    pub fn map<U, F: Fn(T) -> U>(self, f: F) -> XY<U> {
        XY::new(f(self.x), f(self.y))
    }

    /// Creates a new `XY` by applying `f` to `x`, and carrying `y` over.
    pub fn map_x<F: Fn(T) -> T>(self, f: F) -> Self {
        XY::new(f(self.x), self.y)
    }

    /// Creates a new `XY` by applying `f` to `y`, and carrying `x` over.
    pub fn map_y<F: Fn(T) -> T>(self, f: F) -> Self {
        XY::new(self.x, f(self.y))
    }

    /// Destructure self into a pair.
    pub fn pair(self) -> (T, T) {
        (self.x, self.y)
    }

    /// Return a `XY` with references to this one's values.
    pub fn as_ref(&self) -> XY<&T> {
        XY::new(&self.x, &self.y)
    }

    /// Creates an iterator that returns references to `x`, then `y`.
    pub fn iter(&self) -> iter::Chain<iter::Once<&T>, iter::Once<&T>> {
        iter::once(&self.x).chain(iter::once(&self.y))
    }

    /// Returns a reference to the value on the given axis.
    pub fn get(&self, o: Orientation) -> &T {
        match o {
            Orientation::Horizontal => &self.x,
            Orientation::Vertical => &self.y,
        }
    }

    /// Returns a mutable reference to the value on the given axis.
    pub fn get_mut(&mut self, o: Orientation) -> &mut T {
        match o {
            Orientation::Horizontal => &mut self.x,
            Orientation::Vertical => &mut self.y,
        }
    }

    /// Returns a new `XY` of tuples made by zipping `self` and `other`.
    pub fn zip<U>(self, other: XY<U>) -> XY<(T, U)> {
        XY::new((self.x, other.x), (self.y, other.y))
    }

    /// Returns a new `XY` by calling `f` on `self` and `other` for each axis.
    pub fn zip_map<U, V, F: Fn(T, U) -> V>(self, other: XY<U>, f: F) -> XY<V> {
        XY::new(f(self.x, other.x), f(self.y, other.y))
    }
}

impl<T: Clone> XY<T> {
    /// Returns a new `XY` with the axis `o` set to `value`.
    pub fn with_axis(&self, o: Orientation, value: T) -> Self {
        let mut new = self.clone();
        *o.get_ref(&mut new) = value;
        new
    }

    /// Returns a new `XY` with the axis `o` set to the value from `other`.
    pub fn with_axis_from(&self, o: Orientation, other: &Self) -> Self {
        let mut new = self.clone();
        new.set_axis_from(o, other);
        new
    }

    /// Sets the axis `o` on `self` to the value from `other`.
    pub fn set_axis_from(&mut self, o: Orientation, other: &Self) {
        *o.get_ref(self) = o.get(other);
    }
}

impl<T> XY<Option<T>> {
    /// Returns a new `XY` by calling `unwrap_or` on each axis.
    pub fn unwrap_or(self, other: XY<T>) -> XY<T> {
        self.zip_map(other, |s, o| s.unwrap_or(o))
    }
}

impl XY<bool> {
    /// Returns `true` if any of `x` or `y` is `true`.
    pub fn any(&self) -> bool {
        self.x || self.y
    }

    /// Returns `true` if both `x` and `y` are `true`.
    pub fn both(&self) -> bool {
        self.x && self.y
    }
}

impl<T: Copy> XY<T> {
    /// Creates a `XY` with both `x` and `y` set to `value`.
    pub fn both_from(value: T) -> Self {
        XY::new(value, value)
    }
}

impl<T> From<(T, T)> for XY<T> {
    fn from((x, y): (T, T)) -> Self {
        XY::new(x, y)
    }
}