Add some more XY methods

This commit is contained in:
Alexandre Bury 2018-04-16 22:39:27 -07:00
parent 39babacbf5
commit 56ce95f9b6

View File

@ -16,18 +16,45 @@ impl<T> XY<T> {
XY { x: x, y: y } XY { x: x, y: y }
} }
/// Returns `f(self.x, self.y)`
pub fn fold<U, F>(self, f: F) -> U
where
F: FnOnce(T, T) -> U,
{
f(self.x, self.y)
}
/// Creates a new `XY` by applying `f` to `x` and `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> { pub fn map<U, F>(self, f: F) -> XY<U>
where
F: Fn(T) -> U,
{
XY::new(f(self.x), f(self.y)) XY::new(f(self.x), f(self.y))
} }
/// Applies `f` on axis where `condition` is true.
///
/// Carries over `self` otherwise.
pub fn map_if<F>(self, condition: XY<bool>, f: F) -> Self
where
F: Fn(T) -> T,
{
self.zip_map(condition, |v, c| if c { f(v) } else { v })
}
/// Creates a new `XY` by applying `f` to `x`, and carrying `y` over. /// 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 { pub fn map_x<F>(self, f: F) -> Self
where
F: FnOnce(T) -> T,
{
XY::new(f(self.x), self.y) XY::new(f(self.x), self.y)
} }
/// Creates a new `XY` by applying `f` to `y`, and carrying `x` over. /// 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 { pub fn map_y<F>(self, f: F) -> Self
where
F: FnOnce(T) -> T,
{
XY::new(self.x, f(self.y)) XY::new(self.x, f(self.y))
} }
@ -68,7 +95,10 @@ impl<T> XY<T> {
} }
/// Returns a new `XY` by calling `f` on `self` and `other` for each axis. /// 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> { pub fn zip_map<U, V, F>(self, other: XY<U>, f: F) -> XY<V>
where
F: Fn(T, U) -> V,
{
XY::new(f(self.x, other.x), f(self.y, other.y)) XY::new(f(self.x, other.x), f(self.y, other.y))
} }
} }
@ -97,19 +127,34 @@ impl<T: Clone> XY<T> {
impl<T> XY<Option<T>> { impl<T> XY<Option<T>> {
/// Returns a new `XY` by calling `unwrap_or` on each axis. /// Returns a new `XY` by calling `unwrap_or` on each axis.
pub fn unwrap_or(self, other: XY<T>) -> XY<T> { pub fn unwrap_or(self, other: XY<T>) -> XY<T> {
self.zip_map(other, |s, o| s.unwrap_or(o)) self.zip_map(other, Option::unwrap_or)
} }
} }
impl XY<bool> { impl XY<bool> {
/// Returns `true` if any of `x` or `y` is `true`. /// Returns `true` if any of `x` or `y` is `true`.
pub fn any(&self) -> bool { pub fn any(&self) -> bool {
self.x || self.y use std::ops::BitOr;
self.fold(BitOr::bitor)
} }
/// Returns `true` if both `x` and `y` are `true`. /// Returns `true` if both `x` and `y` are `true`.
pub fn both(&self) -> bool { pub fn both(&self) -> bool {
self.x && self.y use std::ops::BitAnd;
self.fold(BitAnd::bitand)
}
/// For each axis, keeps elements from `other` if `self` is `true`.
pub fn select<T>(&self, other: XY<T>) -> XY<Option<T>> {
self.zip_map(
other,
|keep, o| if keep { Some(o) } else { None },
)
}
/// For each axis, selects `if_true` if `self` is true, else `if_false`.
pub fn select_or<T>(&self, if_true: XY<T>, if_false: XY<T>) -> XY<T> {
self.select(if_true).unwrap_or(if_false)
} }
} }
@ -125,3 +170,9 @@ impl<T> From<(T, T)> for XY<T> {
XY::new(x, y) XY::new(x, y)
} }
} }
impl<T, U> From<(XY<T>, XY<U>)> for XY<(T, U)> {
fn from((t, u): (XY<T>, XY<U>)) -> Self {
t.zip(u)
}
}