Added doc & examples to utilities types

This commit is contained in:
Alexandre Bury 2018-11-07 17:13:04 -08:00
parent 02c2680eaa
commit e82f0a077d
5 changed files with 600 additions and 17 deletions

View File

@ -1,6 +1,9 @@
//! Direction-related structures.
//!
//! This module defines two main concepts: [Orientation] and [Direction].
//! This module defines two main concepts: [`Orientation`] and [`Direction`].
//!
//! [`Orientation`]: direction::Orientation
//! [`Direction`]: direction::Direction
//!
//! ### Orientation
//!
@ -12,8 +15,16 @@
//! `Direction` is a bit more complex, and can be of two kinds:
//!
//! * Absolute direction: left, up, right, or down
//! * Relative direction: front or back.
//! Its actual direction depends on the orientation.
//! * Relative direction: front or back. Its actual direction depends on the
//! orientation.
//!
//! Usually, "front" refers to the "forward" direction, or the "next"
//! element. For example, for a vertical `LinearLayout`, "front" would refer
//! to the "down" direction.
//!
//! This is mostly relevant when referring to change of focus. Hitting the
//! `Tab` key would usually cycle focus in the "front" direction, while
//! using the arrow keys would use absolute directions instead.
use vec::Vec2;
use XY;
@ -51,6 +62,17 @@ impl Orientation {
/// Returns a mutable reference to the component of the given vector
/// corresponding to this orientation.
///
/// # Examples
/// ```rust
/// # use cursive::XY;
/// # use cursive::direction::Orientation;
/// let o = Orientation::Horizontal;
/// let mut xy = XY::new(1, 2);
/// *o.get_ref(&mut xy) = 42;
///
/// assert_eq!(xy, XY::new(42, 2));
/// ```
pub fn get_ref<T>(self, v: &mut XY<T>) -> &mut T {
match self {
Orientation::Horizontal => &mut v.x,
@ -61,8 +83,8 @@ impl Orientation {
/// Takes an iterator on sizes, and stack them in the current orientation,
/// returning the size of the required bounding box.
///
/// For an horizontal view, returns (Sum(x), Max(y)).
/// For a vertical view, returns (Max(x),Sum(y)).
/// * For an horizontal view, returns `(Sum(x), Max(y))`.
/// * For a vertical view, returns `(Max(x), Sum(y))`.
pub fn stack<'a, T: Iterator<Item = &'a Vec2>>(self, iter: T) -> Vec2 {
match self {
Orientation::Horizontal => {
@ -74,7 +96,24 @@ impl Orientation {
}
}
/// Creates a new `Vec2` with `value` in `self`'s axis.
/// Creates a new `Vec2` with `main_axis` in `self`'s axis, and
/// `second_axis` for the other axis.
///
/// # Examples
///
/// ```rust
/// # use cursive::direction::Orientation;
/// # use cursive::vec::Vec2;
/// let o = Orientation::Horizontal;
/// let vec = o.make_vec(1, 2);
///
/// assert_eq!(vec, Vec2::new(1, 2));
///
/// let o = Orientation::Vertical;
/// let vec = o.make_vec(1, 2);
///
/// assert_eq!(vec, Vec2::new(2, 1));
/// ```
pub fn make_vec(self, main_axis: usize, second_axis: usize) -> Vec2 {
let mut result = Vec2::zero();
*self.get_ref(&mut result) = main_axis;
@ -97,6 +136,9 @@ pub enum Direction {
impl Direction {
/// Returns the relative direction for the given orientation.
///
/// Some combination have no corresponding relative position. For example,
/// `Direction::Abs(Up)` means nothing for `Orientation::Horizontal`.
pub fn relative(self, orientation: Orientation) -> Option<Relative> {
match self {
Direction::Abs(abs) => abs.relative(orientation),
@ -151,12 +193,11 @@ impl Direction {
/// Direction relative to an orientation.
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Relative {
// TODO: handle right-to-left? (Arabic, ...)
/// Front relative direction.
///
/// * Horizontally, this means `Left`
/// * Vertically, this means `Up`
///
/// TODO: handle right-to-left?
Front,
/// Back relative direction.

View File

@ -4,7 +4,7 @@ use std::sync::Arc;
/// Atomic counter used by [`ProgressBar`].
///
/// [`ProgressBar`]: ../views/struct.ProgressBar.html
#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct Counter(pub Arc<AtomicUsize>);
impl Counter {

View File

@ -5,6 +5,32 @@ use utils::Counter;
///
/// Used to monitor a file downloading or other slow IO task
/// in a progress bar.
///
/// # Examples
///
/// ```rust,no_run
/// use std::io::Read;
/// use cursive::utils::{Counter, ProgressReader};
///
/// // Read a file and report the progress
/// let file = std::fs::File::open("large_file").unwrap();
/// let counter = Counter::new(0);
/// let mut reader = ProgressReader::new(counter.clone(), file);
///
/// std::thread::spawn(move || {
/// // Left as an exercise: use an AtomicBool for a stop condition!
/// loop {
/// let progress = counter.get();
/// println!("Read {} bytes so far", progress);
/// }
/// });
///
/// // As we read data, the counter will be updated and the control thread
/// // will monitor the progress.
/// let mut buffer = Vec::new();
/// reader.read_to_end(&mut buffer).unwrap();
/// ```
#[derive(Clone, Debug)]
pub struct ProgressReader<R: Read> {
reader: R,
counter: Counter,

View File

@ -34,6 +34,13 @@ impl<T: PartialOrd> PartialOrd for XY<T> {
impl XY<usize> {
/// Returns a `Vec2` with `usize::max_value()` in each axis.
///
/// # Examples
///
/// ```rust
/// # use cursive::vec::Vec2;
/// assert!(Vec2::new(9999, 9999) < Vec2::max_value());
/// ```
pub fn max_value() -> Self {
Self::new(usize::max_value(), usize::max_value())
}
@ -41,6 +48,15 @@ impl XY<usize> {
/// Saturating subtraction. Computes `self - other`, saturating at 0.
///
/// Never panics.
///
/// # Examples
///
/// ```rust
/// # use cursive::vec::Vec2;
/// let u = Vec2::new(1, 2);
/// let v = Vec2::new(2, 1);
/// assert_eq!(u.saturating_sub(v), Vec2::new(0, 1));
/// ```
pub fn saturating_sub<O: Into<Self>>(&self, other: O) -> Self {
let other = other.into();
self.zip_map(other, usize::saturating_sub)
@ -49,12 +65,22 @@ impl XY<usize> {
/// Saturating addition with a signed vec.
///
/// Any coordinates saturates to 0.
///
/// # Examples
///
/// ```rust
/// # use cursive::vec::Vec2;
/// # use cursive::XY;
/// let u = Vec2::new(1, 2);
/// let v = XY::<isize>::new(-2, 1);
/// assert_eq!(u.saturating_add(v), Vec2::new(0, 3));
/// ```
pub fn saturating_add<O: Into<XY<isize>>>(&self, other: O) -> Self {
let other = other.into();
self.zip_map(other, |s, o| {
if o > 0 {
s + o as usize
s.saturating_add(o as usize)
} else {
s.saturating_sub((-o) as usize)
}
@ -62,6 +88,15 @@ impl XY<usize> {
}
/// Term-by-term integer division that rounds up.
///
/// # Examples
///
/// ```rust
/// # use cursive::vec::Vec2;
/// let u = Vec2::new(1, 6);
/// let v = Vec2::new(2, 3);
/// assert_eq!(u.div_up(v), Vec2::new(1, 2));
/// ```
pub fn div_up<O>(&self, other: O) -> Self
where
O: Into<Self>,
@ -74,6 +109,15 @@ impl XY<usize> {
/// Returns `None` if `self.x < other.x || self.y < other.y`.
///
/// Never panics.
///
/// # Examples
///
/// ```rust
/// # use cursive::vec::Vec2;
/// let xy = Vec2::new(1, 2);
/// assert_eq!(xy.checked_sub((1, 1)), Some(Vec2::new(0, 1)));
/// assert_eq!(xy.checked_sub((2, 2)), None);
/// ```
pub fn checked_sub<O: Into<Self>>(&self, other: O) -> Option<Self> {
let other = other.into();
if self.fits(other) {
@ -84,6 +128,18 @@ impl XY<usize> {
}
/// Returns a `XY<isize>` from `self`.
///
/// # Examples
///
/// ```rust
/// # use cursive::vec::Vec2;
/// # use cursive::XY;
/// let v: XY<isize> = Vec2::new(1, 2).signed().map(|i| i - 5);
/// assert_eq!(v, XY::new(-4, -3));
///
/// let u = Vec2::new(3, 4);
/// assert_eq!(u.saturating_add(v), Vec2::new(0, 1));
/// ```
pub fn signed(self) -> XY<isize> {
self.into()
}
@ -95,6 +151,16 @@ impl<T: Ord> XY<T> {
/// Shortcut for `self.x <= other.x && self.y <= other.y`.
///
/// If this returns `true`, then `other - self` will not underflow.
///
/// # Examples
///
/// ```rust
/// # use cursive::vec::Vec2;
/// let v = Vec2::new(1, 2);
/// assert!(v.fits_in((1, 2)));
/// assert!(v.fits_in((3, 3)));
/// assert!(!v.fits_in((2, 1)));
/// ```
pub fn fits_in<O: Into<Self>>(&self, other: O) -> bool {
let other = other.into();
self.x <= other.x && self.y <= other.y
@ -105,12 +171,29 @@ impl<T: Ord> XY<T> {
/// Shortcut for `self.x >= other.x && self.y >= other.y`.
///
/// If this returns `true`, then `self - other` will not underflow.
///
/// # Examples
///
/// ```rust
/// # use cursive::vec::Vec2;
/// let v = Vec2::new(1, 2);
/// assert!(v.fits((1, 2)));
/// assert!(v.fits((0, 0)));
/// assert!(!v.fits((2, 1)));
/// ```
pub fn fits<O: Into<Self>>(&self, other: O) -> bool {
let other = other.into();
self.x >= other.x && self.y >= other.y
}
/// Returns a new Vec2 that is a maximum per coordinate.
///
/// # Examples
///
/// ```rust
/// # use cursive::vec::Vec2;
/// assert_eq!(Vec2::max((1, 2), (3, 1)), Vec2::new(3, 2));
/// ```
pub fn max<A: Into<XY<T>>, B: Into<XY<T>>>(a: A, b: B) -> Self {
let a = a.into();
let b = b.into();
@ -118,6 +201,13 @@ impl<T: Ord> XY<T> {
}
/// Returns a new Vec2 that is no larger than any input in both dimensions.
///
/// # Examples
///
/// ```rust
/// # use cursive::vec::Vec2;
/// assert_eq!(Vec2::min((1, 2), (3, 1)), Vec2::new(1, 1));
/// ```
pub fn min<A: Into<XY<T>>, B: Into<XY<T>>>(a: A, b: B) -> Self {
let a = a.into();
let b = b.into();
@ -125,11 +215,15 @@ impl<T: Ord> XY<T> {
}
/// Returns the minimum of `self` and `other`.
///
/// This is equivalent to `Vec2::min(self, other)`.
pub fn or_min<O: Into<XY<T>>>(self, other: O) -> Self {
Self::min(self, other)
}
/// Returns the maximum of `self` and `other`.
///
/// This is equivalent to `Vec2::max(self, other)`.
pub fn or_max<O: Into<XY<T>>>(self, other: O) -> Self {
Self::max(self, other)
}
@ -165,16 +259,39 @@ impl<T: Ord + Add<Output = T> + Clone> XY<T> {
impl<T: Zero + Clone> XY<T> {
/// Returns a vector with the X component of self, and y=0.
///
/// # Examples
///
/// ```rust
/// # use cursive::XY;
/// let xy = XY::new(1, 2);
/// assert_eq!(xy.keep_x(), XY::new(1, 0));
/// ```
pub fn keep_x(&self) -> Self {
Self::new(self.x.clone(), T::zero())
}
/// Returns a vector with the Y component of self, and x=0.
///
/// # Examples
///
/// ```rust
/// # use cursive::XY;
/// let xy = XY::new(1, 2);
/// assert_eq!(xy.keep_y(), XY::new(0, 2));
/// ```
pub fn keep_y(&self) -> Self {
Self::new(T::zero(), self.y.clone())
}
/// Alias for `Self::new(0,0)`.
///
/// # Examples
///
/// ```rust
/// # use cursive::vec::Vec2;
/// assert_eq!(Vec2::zero(), Vec2::new(0, 0));
/// ```
pub fn zero() -> Self {
Self::new(T::zero(), T::zero())
}
@ -184,6 +301,15 @@ impl<'a, T> From<&'a XY<T>> for XY<T>
where
T: Clone,
{
/// Clone a XY
///
/// # Examples
///
/// ```rust
/// # use cursive::XY;
/// let xy = XY::new(String::from("a"), String::from("ab"));
/// assert_eq!(XY::from(&xy), xy);
/// ```
fn from(t: &'a XY<T>) -> Self {
t.clone()
}
@ -194,6 +320,15 @@ impl<T> From<T> for XY<isize>
where
T: Into<XY<usize>>,
{
/// # Examples
///
/// ```rust
/// # use cursive::XY;
/// # use cursive::vec::Vec2;
/// let u = Vec2::new(1, 2);
/// let v: XY<isize> = XY::from(u);
/// assert_eq!(v, XY::new(1, 2));
/// ```
fn from(t: T) -> Self {
let other = t.into();
Self::new(other.x as isize, other.y as isize)
@ -201,24 +336,52 @@ where
}
impl From<(i32, i32)> for XY<usize> {
/// # Examples
///
/// ```rust
/// # use cursive::XY;
/// let xy: XY<isize> = XY::from((-1i32, -2i32));
/// assert_eq!(xy, XY::new(-1, -2));
/// ```
fn from((x, y): (i32, i32)) -> Self {
(x as usize, y as usize).into()
}
}
impl From<(u32, u32)> for XY<usize> {
/// # Examples
///
/// ```rust
/// # use cursive::vec::Vec2;
/// let v = Vec2::from((1u32, 2u32));
/// assert_eq!(v, Vec2::new(1, 2));
/// ```
fn from((x, y): (u32, u32)) -> Self {
(x as usize, y as usize).into()
}
}
impl From<(u8, u8)> for XY<usize> {
/// # Examples
///
/// ```rust
/// # use cursive::vec::Vec2;
/// let v = Vec2::from((1u8, 2u8));
/// assert_eq!(v, Vec2::new(1, 2));
/// ```
fn from((x, y): (u8, u8)) -> Self {
(x as usize, y as usize).into()
}
}
impl From<(u16, u16)> for XY<usize> {
/// # Examples
///
/// ```rust
/// # use cursive::vec::Vec2;
/// let v = Vec2::from((1u16, 2u16));
/// assert_eq!(v, Vec2::new(1, 2));
/// ```
fn from((x, y): (u16, u16)) -> Self {
(x as usize, y as usize).into()
}
@ -232,6 +395,13 @@ where
{
type Output = Self;
/// # Examples
///
/// ```rust
/// # use cursive::XY;
/// let xy = XY::new(1, 2);
/// assert_eq!(xy + (2, 3), XY::new(3, 5));
/// ```
fn add(self, other: O) -> Self {
self.zip_map(other.into(), Add::add)
}
@ -244,6 +414,13 @@ where
{
type Output = Self;
/// # Examples
///
/// ```rust
/// # use cursive::XY;
/// let xy = XY::new(1, 2);
/// assert_eq!(xy - (1, 0), XY::new(0, 2));
/// ```
fn sub(self, other: O) -> Self {
self.zip_map(other.into(), Sub::sub)
}
@ -252,6 +429,13 @@ where
impl<T: Clone + Div<Output = T>> Div<T> for XY<T> {
type Output = Self;
/// # Examples
///
/// ```rust
/// # use cursive::XY;
/// let xy = XY::new(1, 4);
/// assert_eq!(xy / 2, XY::new(0, 2));
/// ```
fn div(self, other: T) -> Self {
self.map(|s| s / other.clone())
}
@ -260,6 +444,13 @@ impl<T: Clone + Div<Output = T>> Div<T> for XY<T> {
impl Mul<usize> for XY<usize> {
type Output = Vec2;
/// # Examples
///
/// ```rust
/// # use cursive::vec::Vec2;
/// let v = Vec2::new(1, 2);
/// assert_eq!(v * 2, Vec2::new(2, 4));
/// ```
fn mul(self, other: usize) -> Vec2 {
self.map(|s| s * other)
}
@ -271,6 +462,14 @@ where
{
type Output = XY<T::Output>;
/// # Examples
///
/// ```rust
/// # use cursive::XY;
/// let u = XY::new(1, 2);
/// let v = XY::new(2, 3);
/// assert_eq!(u * v, XY::new(2, 6));
/// ```
fn mul(self, other: XY<T>) -> Self::Output {
self.zip_map(other, |s, o| s * o)
}
@ -281,6 +480,14 @@ where
{
type Output = XY<T::Output>;
/// # Examples
///
/// ```rust
/// # use cursive::XY;
/// let u = XY::new(2, 3);
/// let v = XY::new(1, 2);
/// assert_eq!(u / v, XY::new(2, 1));
/// ```
fn div(self, other: XY<T>) -> Self::Output {
self.zip_map(other, |s, o| s / o)
}

323
src/xy.rs
View File

@ -14,6 +14,7 @@ impl<T> IntoIterator for XY<T> {
type Item = T;
type IntoIter = iter::Chain<iter::Once<T>, iter::Once<T>>;
/// Iterate over x, then y.
fn into_iter(self) -> Self::IntoIter {
iter::once(self.x).chain(iter::once(self.y))
}
@ -26,11 +27,30 @@ impl<T> XY<T> {
}
/// Swaps the x and y values.
///
/// # Examples
///
/// ```rust
/// # use cursive::XY;
/// let xy = XY::new(1, 2);
/// assert_eq!(xy.swap(), XY::new(2, 1));
/// ```
pub fn swap(self) -> Self {
XY::new(self.y, self.x)
}
/// Returns `f(self.x, self.y)`
///
/// # Examples
///
/// ```rust
/// # use cursive::XY;
/// let xy = XY::new(1, 2);
///
/// assert_eq!(xy.fold(std::ops::Add::add), 3);
/// assert_eq!(xy.fold(std::ops::Mul::mul), 2);
/// assert_eq!(xy.fold(|x, y| x < y), true);
/// ```
pub fn fold<U, F>(self, f: F) -> U
where
F: FnOnce(T, T) -> U,
@ -39,6 +59,16 @@ impl<T> XY<T> {
}
/// Creates a new `XY` by applying `f` to `x` and `y`.
///
/// # Examples
///
/// ```rust
/// # use cursive::XY;
/// let xy = XY::new(1, 2);
///
/// assert_eq!(xy.map(|v| v * 2), XY::new(2, 4));
/// assert_eq!(xy.map(|v| v > 1), XY::new(false, true));
/// ```
pub fn map<U, F>(self, f: F) -> XY<U>
where
F: Fn(T) -> U,
@ -49,6 +79,17 @@ impl<T> XY<T> {
/// Applies `f` on axis where `condition` is true.
///
/// Carries over `self` otherwise.
///
/// # Examples
///
/// ```rust
/// # use cursive::XY;
/// let xy = XY::new(1, 2);
/// let cond = XY::new(true, false);
///
/// assert_eq!(xy.map_if(cond, |v| v * 3), XY::new(3, 2));
///
/// ```
pub fn map_if<F>(self, condition: XY<bool>, f: F) -> Self
where
F: Fn(T) -> T,
@ -59,6 +100,16 @@ impl<T> XY<T> {
/// Applies `f` on axis where `condition` is true.
///
/// Returns `None` otherwise.
///
/// # Examples
///
/// ```rust
/// # use cursive::XY;
/// let xy = XY::new(1, 2);
/// let cond = XY::new(true, false);
///
/// assert_eq!(xy.run_if(cond, |v| v * 3), XY::new(Some(3), None));
/// ```
pub fn run_if<F, U>(self, condition: XY<bool>, f: F) -> XY<Option<U>>
where
F: Fn(T) -> U,
@ -67,6 +118,14 @@ impl<T> XY<T> {
}
/// Creates a new `XY` by applying `f` to `x`, and carrying `y` over.
///
/// # Examples
///
/// ```rust
/// # use cursive::XY;
/// let xy = XY::new(1, 2);
/// assert_eq!(xy.map_x(|x| x * 10), XY::new(10, 2));
/// ```
pub fn map_x<F>(self, f: F) -> Self
where
F: FnOnce(T) -> T,
@ -75,6 +134,14 @@ impl<T> XY<T> {
}
/// Creates a new `XY` by applying `f` to `y`, and carrying `x` over.
///
/// # Examples
///
/// ```rust
/// # use cursive::XY;
/// let xy = XY::new(1, 2);
/// assert_eq!(xy.map_y(|y| y * 10), XY::new(1, 20));
/// ```
pub fn map_y<F>(self, f: F) -> Self
where
F: FnOnce(T) -> T,
@ -83,21 +150,65 @@ impl<T> XY<T> {
}
/// Destructure self into a pair.
///
/// # Examples
///
/// ```rust
/// # use cursive::XY;
/// let xy = XY::new(1, 2);
/// let (x, y) = xy.pair();
/// assert_eq!((x, y), (1, 2));
/// ```
pub fn pair(self) -> (T, T) {
(self.x, self.y)
}
/// Return a `XY` with references to this one's values.
///
/// # Examples
///
/// ```rust
/// # use cursive::XY;
/// fn longer(xy: &XY<String>, l: usize) -> XY<bool> {
/// // `XY::map` takes ownership
/// // So we need to get a XY<&String> from a &XY<String>
/// let by_ref: XY<&String> = xy.as_ref();
/// by_ref.map(|s| s.len() > l)
/// }
///
/// let xy = XY::new(String::from("a"), String::from("bbb"));
///
/// assert_eq!(longer(&xy, 2), XY::new(false, true));
/// ```
pub fn as_ref(&self) -> XY<&T> {
XY::new(&self.x, &self.y)
}
/// Creates an iterator that returns references to `x`, then `y`.
///
/// # Examples
///
/// ```rust
/// # use cursive::XY;
/// let xy = XY::new(1, 2);
/// let vec: Vec<bool> = xy.iter().map(|&i| i > 1).collect();
/// assert_eq!(vec, vec![false, true]);
/// ```
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.
///
/// # Examples
///
/// ```rust
/// # use cursive::XY;
/// # use cursive::direction::Orientation;
/// let xy = XY::new(1, 2);
/// assert_eq!(xy.get(Orientation::Horizontal), &1);
/// assert_eq!(xy.get(Orientation::Vertical), &2);
/// ```
pub fn get(&self, o: Orientation) -> &T {
match o {
Orientation::Horizontal => &self.x,
@ -106,6 +217,17 @@ impl<T> XY<T> {
}
/// Returns a mutable reference to the value on the given axis.
///
/// # Examples
///
/// ```rust
/// # use cursive::XY;
/// # use cursive::direction::Orientation;
/// let mut xy = XY::new(1, 2);
/// *xy.get_mut(Orientation::Horizontal) = 10;
///
/// assert_eq!(xy, XY::new(10, 2));
/// ```
pub fn get_mut(&mut self, o: Orientation) -> &mut T {
match o {
Orientation::Horizontal => &mut self.x,
@ -114,16 +236,49 @@ impl<T> XY<T> {
}
/// Returns a new `XY` of tuples made by zipping `self` and `other`.
///
/// # Examples
///
/// ```rust
/// # use cursive::XY;
/// let a = XY::new(1, 2);
/// let b = XY::new(true, false);
/// assert_eq!(a.zip(b), XY::new((1, true), (2, false)));
/// ```
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` of tuples made by zipping `self`, `a` and `b`.
///
/// # Examples
///
/// ```rust
/// # use cursive::XY;
/// let a = XY::new(1, 2);
/// let b = XY::new(true, false);
/// let c = XY::new("x", "y");
/// assert_eq!(a.zip3(b, c), XY::new((1, true, "x"), (2, false, "y")));
/// ```
pub fn zip3<U, V>(self, a: XY<U>, b: XY<V>) -> XY<(T, U, V)> {
XY::new((self.x, a.x, b.x), (self.y, a.y, b.y))
}
/// Returns a new `XY` of tuples made by zipping `self`, `a`, `b` and `c`.
///
/// # Examples
///
/// ```rust
/// # use cursive::XY;
/// let a = XY::new(1, 2);
/// let b = XY::new(true, false);
/// let c = XY::new("x", "y");
/// let d = XY::new(vec![1], vec![2, 3, 4]);
/// assert_eq!(
/// XY::zip4(a, b, c, d),
/// XY::new((1, true, "x", vec![1]), (2, false, "y", vec![2, 3, 4]))
/// );
/// ```
pub fn zip4<U, V, W>(
self, a: XY<U>, b: XY<V>, c: XY<W>,
) -> XY<(T, U, V, W)> {
@ -131,6 +286,27 @@ impl<T> XY<T> {
}
/// Returns a new `XY` of tuples made by zipping `self`, `a`, `b`, `c` and `d`.
///
/// # Examples
///
/// ```rust
/// # use cursive::XY;
/// let a = XY::new(1, 2);
/// let b = XY::new(true, false);
/// let c = XY::new("x", "y");
/// let d = XY::new(vec![1], vec![2, 3, 4]);
/// let e = XY::new('a', 'b');
///
/// let xy: XY<Option<char>> = XY::zip5(a, b, c, d, e)
/// .map(|(a, b, c, d, e)| {
/// if b && d.contains(&a) {
/// Some(e)
/// } else {
/// c.chars().next()
/// }
/// });
/// assert_eq!(xy, XY::new(Some('a'), Some('y')));
/// ```
pub fn zip5<U, V, W, Z>(
self, a: XY<U>, b: XY<V>, c: XY<W>, d: XY<Z>,
) -> XY<(T, U, V, W, Z)> {
@ -138,6 +314,16 @@ impl<T> XY<T> {
}
/// Returns a new `XY` by calling `f` on `self` and `other` for each axis.
///
/// # Examples
///
/// ```rust
/// # use cursive::XY;
/// let a = XY::new((1, 10), (2, 20));
/// let b = XY::new(true, false);
/// let xy = a.zip_map(b, |(a1, a2), b| if b { a1 } else { a2 });
/// assert_eq!(xy, XY::new(1, 20));
/// ```
pub fn zip_map<U, V, F>(self, other: XY<U>, f: F) -> XY<V>
where
F: Fn(T, U) -> V,
@ -146,6 +332,16 @@ impl<T> XY<T> {
}
/// For each axis, keep the element from `self` if `keep` is `true`.
///
/// # Examples
///
/// ```rust
/// # use cursive::XY;
/// let xy = XY::new(1, 2);
/// let cond = XY::new(true, false);
///
/// assert_eq!(xy.keep(cond), XY::new(Some(1), None));
/// ```
pub fn keep(self, keep: XY<bool>) -> XY<Option<T>> {
keep.select(self)
}
@ -153,6 +349,16 @@ impl<T> XY<T> {
impl<T: Clone> XY<T> {
/// Returns a new `XY` with the axis `o` set to `value`.
///
/// # Examples
///
/// ```rust
/// # use cursive::XY;
/// # use cursive::direction::Orientation;
/// let xy = XY::new(1, 2).with_axis(Orientation::Horizontal, 42);
///
/// assert_eq!(xy, XY::new(42, 2));
/// ```
pub fn with_axis(&self, o: Orientation, value: T) -> Self {
let mut new = self.clone();
*o.get_ref(&mut new) = value;
@ -160,6 +366,17 @@ impl<T: Clone> XY<T> {
}
/// Returns a new `XY` with the axis `o` set to the value from `other`.
///
/// # Examples
///
/// ```rust
/// # use cursive::XY;
/// # use cursive::direction::Orientation;
/// let other = XY::new(3, 4);
/// let xy = XY::new(1, 2).with_axis_from(Orientation::Horizontal, &other);
///
/// assert_eq!(xy, XY::new(3, 2));
/// ```
pub fn with_axis_from(&self, o: Orientation, other: &Self) -> Self {
let mut new = self.clone();
new.set_axis_from(o, other);
@ -167,66 +384,158 @@ impl<T: Clone> XY<T> {
}
/// Sets the axis `o` on `self` to the value from `other`.
///
/// # Examples
///
/// ```rust
/// # use cursive::XY;
/// # use cursive::direction::Orientation;
/// let mut xy = XY::new(1, 2);
/// let other = XY::new(3, 4);
/// xy.set_axis_from(Orientation::Horizontal, &other);
///
/// assert_eq!(xy, XY::new(3, 2));
/// ```
pub fn set_axis_from(&mut self, o: Orientation, other: &Self) {
*o.get_ref(self) = o.get(other);
}
/// Creates a `XY` with both `x` and `y` set to `value`.
///
/// # Examples
///
/// ```rust
/// # use cursive::XY;
/// let xy = XY::both_from(42);
///
/// assert_eq!(xy, XY::new(42, 42));
/// ```
pub fn both_from(value: T) -> Self {
let x = value.clone();
let y = value;
XY::new(x, y)
}
}
impl<T> XY<Option<T>> {
/// Returns a new `XY` by calling `unwrap_or` on each axis.
///
/// # Examples
///
/// ```rust
/// # use cursive::XY;
/// let xy = XY::new(Some(1), None);
/// assert_eq!(xy.unwrap_or(XY::new(10, 20)), XY::new(1, 20));
/// ```
pub fn unwrap_or(self, other: XY<T>) -> XY<T> {
self.zip_map(other, Option::unwrap_or)
}
}
impl XY<bool> {
// Could also be called "either"
/// Returns `true` if any of `x` or `y` is `true`.
///
/// # Examples
///
/// ```rust
/// # use cursive::XY;
/// assert_eq!(XY::new(true, false).any(), true);
/// assert_eq!(XY::new(false, false).any(), false);
/// assert_eq!(XY::new('a', 'b').map(|c| c == 'a').any(), true);
/// ```
pub fn any(self) -> bool {
use std::ops::BitOr;
self.fold(BitOr::bitor)
}
// Could also be called "all"
/// Returns `true` if both `x` and `y` are `true`.
///
/// # Examples
///
/// ```rust
/// # use cursive::XY;
/// assert_eq!(XY::new(true, false).both(), false);
/// assert_eq!(XY::new(true, true).both(), true);
/// assert_eq!(XY::new("abc", "de").map(|s| s.len() > 2).both(), false);
/// ```
pub fn both(self) -> bool {
use std::ops::BitAnd;
self.fold(BitAnd::bitand)
}
/// For each axis, keeps elements from `other` if `self` is `true`.
///
/// # Examples
///
/// ```rust
/// # use cursive::XY;
/// let choice = XY::new(true, false);
/// let values = XY::new(1, 2);
/// let selection = choice.select(values);
///
/// assert_eq!(selection, XY::new(Some(1), None));
/// ```
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`.
///
/// # Examples
///
/// ```rust
/// # use cursive::XY;
/// let choice = XY::new(true, false);
/// let values = XY::new(1, 2);
/// let fallback = XY::new(3, 4);
/// let selection = choice.select_or(values, fallback);
///
/// assert_eq!(selection, XY::new(1, 4));
/// ```
pub fn select_or<T>(self, if_true: XY<T>, if_false: XY<T>) -> XY<T> {
self.select(if_true).unwrap_or(if_false)
}
/// Returns a term-by-term AND operation.
///
/// # Examples
///
/// ```rust
/// # use cursive::XY;
/// let a = XY::new(true, false);
/// let b = XY::new(true, true);
/// assert_eq!(a.and(b), XY::new(true, false));
/// ```
pub fn and(self, other: Self) -> Self {
self.zip_map(other, |s, o| s && o)
}
/// Returns a term-by-term OR operation.
///
/// # Examples
///
/// ```rust
/// # use cursive::XY;
/// let a = XY::new(true, false);
/// let b = XY::new(true, true);
/// assert_eq!(a.or(b), XY::new(true, true));
/// ```
pub fn or(self, other: Self) -> Self {
self.zip_map(other, |s, o| s || o)
}
}
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> {
/// A pair is assumed to be (x, y)
fn from((x, y): (T, T)) -> Self {
XY::new(x, y)
}
}
impl<T, U> From<(XY<T>, XY<U>)> for XY<(T, U)> {
/// Easily zip a pair of XY into a XY of pair
fn from((t, u): (XY<T>, XY<U>)) -> Self {
t.zip(u)
}