From e82f0a077d0ed341c8ab7f2e6934fd8fc74f6a23 Mon Sep 17 00:00:00 2001 From: Alexandre Bury Date: Wed, 7 Nov 2018 17:13:04 -0800 Subject: [PATCH] Added doc & examples to utilities types --- src/direction.rs | 57 ++++++-- src/utils/counter.rs | 2 +- src/utils/reader.rs | 26 ++++ src/vec.rs | 209 +++++++++++++++++++++++++++- src/xy.rs | 323 ++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 600 insertions(+), 17 deletions(-) diff --git a/src/direction.rs b/src/direction.rs index 1193aaf..a92761c 100644 --- a/src/direction.rs +++ b/src/direction.rs @@ -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(self, v: &mut XY) -> &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>(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 { 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. diff --git a/src/utils/counter.rs b/src/utils/counter.rs index 3c74c26..f0c634d 100644 --- a/src/utils/counter.rs +++ b/src/utils/counter.rs @@ -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); impl Counter { diff --git a/src/utils/reader.rs b/src/utils/reader.rs index f93a0b3..37cbb83 100644 --- a/src/utils/reader.rs +++ b/src/utils/reader.rs @@ -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 { reader: R, counter: Counter, diff --git a/src/vec.rs b/src/vec.rs index bba029e..0e889d8 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -34,6 +34,13 @@ impl PartialOrd for XY { impl XY { /// 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 { /// 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>(&self, other: O) -> Self { let other = other.into(); self.zip_map(other, usize::saturating_sub) @@ -49,12 +65,22 @@ impl XY { /// 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::::new(-2, 1); + /// assert_eq!(u.saturating_add(v), Vec2::new(0, 3)); + /// ``` pub fn saturating_add>>(&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 { } /// 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(&self, other: O) -> Self where O: Into, @@ -74,6 +109,15 @@ impl XY { /// 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>(&self, other: O) -> Option { let other = other.into(); if self.fits(other) { @@ -84,6 +128,18 @@ impl XY { } /// Returns a `XY` from `self`. + /// + /// # Examples + /// + /// ```rust + /// # use cursive::vec::Vec2; + /// # use cursive::XY; + /// let v: XY = 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 { self.into() } @@ -95,6 +151,16 @@ impl XY { /// 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>(&self, other: O) -> bool { let other = other.into(); self.x <= other.x && self.y <= other.y @@ -105,12 +171,29 @@ impl XY { /// 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>(&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>, B: Into>>(a: A, b: B) -> Self { let a = a.into(); let b = b.into(); @@ -118,6 +201,13 @@ impl XY { } /// 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>, B: Into>>(a: A, b: B) -> Self { let a = a.into(); let b = b.into(); @@ -125,11 +215,15 @@ impl XY { } /// Returns the minimum of `self` and `other`. + /// + /// This is equivalent to `Vec2::min(self, other)`. pub fn or_min>>(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>>(self, other: O) -> Self { Self::max(self, other) } @@ -165,16 +259,39 @@ impl + Clone> XY { impl XY { /// 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> for XY 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) -> Self { t.clone() } @@ -194,6 +320,15 @@ impl From for XY where T: Into>, { + /// # Examples + /// + /// ```rust + /// # use cursive::XY; + /// # use cursive::vec::Vec2; + /// let u = Vec2::new(1, 2); + /// let v: XY = 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 { + /// # Examples + /// + /// ```rust + /// # use cursive::XY; + /// let xy: XY = 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 { + /// # 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 { + /// # 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 { + /// # 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> Div for XY { 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> Div for XY { impl Mul for XY { 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; + /// # 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) -> Self::Output { self.zip_map(other, |s, o| s * o) } @@ -281,6 +480,14 @@ where { type Output = XY; + /// # 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) -> Self::Output { self.zip_map(other, |s, o| s / o) } diff --git a/src/xy.rs b/src/xy.rs index ba70a53..6bacb84 100644 --- a/src/xy.rs +++ b/src/xy.rs @@ -14,6 +14,7 @@ impl IntoIterator for XY { type Item = T; type IntoIter = iter::Chain, iter::Once>; + /// 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 XY { } /// 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(self, f: F) -> U where F: FnOnce(T, T) -> U, @@ -39,6 +59,16 @@ impl XY { } /// 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(self, f: F) -> XY where F: Fn(T) -> U, @@ -49,6 +79,17 @@ impl XY { /// 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(self, condition: XY, f: F) -> Self where F: Fn(T) -> T, @@ -59,6 +100,16 @@ impl XY { /// 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(self, condition: XY, f: F) -> XY> where F: Fn(T) -> U, @@ -67,6 +118,14 @@ impl XY { } /// 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(self, f: F) -> Self where F: FnOnce(T) -> T, @@ -75,6 +134,14 @@ impl XY { } /// 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(self, f: F) -> Self where F: FnOnce(T) -> T, @@ -83,21 +150,65 @@ impl XY { } /// 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, l: usize) -> XY { + /// // `XY::map` takes ownership + /// // So we need to get a XY<&String> from a &XY + /// 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 = xy.iter().map(|&i| i > 1).collect(); + /// assert_eq!(vec, vec![false, true]); + /// ``` pub fn iter(&self) -> iter::Chain, 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 XY { } /// 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 XY { } /// 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(self, other: XY) -> 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(self, a: XY, b: XY) -> 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( self, a: XY, b: XY, c: XY, ) -> XY<(T, U, V, W)> { @@ -131,6 +286,27 @@ impl XY { } /// 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> = 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( self, a: XY, b: XY, c: XY, d: XY, ) -> XY<(T, U, V, W, Z)> { @@ -138,6 +314,16 @@ impl XY { } /// 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(self, other: XY, f: F) -> XY where F: Fn(T, U) -> V, @@ -146,6 +332,16 @@ impl XY { } /// 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) -> XY> { keep.select(self) } @@ -153,6 +349,16 @@ impl XY { impl XY { /// 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 XY { } /// 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 XY { } /// 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 XY> { /// 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) -> XY { self.zip_map(other, Option::unwrap_or) } } impl XY { + // 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(self, other: XY) -> XY> { 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(self, if_true: XY, if_false: XY) -> XY { 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 XY { - /// Creates a `XY` with both `x` and `y` set to `value`. - pub fn both_from(value: T) -> Self { - XY::new(value, value) - } -} - impl From<(T, T)> for XY { + /// A pair is assumed to be (x, y) fn from((x, y): (T, T)) -> Self { XY::new(x, y) } } impl From<(XY, XY)> for XY<(T, U)> { + /// Easily zip a pair of XY into a XY of pair fn from((t, u): (XY, XY)) -> Self { t.zip(u) }