<commit_before>//! Lambda-encoded [result type](https://doc.rust-lang.org/std/result/enum.Result.html)

use term::{Term, abs, app};
use term::Term::*;
use data::boolean::{tru, fls};
use data::option::{none, some};
use combinators::I;

/// Applied to an argument it consumes it and produces a lambda-encoded Result::Ok that contains
/// it.
///
/// OK ≡ λxab.a x ≡ λ λ λ 1 3
///
/// # Example
/// ```
/// use lambda_calculus::data::result::ok;
/// use lambda_calculus::*;
///
/// let ok_one: Result<usize, usize> = Ok(1);
/// assert_eq!(beta(app(ok(), 1.into_church()), NOR, 0), ok_one.into_church());
/// ```
pub fn ok() -> Term {
    abs!(3, app(Var(2), Var(3)))
}

/// Applied to an argument it consumes it and produces a lambda-encoded Result::Err that contains
/// it.
///
/// ERR ≡ λxab.b x ≡ λ λ λ 2 3
///
/// # Example
/// ```
/// use lambda_calculus::data::result::err;
/// use lambda_calculus::*;
///
/// let err_two: Result<usize, usize> = Err(2);
/// assert_eq!(beta(app(err(), 2.into_church()), NOR, 0), err_two.into_church());
/// ```
pub fn err() -> Term {
    abs!(3, app(Var(1), Var(3)))
}

/// Applied to a lambda-encoded Result it produces a lambda-encoded boolean indicating whether it
/// is Result::Ok.
///
/// IS_OK ≡ λa.a (λx.TRUE) (λx.FALSE) ≡ λ 1 (λ TRUE) (λ FALSE)
///
/// # Example
/// ```
/// use lambda_calculus::data::result::is_ok;
/// use lambda_calculus::*;
///
/// let ok_one: Result<usize, usize> = Ok(1);
/// let err_two: Result<usize, usize> = Err(2);
///
/// assert_eq!(beta(app(is_ok(), ok_one.into_church()), NOR, 0), true.into());
/// assert_eq!(beta(app(is_ok(), err_two.into_church()), NOR, 0), false.into());
/// ```
pub fn is_ok() -> Term {
    abs(app!(Var(1), abs(tru()), abs(fls())))
}

/// Applied to a lambda-encoded Result it produces a lambda-encoded boolean indicating whether it
/// is Result::Err.
///
/// IS_ERR ≡ λa.a FALSE (λx.TRUE) ≡ λ 1 FALSE (λ TRUE)
///
/// # Example
/// ```
/// use lambda_calculus::data::result::is_err;
/// use lambda_calculus::*;
///
/// let ok_one: Result<usize, usize> = Ok(1);
/// let err_two: Result<usize, usize> = Err(2);
///
/// assert_eq!(beta(app(is_err(), ok_one.into_church()), NOR, 0), false.into());
/// assert_eq!(beta(app(is_err(), err_two.into_church()), NOR, 0), true.into());
/// ```
pub fn is_err() -> Term {
    abs(app!(Var(1), abs(fls()), abs(tru())))
}

/// Applied to a lambda-encoded Result it produces a lambda-encoded Option containing the Ok value.
///
/// OPTION_OK ≡ λa.a SOME (λx.NONE) ≡ λ 1 SOME (λ NONE)
///
/// # Example
/// ```
/// use lambda_calculus::data::result::option_ok;
/// use lambda_calculus::data::option::none;
/// use lambda_calculus::*;
///
/// let ok_one: Result<usize, usize> = Ok(1);
/// let err_two: Result<usize, usize> = Err(2);
///
/// assert_eq!(beta(app(option_ok(), ok_one.into_church()), NOR, 0), Some(1).into_church());
/// assert_eq!(beta(app(option_ok(), err_two.into_church()), NOR, 0), none());
/// ```
pub fn option_ok() -> Term {
    abs(app!(Var(1), some(), abs(none())))
}

/// Applied to a lambda-encoded Result it produces a lambda-encoded Option containing the Err value.
///
/// OPTION_ERR ≡ λa.a (λx.NONE) SOME ≡ λ 1 (λ NONE) SOME
///
/// # Example
/// ```
/// use lambda_calculus::data::result::option_err;
/// use lambda_calculus::data::option::none;
/// use lambda_calculus::*;
///
/// let ok_one: Result<usize, usize> = Ok(1);
/// let err_two: Result<usize, usize> = Err(2);
///
/// assert_eq!(beta(app(option_err(), ok_one.into_church()), NOR, 0), none());
/// assert_eq!(beta(app(option_err(), err_two.into_church()), NOR, 0), Some(2).into_church());
/// ```
pub fn option_err() -> Term {
    abs(app!(Var(1), abs(none()), some()))
}

/// Applied to one argument and a lambda-encoded Result it returns the value inside the Ok or
/// the first argument if the Result is not Ok.
///
/// UNWRAP_OR ≡ λdr.r I (λx.d) ≡ λ λ 1 I (λ 3)
///
/// # Example
/// ```
/// use lambda_calculus::data::result::unwrap_or;
/// use lambda_calculus::*;
///
/// let ok_one: Result<usize, usize> = Ok(1);
/// let err_two: Result<usize, usize> = Err(2);
///
/// assert_eq!(beta(app!(unwrap_or(), 3.into_church(), ok_one.into_church()), NOR, 0), 1.into_church());
/// assert_eq!(beta(app!(unwrap_or(), 3.into_church(), err_two.into_church()), NOR, 0), 3.into_church());
/// ```
pub fn unwrap_or() -> Term {
    abs!(2, app!(Var(1), I(), abs(Var(3))))
}

/// Applied to a function and a lambda-encoded Result it applies the function to the contents of
/// the Result if it is Ok.
///
/// MAP ≡ λfm.m (λx.OK (f x)) ERR ≡ λ λ 1 (λ OK (3 1)) ERR
///
/// # Example
/// ```
/// use lambda_calculus::data::result::map;
/// use lambda_calculus::data::num::church::succ;
/// use lambda_calculus::*;
///
/// let ok_one: Result<usize, usize> = Ok(1);
/// let ok_two: Result<usize, usize> = Ok(2);
/// let err_two: Result<usize, usize> = Err(2);
///
/// assert_eq!(beta(app!(map(), succ(), ok_one.into_church()), NOR, 0), ok_two.into_church());
/// assert_eq!(beta(app!(map(), succ(), err_two.into_church()), NOR, 0), err_two.into_church());
/// ```
pub fn map() -> Term {
    abs!(2, app!(
        Var(1),
        abs(app(ok(), app(Var(3), Var(1)))),
        err()
    ))
}

/// Applied to a function and a lambda-encoded Result it applies the function to the contents of
/// the Result if it is Ok.
///
/// MAP_ERR ≡ λfm.m OK (λx.ERR (f x)) ≡ λ λ 1 OK (λ ERR (3 1))
///
/// # Example
/// ```
/// use lambda_calculus::data::result::map_err;
/// use lambda_calculus::data::num::church::succ;
/// use lambda_calculus::*;
///
/// let ok_one: Result<usize, usize> = Ok(1);
/// let err_two: Result<usize, usize> = Err(2);
/// let err_three: Result<usize, usize> = Err(3);
///
/// assert_eq!(beta(app!(map_err(), succ(), ok_one.into_church()), NOR, 0), ok_one.into_church());
/// assert_eq!(beta(app!(map_err(), succ(), err_two.into_church()), NOR, 0), err_three.into_church());
/// ```
pub fn map_err() -> Term {
    abs!(2, app!(
        Var(1),
        ok(),
        abs(app(err(), app(Var(3), Var(1))))
    ))
}

/// Applied to a lambda-encoded Result and a function that returns a lambda-encoded Result, it
/// applies the function to the contents of the Result if it is Ok.
///
/// AND_THEN ≡ λmf.m f ERR ≡ λ λ 2 1 ERR
///
/// # Example
/// ```
/// use lambda_calculus::data::result::{and_then, ok};
/// use lambda_calculus::data::num::church::succ;
/// use lambda_calculus::*;
///
/// // Equivalent to the closure `|x| { Ok(x+1) }` in Rust
/// let ok_succ: Term = abs(app(ok(), app(succ(), Var(1))));
///
/// let ok_one: Result<usize, usize> = Ok(1);
/// let ok_two: Result<usize, usize> = Ok(2);
/// let err_two: Result<usize, usize> = Err(2);
///
/// assert_eq!(
///     beta(app!(and_then(), err_two.into_church(), ok_succ.clone()), NOR, 0),
///     err_two.into_church()
/// );
/// assert_eq!(
///     beta(app!(and_then(), ok_one.into_church(), ok_succ.clone()), NOR, 0),
///     ok_two.into_church()
/// );
/// ```
pub fn and_then() -> Term {
    abs!(2, app!(Var(2), Var(1), err()))
}

impl Into<Term> for Result<Term, Term> {
    fn into(self) -> Term {
        match self {
            Ok(ok) => abs!(2, app(Var(2), ok)),
            Err(err) => abs!(2, app(Var(1), err))
        }
    }
}
<commit_msg>fix documentation<commit_after>//! Lambda-encoded [result type](https://doc.rust-lang.org/std/result/enum.Result.html)

use term::{Term, abs, app};
use term::Term::*;
use data::boolean::{tru, fls};
use data::option::{none, some};
use combinators::I;

/// Applied to an argument it consumes it and produces a lambda-encoded `Result::Ok` that contains
/// it.
///
/// OK ≡ λxab.a x ≡ λ λ λ 2 3
///
/// # Example
/// ```
/// use lambda_calculus::data::result::ok;
/// use lambda_calculus::*;
///
/// let ok_one: Result<usize, usize> = Ok(1);
/// assert_eq!(beta(app(ok(), 1.into_church()), NOR, 0), ok_one.into_church());
/// ```
pub fn ok() -> Term {
    abs!(3, app(Var(2), Var(3)))
}

/// Applied to an argument it consumes it and produces a lambda-encoded `Result::Err` that contains
/// it.
///
/// ERR ≡ λxab.b x ≡ λ λ λ 1 3
///
/// # Example
/// ```
/// use lambda_calculus::data::result::err;
/// use lambda_calculus::*;
///
/// let err_two: Result<usize, usize> = Err(2);
/// assert_eq!(beta(app(err(), 2.into_church()), NOR, 0), err_two.into_church());
/// ```
pub fn err() -> Term {
    abs!(3, app(Var(1), Var(3)))
}

/// Applied to a lambda-encoded `Result` it produces a lambda-encoded boolean indicating whether it
/// is `Result::Ok`.
///
/// IS_OK ≡ λa.a (λx.TRUE) (λx.FALSE) ≡ λ 1 (λ TRUE) (λ FALSE)
///
/// # Example
/// ```
/// use lambda_calculus::data::result::is_ok;
/// use lambda_calculus::*;
///
/// let ok_one: Result<usize, usize> = Ok(1);
/// let err_two: Result<usize, usize> = Err(2);
///
/// assert_eq!(beta(app(is_ok(), ok_one.into_church()), NOR, 0), true.into());
/// assert_eq!(beta(app(is_ok(), err_two.into_church()), NOR, 0), false.into());
/// ```
pub fn is_ok() -> Term {
    abs(app!(Var(1), abs(tru()), abs(fls())))
}

/// Applied to a lambda-encoded `Result` it produces a lambda-encoded boolean indicating whether it
/// is `Result::Err`.
///
/// IS_ERR ≡ λa.a (λx.FALSE) (λx.TRUE) ≡ λ 1 (λ FALSE) (λ TRUE)
///
/// # Example
/// ```
/// use lambda_calculus::data::result::is_err;
/// use lambda_calculus::*;
///
/// let ok_one: Result<usize, usize> = Ok(1);
/// let err_two: Result<usize, usize> = Err(2);
///
/// assert_eq!(beta(app(is_err(), ok_one.into_church()), NOR, 0), false.into());
/// assert_eq!(beta(app(is_err(), err_two.into_church()), NOR, 0), true.into());
/// ```
pub fn is_err() -> Term {
    abs(app!(Var(1), abs(fls()), abs(tru())))
}

/// Applied to a lambda-encoded `Result` it produces a lambda-encoded `Option` containing the `Ok` value.
///
/// OPTION_OK ≡ λa.a SOME (λx.NONE) ≡ λ 1 SOME (λ NONE)
///
/// # Example
/// ```
/// use lambda_calculus::data::result::option_ok;
/// use lambda_calculus::data::option::none;
/// use lambda_calculus::*;
///
/// let ok_one: Result<usize, usize> = Ok(1);
/// let err_two: Result<usize, usize> = Err(2);
///
/// assert_eq!(beta(app(option_ok(), ok_one.into_church()), NOR, 0), Some(1).into_church());
/// assert_eq!(beta(app(option_ok(), err_two.into_church()), NOR, 0), none());
/// ```
pub fn option_ok() -> Term {
    abs(app!(Var(1), some(), abs(none())))
}

/// Applied to a lambda-encoded `Result it produces a lambda-encoded Option containing the `Err`
/// value.
///
/// OPTION_ERR ≡ λa.a (λx.NONE) SOME ≡ λ 1 (λ NONE) SOME
///
/// # Example
/// ```
/// use lambda_calculus::data::result::option_err;
/// use lambda_calculus::data::option::none;
/// use lambda_calculus::*;
///
/// let ok_one: Result<usize, usize> = Ok(1);
/// let err_two: Result<usize, usize> = Err(2);
///
/// assert_eq!(beta(app(option_err(), ok_one.into_church()), NOR, 0), none());
/// assert_eq!(beta(app(option_err(), err_two.into_church()), NOR, 0), Some(2).into_church());
/// ```
pub fn option_err() -> Term {
    abs(app!(Var(1), abs(none()), some()))
}

/// Applied to one argument and a lambda-encoded `Result` it returns the value inside the `Ok` or
/// the first argument if the `Result` is not `Ok`.
///
/// UNWRAP_OR ≡ λdr.r I (λx.d) ≡ λ λ 1 I (λ 3)
///
/// # Example
/// ```
/// use lambda_calculus::data::result::unwrap_or;
/// use lambda_calculus::*;
///
/// let ok_one: Result<usize, usize> = Ok(1);
/// let err_two: Result<usize, usize> = Err(2);
///
/// assert_eq!(beta(app!(unwrap_or(), 3.into_church(), ok_one.into_church()), NOR, 0), 1.into_church());
/// assert_eq!(beta(app!(unwrap_or(), 3.into_church(), err_two.into_church()), NOR, 0), 3.into_church());
/// ```
pub fn unwrap_or() -> Term {
    abs!(2, app!(Var(1), I(), abs(Var(3))))
}

/// Applied to a function and a lambda-encoded `Result` it applies the function to the contents of
/// the `Result` if it is `Ok`.
///
/// MAP ≡ λfm.m (λx.OK (f x)) ERR ≡ λ λ 1 (λ OK (3 1)) ERR
///
/// # Example
/// ```
/// use lambda_calculus::data::result::map;
/// use lambda_calculus::data::num::church::succ;
/// use lambda_calculus::*;
///
/// let ok_one: Result<usize, usize> = Ok(1);
/// let ok_two: Result<usize, usize> = Ok(2);
/// let err_two: Result<usize, usize> = Err(2);
///
/// assert_eq!(beta(app!(map(), succ(), ok_one.into_church()), NOR, 0), ok_two.into_church());
/// assert_eq!(beta(app!(map(), succ(), err_two.into_church()), NOR, 0), err_two.into_church());
/// ```
pub fn map() -> Term {
    abs!(2, app!(
        Var(1),
        abs(app(ok(), app(Var(3), Var(1)))),
        err()
    ))
}

/// Applied to a function and a lambda-encoded `Result` it applies the function to the contents of
/// the `Result` if it is `Ok`.
///
/// MAP_ERR ≡ λfm.m OK (λx.ERR (f x)) ≡ λ λ 1 OK (λ ERR (3 1))
///
/// # Example
/// ```
/// use lambda_calculus::data::result::map_err;
/// use lambda_calculus::data::num::church::succ;
/// use lambda_calculus::*;
///
/// let ok_one: Result<usize, usize> = Ok(1);
/// let err_two: Result<usize, usize> = Err(2);
/// let err_three: Result<usize, usize> = Err(3);
///
/// assert_eq!(beta(app!(map_err(), succ(), ok_one.into_church()), NOR, 0), ok_one.into_church());
/// assert_eq!(beta(app!(map_err(), succ(), err_two.into_church()), NOR, 0), err_three.into_church());
/// ```
pub fn map_err() -> Term {
    abs!(2, app!(
        Var(1),
        ok(),
        abs(app(err(), app(Var(3), Var(1))))
    ))
}

/// Applied to a lambda-encoded `Result` and a function that returns a lambda-encoded Result, it
/// applies the function to the contents of the `Result` if it is `Ok`.
///
/// AND_THEN ≡ λmf.m f ERR ≡ λ λ 2 1 ERR
///
/// # Example
/// ```
/// use lambda_calculus::data::result::{and_then, ok};
/// use lambda_calculus::data::num::church::succ;
/// use lambda_calculus::*;
///
/// // Equivalent to the closure `|x| { Ok(x+1) }` in Rust
/// let ok_succ: Term = abs(app(ok(), app(succ(), Var(1))));
///
/// let ok_one: Result<usize, usize> = Ok(1);
/// let ok_two: Result<usize, usize> = Ok(2);
/// let err_two: Result<usize, usize> = Err(2);
///
/// assert_eq!(
///     beta(app!(and_then(), err_two.into_church(), ok_succ.clone()), NOR, 0),
///     err_two.into_church()
/// );
/// assert_eq!(
///     beta(app!(and_then(), ok_one.into_church(), ok_succ.clone()), NOR, 0),
///     ok_two.into_church()
/// );
/// ```
pub fn and_then() -> Term {
    abs!(2, app!(Var(2), Var(1), err()))
}

impl Into<Term> for Result<Term, Term> {
    fn into(self) -> Term {
        match self {
            Ok(ok) => abs!(2, app(Var(2), ok)),
            Err(err) => abs!(2, app(Var(1), err))
        }
    }
}
<|endoftext|>


<commit_before>use std::mem;
use libc::{uint32_t, c_void};
use std::raw;

#[allow(non_camel_case_types)]
pub mod ll {
    use libc::{uint32_t, uint64_t, c_void, c_int};

    //SDL_timer.h
    pub type SDL_TimerCallback =
        ::std::option::Option<extern "C" fn(arg1: uint32_t, arg2: *const c_void)
                                            -> uint32_t>;
    pub type SDL_TimerID = c_int;
    extern "C" {
        pub fn SDL_GetTicks() -> uint32_t;
        pub fn SDL_GetPerformanceCounter() -> uint64_t;
        pub fn SDL_GetPerformanceFrequency() -> uint64_t;
        pub fn SDL_Delay(ms: uint32_t);

        pub fn SDL_AddTimer(interval: uint32_t, callback: SDL_TimerCallback,
                            param: *const c_void) -> SDL_TimerID;
        pub fn SDL_RemoveTimer(id: SDL_TimerID) -> c_int;
    }
}

pub fn get_ticks() -> uint {
    unsafe { ll::SDL_GetTicks() as uint }
}

pub fn get_performance_counter() -> u64 {
    unsafe { ll::SDL_GetPerformanceCounter() }
}

pub fn get_performance_frequency() -> u64 {
    unsafe { ll::SDL_GetPerformanceFrequency() }
}

pub fn delay(ms: uint) {
    unsafe { ll::SDL_Delay(ms as u32) }
}

pub struct Timer<'a> {
    delay: uint,
    raw: ll::SDL_TimerID,
    closure: raw::Closure,
    remove_on_drop: bool,
}

impl<'a> Timer<'a> {
    pub fn new<'a>(delay: uint, callback: ||: 'a -> uint, remove_on_drop: bool) -> Timer<'a> {
        unsafe {
            let c_param = mem::transmute::<_, raw::Closure>(callback);
            Timer { delay: delay, raw: 0, closure: c_param, remove_on_drop: remove_on_drop }
        }
    }

    pub fn start(&mut self) {
        unsafe {
            let timer_id = ll::SDL_AddTimer(self.delay as u32, Some(c_timer_callback), mem::transmute(&self.closure));
            self.raw = timer_id;
        }
    }

    pub fn remove(&mut self) -> bool {
        let ret = unsafe { ll::SDL_RemoveTimer(self.raw) };
        if self.raw != 0 {
            self.raw = 0
        }
        ret == 1
    }
}

#[unsafe_destructor]
impl<'a> Drop for Timer<'a> {
    fn drop(&mut self) {
        if self.remove_on_drop {
            let ret = unsafe { ll::SDL_RemoveTimer(self.raw) };
            if ret != 1 {
                println!("error dropping timer {}, maybe already removed.", self.raw);
            }
        }
    }
}

extern "C" fn c_timer_callback(_interval: uint32_t, param: *const c_void) -> uint32_t {
    let f : &mut || -> uint = unsafe { mem::transmute(param) };
    (*f)() as uint32_t
}
<commit_msg>Remove shadowed lifetime<commit_after>use std::mem;
use libc::{uint32_t, c_void};
use std::raw;

#[allow(non_camel_case_types)]
pub mod ll {
    use libc::{uint32_t, uint64_t, c_void, c_int};

    //SDL_timer.h
    pub type SDL_TimerCallback =
        ::std::option::Option<extern "C" fn(arg1: uint32_t, arg2: *const c_void)
                                            -> uint32_t>;
    pub type SDL_TimerID = c_int;
    extern "C" {
        pub fn SDL_GetTicks() -> uint32_t;
        pub fn SDL_GetPerformanceCounter() -> uint64_t;
        pub fn SDL_GetPerformanceFrequency() -> uint64_t;
        pub fn SDL_Delay(ms: uint32_t);

        pub fn SDL_AddTimer(interval: uint32_t, callback: SDL_TimerCallback,
                            param: *const c_void) -> SDL_TimerID;
        pub fn SDL_RemoveTimer(id: SDL_TimerID) -> c_int;
    }
}

pub fn get_ticks() -> uint {
    unsafe { ll::SDL_GetTicks() as uint }
}

pub fn get_performance_counter() -> u64 {
    unsafe { ll::SDL_GetPerformanceCounter() }
}

pub fn get_performance_frequency() -> u64 {
    unsafe { ll::SDL_GetPerformanceFrequency() }
}

pub fn delay(ms: uint) {
    unsafe { ll::SDL_Delay(ms as u32) }
}

pub struct Timer<'a> {
    delay: uint,
    raw: ll::SDL_TimerID,
    closure: raw::Closure,
    remove_on_drop: bool,
}

impl<'a> Timer<'a> {
    pub fn new(delay: uint, callback: ||: 'a -> uint, remove_on_drop: bool) -> Timer<'a> {
        unsafe {
            let c_param = mem::transmute::<_, raw::Closure>(callback);
            Timer { delay: delay, raw: 0, closure: c_param, remove_on_drop: remove_on_drop }
        }
    }

    pub fn start(&mut self) {
        unsafe {
            let timer_id = ll::SDL_AddTimer(self.delay as u32, Some(c_timer_callback), mem::transmute(&self.closure));
            self.raw = timer_id;
        }
    }

    pub fn remove(&mut self) -> bool {
        let ret = unsafe { ll::SDL_RemoveTimer(self.raw) };
        if self.raw != 0 {
            self.raw = 0
        }
        ret == 1
    }
}

#[unsafe_destructor]
impl<'a> Drop for Timer<'a> {
    fn drop(&mut self) {
        if self.remove_on_drop {
            let ret = unsafe { ll::SDL_RemoveTimer(self.raw) };
            if ret != 1 {
                println!("error dropping timer {}, maybe already removed.", self.raw);
            }
        }
    }
}

extern "C" fn c_timer_callback(_interval: uint32_t, param: *const c_void) -> uint32_t {
    let f : &mut || -> uint = unsafe { mem::transmute(param) };
    (*f)() as uint32_t
}
<|endoftext|>


<commit_before>//@ignore-windows: Concurrency on Windows is not supported yet.
//@compile-flags: -Zmiri-ignore-leaks -Zmiri-disable-stacked-borrows

// The following tests check whether our weak memory emulation produces
// any inconsistent execution outcomes
//
// Due to the random nature of choosing valid stores, it is always
// possible that our tests spuriously succeeds: even though our weak
// memory emulation code has incorrectly identified a store in
// modification order as being valid, it may be never chosen by
// the RNG and never observed in our tests.
//
// To mitigate this, each test is ran enough times such that the chance
// of spurious success is very low. These tests never supriously fail.

// Test cases and their consistent outcomes are from
// http://svr-pes20-cppmem.cl.cam.ac.uk/cppmem/
// Based on
// M. Batty, S. Owens, S. Sarkar, P. Sewell and T. Weber,
// "Mathematizing C++ concurrency", ACM SIGPLAN Notices, vol. 46, no. 1, pp. 55-66, 2011.
// Available: https://ss265.host.cs.st-andrews.ac.uk/papers/n3132.pdf.

use std::sync::atomic::Ordering::*;
use std::sync::atomic::{fence, AtomicBool, AtomicI32};
use std::thread::spawn;

#[derive(Copy, Clone)]
struct EvilSend<T>(pub T);

unsafe impl<T> Send for EvilSend<T> {}
unsafe impl<T> Sync for EvilSend<T> {}

// We can't create static items because we need to run each test
// multiple times
fn static_atomic(val: i32) -> &'static AtomicI32 {
    let ret = Box::leak(Box::new(AtomicI32::new(val)));
    ret
}
fn static_atomic_bool(val: bool) -> &'static AtomicBool {
    let ret = Box::leak(Box::new(AtomicBool::new(val)));
    ret
}

// Spins until it acquires a pre-determined value.
fn acquires_value(loc: &AtomicI32, val: i32) -> i32 {
    while loc.load(Acquire) != val {
        std::hint::spin_loop();
    }
    val
}

fn test_corr() {
    let x = static_atomic(0);
    let y = static_atomic(0);

    let j1 = spawn(move || {
        x.store(1, Relaxed);
        x.store(2, Relaxed);
    });

    #[rustfmt::skip]
    let j2 = spawn(move || {
        let r2 = x.load(Relaxed); // -------------------------------------+
        y.store(1, Release); // ---------------------+                    |
        r2 //                                        |                    |
    }); //                                           |                    |
    #[rustfmt::skip] //                              |synchronizes-with   |happens-before
    let j3 = spawn(move || { //                      |                    |
        acquires_value(&y, 1); // <------------------+                    |
        x.load(Relaxed) // <----------------------------------------------+
        // The two reads on x are ordered by hb, so they cannot observe values
        // differently from the modification order. If the first read observed
        // 2, then the second read must observe 2 as well.
    });

    j1.join().unwrap();
    let r2 = j2.join().unwrap();
    let r3 = j3.join().unwrap();
    if r2 == 2 {
        assert_eq!(r3, 2);
    }
}

fn test_wrc() {
    let x = static_atomic(0);
    let y = static_atomic(0);

    #[rustfmt::skip]
    let j1 = spawn(move || {
        x.store(1, Release); // ---------------------+---------------------+
    }); //                                           |                     |
    #[rustfmt::skip] //                              |synchronizes-with    |
    let j2 = spawn(move || { //                      |                     |
        acquires_value(&x, 1); // <------------------+                     |
        y.store(1, Release); // ---------------------+                     |happens-before
    }); //                                           |                     |
    #[rustfmt::skip] //                              |synchronizes-with    |
    let j3 = spawn(move || { //                      |                     |
        acquires_value(&y, 1); // <------------------+                     |
        x.load(Relaxed) // <-----------------------------------------------+
    });

    j1.join().unwrap();
    j2.join().unwrap();
    let r3 = j3.join().unwrap();

    assert_eq!(r3, 1);
}

fn test_message_passing() {
    let mut var = 0u32;
    let ptr = &mut var as *mut u32;
    let x = EvilSend(ptr);
    let y = static_atomic(0);

    #[rustfmt::skip]
    let j1 = spawn(move || {
        unsafe { *x.0 = 1 }; // -----------------------------------------+
        y.store(1, Release); // ---------------------+                   |
    }); //                                           |                   |
    #[rustfmt::skip] //                              |synchronizes-with  | happens-before
    let j2 = spawn(move || { //                      |                   |
        acquires_value(&y, 1); // <------------------+                   |
        unsafe { *x.0 } // <---------------------------------------------+
    });

    j1.join().unwrap();
    let r2 = j2.join().unwrap();

    assert_eq!(r2, 1);
}

// LB+acq_rel+acq_rel
fn test_load_buffering_acq_rel() {
    let x = static_atomic(0);
    let y = static_atomic(0);
    let j1 = spawn(move || {
        let r1 = x.load(Acquire);
        y.store(1, Release);
        r1
    });

    let j2 = spawn(move || {
        let r2 = y.load(Acquire);
        x.store(1, Release);
        r2
    });

    let r1 = j1.join().unwrap();
    let r2 = j2.join().unwrap();

    // 3 consistent outcomes: (0,0), (0,1), (1,0)
    assert_ne!((r1, r2), (1, 1));
}

fn test_mixed_access() {
    /*
    int main() {
      atomic_int x = 0;
      {{{
        x.store(1, mo_relaxed);
      }}}

      x.store(2, mo_relaxed);

      {{{
        r1 = x.load(mo_relaxed);
      }}}

      return 0;
    }
        */
    let x = static_atomic(0);

    spawn(move || {
        x.store(1, Relaxed);
    })
    .join()
    .unwrap();

    x.store(2, Relaxed);

    let r2 = spawn(move || x.load(Relaxed)).join().unwrap();

    assert_eq!(r2, 2);
}

// The following two tests are taken from Repairing Sequential Consistency in C/C++11
// by Lahav et al.
// https://plv.mpi-sws.org/scfix/paper.pdf

// Test case SB
fn test_sc_store_buffering() {
    let x = static_atomic(0);
    let y = static_atomic(0);

    let j1 = spawn(move || {
        x.store(1, SeqCst);
        y.load(SeqCst)
    });

    let j2 = spawn(move || {
        y.store(1, SeqCst);
        x.load(SeqCst)
    });

    let a = j1.join().unwrap();
    let b = j2.join().unwrap();

    assert_ne!((a, b), (0, 0));
}

fn test_single_thread() {
    let x = AtomicI32::new(42);

    assert_eq!(x.load(Relaxed), 42);

    x.store(43, Relaxed);

    assert_eq!(x.load(Relaxed), 43);
}

fn test_sync_through_rmw_and_fences() {
    // Example from https://github.com/llvm/llvm-project/issues/56450#issuecomment-1183695905
    #[no_mangle]
    pub fn rdmw(storing: &AtomicI32, sync: &AtomicI32, loading: &AtomicI32) -> i32 {
        storing.store(1, Relaxed);
        fence(Release);
        sync.fetch_add(0, Relaxed);
        fence(Acquire);
        loading.load(Relaxed)
    }

    let x = static_atomic(0);
    let y = static_atomic(0);
    let z = static_atomic(0);

    // Since each thread is so short, we need to make sure that they truely run at the same time
    // Otherwise t1 will finish before t2 even starts
    let go = static_atomic_bool(false);

    let t1 = spawn(move || {
        while !go.load(Relaxed) {}
        rdmw(y, x, z)
    });

    let t2 = spawn(move || {
        while !go.load(Relaxed) {}
        rdmw(z, x, y)
    });

    go.store(true, Relaxed);

    let a = t1.join().unwrap();
    let b = t2.join().unwrap();
    assert_ne!((a, b), (0, 0));
}

pub fn main() {
    for _ in 0..50 {
        test_single_thread();
        test_mixed_access();
        test_load_buffering_acq_rel();
        test_message_passing();
        test_wrc();
        test_corr();
        test_sc_store_buffering();
        test_sync_through_rmw_and_fences();
    }
}
<commit_msg>add work-around for #2164<commit_after>//@ignore-windows: Concurrency on Windows is not supported yet.
//@compile-flags: -Zmiri-ignore-leaks -Zmiri-disable-stacked-borrows

// The following tests check whether our weak memory emulation produces
// any inconsistent execution outcomes
//
// Due to the random nature of choosing valid stores, it is always
// possible that our tests spuriously succeeds: even though our weak
// memory emulation code has incorrectly identified a store in
// modification order as being valid, it may be never chosen by
// the RNG and never observed in our tests.
//
// To mitigate this, each test is ran enough times such that the chance
// of spurious success is very low. These tests never supriously fail.

// Test cases and their consistent outcomes are from
// http://svr-pes20-cppmem.cl.cam.ac.uk/cppmem/
// Based on
// M. Batty, S. Owens, S. Sarkar, P. Sewell and T. Weber,
// "Mathematizing C++ concurrency", ACM SIGPLAN Notices, vol. 46, no. 1, pp. 55-66, 2011.
// Available: https://ss265.host.cs.st-andrews.ac.uk/papers/n3132.pdf.

use std::sync::atomic::Ordering::*;
use std::sync::atomic::{fence, AtomicBool, AtomicI32};
use std::thread::spawn;

#[derive(Copy, Clone)]
struct EvilSend<T>(pub T);

unsafe impl<T> Send for EvilSend<T> {}
unsafe impl<T> Sync for EvilSend<T> {}

// We can't create static items because we need to run each test
// multiple times
fn static_atomic(val: i32) -> &'static AtomicI32 {
    let ret = Box::leak(Box::new(AtomicI32::new(val)));
    ret.store(val, Relaxed); // work around https://github.com/rust-lang/miri/issues/2164
    ret
}
fn static_atomic_bool(val: bool) -> &'static AtomicBool {
    let ret = Box::leak(Box::new(AtomicBool::new(val)));
    ret.store(val, Relaxed); // work around https://github.com/rust-lang/miri/issues/2164
    ret
}

// Spins until it acquires a pre-determined value.
fn acquires_value(loc: &AtomicI32, val: i32) -> i32 {
    while loc.load(Acquire) != val {
        std::hint::spin_loop();
    }
    val
}

fn test_corr() {
    let x = static_atomic(0);
    let y = static_atomic(0);

    let j1 = spawn(move || {
        x.store(1, Relaxed);
        x.store(2, Relaxed);
    });

    #[rustfmt::skip]
    let j2 = spawn(move || {
        let r2 = x.load(Relaxed); // -------------------------------------+
        y.store(1, Release); // ---------------------+                    |
        r2 //                                        |                    |
    }); //                                           |                    |
    #[rustfmt::skip] //                              |synchronizes-with   |happens-before
    let j3 = spawn(move || { //                      |                    |
        acquires_value(&y, 1); // <------------------+                    |
        x.load(Relaxed) // <----------------------------------------------+
        // The two reads on x are ordered by hb, so they cannot observe values
        // differently from the modification order. If the first read observed
        // 2, then the second read must observe 2 as well.
    });

    j1.join().unwrap();
    let r2 = j2.join().unwrap();
    let r3 = j3.join().unwrap();
    if r2 == 2 {
        assert_eq!(r3, 2);
    }
}

fn test_wrc() {
    let x = static_atomic(0);
    let y = static_atomic(0);

    #[rustfmt::skip]
    let j1 = spawn(move || {
        x.store(1, Release); // ---------------------+---------------------+
    }); //                                           |                     |
    #[rustfmt::skip] //                              |synchronizes-with    |
    let j2 = spawn(move || { //                      |                     |
        acquires_value(&x, 1); // <------------------+                     |
        y.store(1, Release); // ---------------------+                     |happens-before
    }); //                                           |                     |
    #[rustfmt::skip] //                              |synchronizes-with    |
    let j3 = spawn(move || { //                      |                     |
        acquires_value(&y, 1); // <------------------+                     |
        x.load(Relaxed) // <-----------------------------------------------+
    });

    j1.join().unwrap();
    j2.join().unwrap();
    let r3 = j3.join().unwrap();

    assert_eq!(r3, 1);
}

fn test_message_passing() {
    let mut var = 0u32;
    let ptr = &mut var as *mut u32;
    let x = EvilSend(ptr);
    let y = static_atomic(0);

    #[rustfmt::skip]
    let j1 = spawn(move || {
        unsafe { *x.0 = 1 }; // -----------------------------------------+
        y.store(1, Release); // ---------------------+                   |
    }); //                                           |                   |
    #[rustfmt::skip] //                              |synchronizes-with  | happens-before
    let j2 = spawn(move || { //                      |                   |
        acquires_value(&y, 1); // <------------------+                   |
        unsafe { *x.0 } // <---------------------------------------------+
    });

    j1.join().unwrap();
    let r2 = j2.join().unwrap();

    assert_eq!(r2, 1);
}

// LB+acq_rel+acq_rel
fn test_load_buffering_acq_rel() {
    let x = static_atomic(0);
    let y = static_atomic(0);
    let j1 = spawn(move || {
        let r1 = x.load(Acquire);
        y.store(1, Release);
        r1
    });

    let j2 = spawn(move || {
        let r2 = y.load(Acquire);
        x.store(1, Release);
        r2
    });

    let r1 = j1.join().unwrap();
    let r2 = j2.join().unwrap();

    // 3 consistent outcomes: (0,0), (0,1), (1,0)
    assert_ne!((r1, r2), (1, 1));
}

fn test_mixed_access() {
    /*
    int main() {
      atomic_int x = 0;
      {{{
        x.store(1, mo_relaxed);
      }}}

      x.store(2, mo_relaxed);

      {{{
        r1 = x.load(mo_relaxed);
      }}}

      return 0;
    }
        */
    let x = static_atomic(0);

    spawn(move || {
        x.store(1, Relaxed);
    })
    .join()
    .unwrap();

    x.store(2, Relaxed);

    let r2 = spawn(move || x.load(Relaxed)).join().unwrap();

    assert_eq!(r2, 2);
}

// The following two tests are taken from Repairing Sequential Consistency in C/C++11
// by Lahav et al.
// https://plv.mpi-sws.org/scfix/paper.pdf

// Test case SB
fn test_sc_store_buffering() {
    let x = static_atomic(0);
    let y = static_atomic(0);

    let j1 = spawn(move || {
        x.store(1, SeqCst);
        y.load(SeqCst)
    });

    let j2 = spawn(move || {
        y.store(1, SeqCst);
        x.load(SeqCst)
    });

    let a = j1.join().unwrap();
    let b = j2.join().unwrap();

    assert_ne!((a, b), (0, 0));
}

fn test_single_thread() {
    let x = AtomicI32::new(42);

    assert_eq!(x.load(Relaxed), 42);

    x.store(43, Relaxed);

    assert_eq!(x.load(Relaxed), 43);
}

fn test_sync_through_rmw_and_fences() {
    // Example from https://github.com/llvm/llvm-project/issues/56450#issuecomment-1183695905
    #[no_mangle]
    pub fn rdmw(storing: &AtomicI32, sync: &AtomicI32, loading: &AtomicI32) -> i32 {
        storing.store(1, Relaxed);
        fence(Release);
        sync.fetch_add(0, Relaxed);
        fence(Acquire);
        loading.load(Relaxed)
    }

    let x = static_atomic(0);
    let y = static_atomic(0);
    let z = static_atomic(0);

    // Since each thread is so short, we need to make sure that they truely run at the same time
    // Otherwise t1 will finish before t2 even starts
    let go = static_atomic_bool(false);

    let t1 = spawn(move || {
        while !go.load(Relaxed) {}
        rdmw(y, x, z)
    });

    let t2 = spawn(move || {
        while !go.load(Relaxed) {}
        rdmw(z, x, y)
    });

    go.store(true, Relaxed);

    let a = t1.join().unwrap();
    let b = t2.join().unwrap();
    assert_ne!((a, b), (0, 0));
}

pub fn main() {
    for _ in 0..50 {
        test_single_thread();
        test_mixed_access();
        test_load_buffering_acq_rel();
        test_message_passing();
        test_wrc();
        test_corr();
        test_sc_store_buffering();
        test_sync_through_rmw_and_fences();
    }
}
<|endoftext|>


<commit_before>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{Factory, Result, Swarm, Version};
use anyhow::format_err;
use rand::rngs::StdRng;
use std::{env, fs::File, io::Read, num::NonZeroUsize, path::PathBuf};
use tokio::runtime::Runtime;

mod cluster_helper;
mod node;
mod swarm;

pub use cluster_helper::*;
pub use node::K8sNode;
pub use swarm::*;

use diem_sdk::crypto::ed25519::ED25519_PRIVATE_KEY_LENGTH;
use diem_secure_storage::{CryptoStorage, KVStorage, VaultStorage};

const DEFAULT_TESTNET_IMAGE_TAG: &str = "devnet";

pub struct K8sFactory {
    root_key: [u8; ED25519_PRIVATE_KEY_LENGTH],
    treasury_compliance_key: [u8; ED25519_PRIVATE_KEY_LENGTH],
    cluster_name: String,
    helm_repo: String,
    image_tag: String,
    base_image_tag: String,
}

impl K8sFactory {
    pub fn new(
        cluster_name: String,
        helm_repo: String,
        image_tag: String,
        base_image_tag: String,
    ) -> Result<K8sFactory> {
        let vault_addr = env::var("VAULT_ADDR")
            .map_err(|_| format_err!("Expected environment variable VAULT_ADDR"))?;
        let vault_cacert = env::var("VAULT_CACERT")
            .map_err(|_| format_err!("Expected environment variable VAULT_CACERT"))?;
        let vault_token = env::var("VAULT_TOKEN")
            .map_err(|_| format_err!("Expected environment variable VAULT_TOKEN"))?;

        let vault_cacert_path = PathBuf::from(vault_cacert.clone());

        let mut vault_cacert_file = File::open(vault_cacert_path)
            .map_err(|_| format_err!("Failed to open VAULT_CACERT file at {}", &vault_cacert))?;
        let mut vault_cacert_contents = String::new();
        vault_cacert_file
            .read_to_string(&mut vault_cacert_contents)
            .map_err(|_| format_err!("Failed to read VAULT_CACERT file at {}", &vault_cacert))?;

        let vault = VaultStorage::new(
            vault_addr,
            vault_token,
            Some(vault_cacert_contents),
            None,
            false,
            None,
            None,
        );
        vault.available()?;
        let root_key = vault
            .export_private_key("diem__diem_root")
            .unwrap()
            .to_bytes();
        let treasury_compliance_key = vault
            .export_private_key("diem__treasury_compliance")
            .unwrap()
            .to_bytes();

        Ok(Self {
            root_key,
            treasury_compliance_key,
            cluster_name,
            helm_repo,
            image_tag,
            base_image_tag,
        })
    }
}

impl Factory for K8sFactory {
    fn versions<'a>(&'a self) -> Box<dyn Iterator<Item = Version> + 'a> {
        let version = vec![
            Version::new(0, self.base_image_tag.clone()),
            Version::new(1, self.image_tag.clone()),
        ];
        Box::new(version.into_iter())
    }

    fn launch_swarm(
        &self,
        _rng: &mut StdRng,
        node_num: NonZeroUsize,
        version: &Version,
    ) -> Result<Box<dyn Swarm>> {
        set_eks_nodegroup_size(self.cluster_name.clone(), node_num.get(), true)?;
        uninstall_from_k8s_cluster()?;
        clean_k8s_cluster(
            self.helm_repo.clone(),
            node_num.get(),
            format!("{}", version),
            DEFAULT_TESTNET_IMAGE_TAG.to_string(),
            true,
        )?;
        let rt = Runtime::new().unwrap();
        let swarm = rt
            .block_on(K8sSwarm::new(
                &self.root_key,
                &self.treasury_compliance_key,
                &self.cluster_name,
                &self.helm_repo,
                &self.image_tag,
                &self.base_image_tag,
            ))
            .unwrap();
        Ok(Box::new(swarm))
    }
}
<commit_msg>[forge] Always scale down first before test<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{Factory, Result, Swarm, Version};
use anyhow::format_err;
use rand::rngs::StdRng;
use std::{env, fs::File, io::Read, num::NonZeroUsize, path::PathBuf};
use tokio::runtime::Runtime;

mod cluster_helper;
mod node;
mod swarm;

pub use cluster_helper::*;
pub use node::K8sNode;
pub use swarm::*;

use diem_sdk::crypto::ed25519::ED25519_PRIVATE_KEY_LENGTH;
use diem_secure_storage::{CryptoStorage, KVStorage, VaultStorage};

const DEFAULT_TESTNET_IMAGE_TAG: &str = "devnet";

pub struct K8sFactory {
    root_key: [u8; ED25519_PRIVATE_KEY_LENGTH],
    treasury_compliance_key: [u8; ED25519_PRIVATE_KEY_LENGTH],
    cluster_name: String,
    helm_repo: String,
    image_tag: String,
    base_image_tag: String,
}

impl K8sFactory {
    pub fn new(
        cluster_name: String,
        helm_repo: String,
        image_tag: String,
        base_image_tag: String,
    ) -> Result<K8sFactory> {
        let vault_addr = env::var("VAULT_ADDR")
            .map_err(|_| format_err!("Expected environment variable VAULT_ADDR"))?;
        let vault_cacert = env::var("VAULT_CACERT")
            .map_err(|_| format_err!("Expected environment variable VAULT_CACERT"))?;
        let vault_token = env::var("VAULT_TOKEN")
            .map_err(|_| format_err!("Expected environment variable VAULT_TOKEN"))?;

        let vault_cacert_path = PathBuf::from(vault_cacert.clone());

        let mut vault_cacert_file = File::open(vault_cacert_path)
            .map_err(|_| format_err!("Failed to open VAULT_CACERT file at {}", &vault_cacert))?;
        let mut vault_cacert_contents = String::new();
        vault_cacert_file
            .read_to_string(&mut vault_cacert_contents)
            .map_err(|_| format_err!("Failed to read VAULT_CACERT file at {}", &vault_cacert))?;

        let vault = VaultStorage::new(
            vault_addr,
            vault_token,
            Some(vault_cacert_contents),
            None,
            false,
            None,
            None,
        );
        vault.available()?;
        let root_key = vault
            .export_private_key("diem__diem_root")
            .unwrap()
            .to_bytes();
        let treasury_compliance_key = vault
            .export_private_key("diem__treasury_compliance")
            .unwrap()
            .to_bytes();

        Ok(Self {
            root_key,
            treasury_compliance_key,
            cluster_name,
            helm_repo,
            image_tag,
            base_image_tag,
        })
    }
}

impl Factory for K8sFactory {
    fn versions<'a>(&'a self) -> Box<dyn Iterator<Item = Version> + 'a> {
        let version = vec![
            Version::new(0, self.base_image_tag.clone()),
            Version::new(1, self.image_tag.clone()),
        ];
        Box::new(version.into_iter())
    }

    fn launch_swarm(
        &self,
        _rng: &mut StdRng,
        node_num: NonZeroUsize,
        version: &Version,
    ) -> Result<Box<dyn Swarm>> {
        uninstall_from_k8s_cluster()?;
        set_eks_nodegroup_size(self.cluster_name.clone(), 0, true)?;
        set_eks_nodegroup_size(self.cluster_name.clone(), node_num.get(), true)?;
        clean_k8s_cluster(
            self.helm_repo.clone(),
            node_num.get(),
            format!("{}", version),
            DEFAULT_TESTNET_IMAGE_TAG.to_string(),
            true,
        )?;
        let rt = Runtime::new().unwrap();
        let swarm = rt
            .block_on(K8sSwarm::new(
                &self.root_key,
                &self.treasury_compliance_key,
                &self.cluster_name,
                &self.helm_repo,
                &self.image_tag,
                &self.base_image_tag,
            ))
            .unwrap();
        Ok(Box::new(swarm))
    }
}
<|endoftext|>


<commit_before>//! Trait definitions and type aliases.

use image::{
    Rgb,
    Rgba,
    Luma,
    Pixel,
    Primitive,
    ImageBuffer
};
use num::{
    Bounded,
    NumCast
};
use std::{
    u8,
    u16
};

use std::cmp::Ordering::{
    Equal, Greater, Less
};

/// An ImageBuffer containing Pixels of type P with storage
/// Vec<P::Subpixel>.
// TODO: This produces a compiler warning about trait bounds
// TODO: not being enforced in type definitions. In this case
// TODO: they are. Can we get rid of the warning?
pub type VecBuffer<P: Pixel> = ImageBuffer<P, Vec<P::Subpixel>>;

/// Used to name the type we get by replacing
/// the channel type of a given Pixel type.
pub trait WithChannel<C: Primitive>: Pixel {
    type Pixel: Pixel<Subpixel=C> + 'static;
}

pub type ChannelMap<Pix, Sub> = <Pix as WithChannel<Sub>>::Pixel;

impl<T, U> WithChannel<U> for Rgb<T>
    where T: Primitive + 'static,
          U: Primitive + 'static {
    type Pixel = Rgb<U>;
}

impl<T, U> WithChannel<U> for Rgba<T>
    where T: Primitive + 'static,
          U: Primitive + 'static {
    type Pixel = Rgba<U>;
}

impl<T, U> WithChannel<U> for Luma<T>
    where T: Primitive + 'static,
          U: Primitive + 'static {
    type Pixel = Luma<U>;
}

/// Pixels which have a named Black value.
pub trait HasBlack {
    fn black() -> Self;
}

/// Pixels which have a named White value.
pub trait HasWhite {
    fn white() -> Self;
}

impl HasBlack for Luma<u8> {
    fn black() -> Self {
        Luma([0u8])
    }
}

impl HasWhite for Luma<u8> {
    fn white() -> Self {
        Luma([u8::MAX])
    }
}

impl HasBlack for Luma<u16> {
    fn black() -> Self {
        Luma([0u16])
    }
}

impl HasWhite for Luma<u16> {
    fn white() -> Self {
        Luma([u16::MAX])
    }
}

impl HasBlack for Rgb<u8> {
    fn black() -> Self {
        Rgb([0u8; 3])
    }
}

impl HasWhite for Rgb<u8> {
    fn white() -> Self {
        Rgb([u8::MAX; 3])
    }
}

/// A type to which we can clamp a value of type T.
/// Implementations are not required to handle NaNs gracefully.
pub trait Clamp<T> {
    fn clamp(x: T) -> Self;
}

/// Creates an implementation of Clamp<To> for type From.
// TODO: improve performance
macro_rules! implement_clamp {
    ($from:ty, $to:ty) => (
        impl Clamp<$from> for $to {
            fn clamp(x: $from) -> $to {
                clamp_impl(x)
            }
        }
    )
}

implement_clamp!(f32, u8);
implement_clamp!(f32, u16);
implement_clamp!(f64, u8);
implement_clamp!(f64, u16);
implement_clamp!(i32, u8);
implement_clamp!(i32, u16);
implement_clamp!(i32, i16);
implement_clamp!(u16, u8);

/// Clamp a value from a type with larger range to one with
/// a smaller range. Deliberately not exported - should be used
/// via the Clamp trait.
fn clamp_impl<From: NumCast + PartialOrd, To: NumCast + Bounded>(x: From) -> To {
    let to_max = <From as NumCast>::from(To::max_value()).unwrap();
    let to_min = <From as NumCast>::from(To::min_value()).unwrap();
    let clamped = partial_max(partial_min(x, to_max).unwrap(), to_min).unwrap();
    To::from(clamped).unwrap()
}

/// Copied from std::cmp as it's now deprecated.
fn partial_max<T: PartialOrd>(v1: T, v2: T) -> Option<T> {
    match v1.partial_cmp(&v2) {
        Some(Equal) | Some(Less) => Some(v2),
        Some(Greater) => Some(v1),
        None => None
    }
}

/// Copied from std::cmp as it's now deprecated.
fn partial_min<T: PartialOrd>(v1: T, v2: T) -> Option<T> {
    match v1.partial_cmp(&v2) {
        Some(Less) | Some(Equal) => Some(v1),
        Some(Greater) => Some(v2),
        None => None
    }
}

#[cfg(test)]
mod test {

    use super::Clamp;

    #[test]
    fn test_clamp_f32_u8() {
        let t: u8 = Clamp::clamp(255f32);
        assert_eq!(t, 255u8);
        let u: u8 = Clamp::clamp(300f32);
        assert_eq!(u, 255u8);
        let v: u8 = Clamp::clamp(0f32);
        assert_eq!(v, 0u8);
        let w: u8 = Clamp::clamp(-5f32);
        assert_eq!(w, 0u8);
    }

    #[test]
    fn test_clamp_f32_u16() {
        let t: u16 = Clamp::clamp(65535f32);
        assert_eq!(t, 65535u16);
        let u: u16 = Clamp::clamp(300000f32);
        assert_eq!(u, 65535u16);
        let v: u16 = Clamp::clamp(0f32);
        assert_eq!(v, 0u16);
        let w: u16 = Clamp::clamp(-5f32);
        assert_eq!(w, 0u16);
    }
}
<commit_msg>Fix comment<commit_after>//! Trait definitions and type aliases.

use image::{
    Rgb,
    Rgba,
    Luma,
    Pixel,
    Primitive,
    ImageBuffer
};
use num::{
    Bounded,
    NumCast
};
use std::{
    u8,
    u16
};

use std::cmp::Ordering::{
    Equal, Greater, Less
};

/// An ImageBuffer containing Pixels of type P with storage
/// Vec<P::Subpixel>.
// TODO: This produces a compiler warning about trait bounds
// TODO: not being enforced in type definitions. In this case
// TODO: they are. Can we get rid of the warning?
pub type VecBuffer<P: Pixel> = ImageBuffer<P, Vec<P::Subpixel>>;

/// Used to name the type we get by replacing
/// the channel type of a given Pixel type.
pub trait WithChannel<C: Primitive>: Pixel {
    type Pixel: Pixel<Subpixel=C> + 'static;
}

pub type ChannelMap<Pix, Sub> = <Pix as WithChannel<Sub>>::Pixel;

impl<T, U> WithChannel<U> for Rgb<T>
    where T: Primitive + 'static,
          U: Primitive + 'static {
    type Pixel = Rgb<U>;
}

impl<T, U> WithChannel<U> for Rgba<T>
    where T: Primitive + 'static,
          U: Primitive + 'static {
    type Pixel = Rgba<U>;
}

impl<T, U> WithChannel<U> for Luma<T>
    where T: Primitive + 'static,
          U: Primitive + 'static {
    type Pixel = Luma<U>;
}

/// Pixels which have a named Black value.
pub trait HasBlack {
    fn black() -> Self;
}

/// Pixels which have a named White value.
pub trait HasWhite {
    fn white() -> Self;
}

impl HasBlack for Luma<u8> {
    fn black() -> Self {
        Luma([0u8])
    }
}

impl HasWhite for Luma<u8> {
    fn white() -> Self {
        Luma([u8::MAX])
    }
}

impl HasBlack for Luma<u16> {
    fn black() -> Self {
        Luma([0u16])
    }
}

impl HasWhite for Luma<u16> {
    fn white() -> Self {
        Luma([u16::MAX])
    }
}

impl HasBlack for Rgb<u8> {
    fn black() -> Self {
        Rgb([0u8; 3])
    }
}

impl HasWhite for Rgb<u8> {
    fn white() -> Self {
        Rgb([u8::MAX; 3])
    }
}

/// A type to which we can clamp a value of type T.
/// Implementations are not required to handle NaNs gracefully.
pub trait Clamp<T> {
    fn clamp(x: T) -> Self;
}

/// Creates an implementation of Clamp<From> for type To.
// TODO: improve performance
macro_rules! implement_clamp {
    ($from:ty, $to:ty) => (
        impl Clamp<$from> for $to {
            fn clamp(x: $from) -> $to {
                clamp_impl(x)
            }
        }
    )
}

implement_clamp!(f32, u8);
implement_clamp!(f32, u16);
implement_clamp!(f64, u8);
implement_clamp!(f64, u16);
implement_clamp!(i32, u8);
implement_clamp!(i32, u16);
implement_clamp!(i32, i16);
implement_clamp!(u16, u8);

/// Clamp a value from a type with larger range to one with
/// a smaller range. Deliberately not exported - should be used
/// via the Clamp trait.
fn clamp_impl<From: NumCast + PartialOrd, To: NumCast + Bounded>(x: From) -> To {
    let to_max = <From as NumCast>::from(To::max_value()).unwrap();
    let to_min = <From as NumCast>::from(To::min_value()).unwrap();
    let clamped = partial_max(partial_min(x, to_max).unwrap(), to_min).unwrap();
    To::from(clamped).unwrap()
}

/// Copied from std::cmp as it's now deprecated.
fn partial_max<T: PartialOrd>(v1: T, v2: T) -> Option<T> {
    match v1.partial_cmp(&v2) {
        Some(Equal) | Some(Less) => Some(v2),
        Some(Greater) => Some(v1),
        None => None
    }
}

/// Copied from std::cmp as it's now deprecated.
fn partial_min<T: PartialOrd>(v1: T, v2: T) -> Option<T> {
    match v1.partial_cmp(&v2) {
        Some(Less) | Some(Equal) => Some(v1),
        Some(Greater) => Some(v2),
        None => None
    }
}

#[cfg(test)]
mod test {

    use super::Clamp;

    #[test]
    fn test_clamp_f32_u8() {
        let t: u8 = Clamp::clamp(255f32);
        assert_eq!(t, 255u8);
        let u: u8 = Clamp::clamp(300f32);
        assert_eq!(u, 255u8);
        let v: u8 = Clamp::clamp(0f32);
        assert_eq!(v, 0u8);
        let w: u8 = Clamp::clamp(-5f32);
        assert_eq!(w, 0u8);
    }

    #[test]
    fn test_clamp_f32_u16() {
        let t: u16 = Clamp::clamp(65535f32);
        assert_eq!(t, 65535u16);
        let u: u16 = Clamp::clamp(300000f32);
        assert_eq!(u, 65535u16);
        let v: u16 = Clamp::clamp(0f32);
        assert_eq!(v, 0u16);
        let w: u16 = Clamp::clamp(-5f32);
        assert_eq!(w, 0u16);
    }
}
<|endoftext|>


<commit_before>use futures::sync::mpsc;
use futures::{Async, AsyncSink, Future, Poll, Sink, Stream};
use postgres_protocol::message::backend::Message;
use postgres_protocol::message::frontend;
use std::collections::{HashMap, VecDeque};
use std::io;
use tokio_codec::Framed;
use want::Taker;

use disconnected;
use error::{self, Error};
use proto::codec::PostgresCodec;
use proto::socket::Socket;
use {bad_response, CancelData};

pub struct Request {
    pub messages: Vec<u8>,
    pub sender: mpsc::Sender<Message>,
}

#[derive(PartialEq, Debug)]
enum State {
    Active,
    Terminating,
    Closing,
}

pub struct Connection {
    stream: Framed<Socket, PostgresCodec>,
    cancel_data: CancelData,
    parameters: HashMap<String, String>,
    receiver: mpsc::UnboundedReceiver<Request>,
    taker: Taker,
    pending_request: Option<Vec<u8>>,
    pending_response: Option<Message>,
    responses: VecDeque<mpsc::Sender<Message>>,
    state: State,
}

impl Connection {
    pub fn new(
        stream: Framed<Socket, PostgresCodec>,
        cancel_data: CancelData,
        parameters: HashMap<String, String>,
        receiver: mpsc::UnboundedReceiver<Request>,
        taker: Taker,
    ) -> Connection {
        Connection {
            stream,
            cancel_data,
            parameters,
            receiver,
            taker,
            pending_request: None,
            pending_response: None,
            responses: VecDeque::new(),
            state: State::Active,
        }
    }

    pub fn cancel_data(&self) -> CancelData {
        self.cancel_data
    }

    pub fn parameter(&self, name: &str) -> Option<&str> {
        self.parameters.get(name).map(|s| &**s)
    }

    fn poll_response(&mut self) -> Poll<Option<Message>, io::Error> {
        if let Some(message) = self.pending_response.take() {
            trace!("retrying pending response");
            return Ok(Async::Ready(Some(message)));
        }

        self.stream.poll()
    }

    fn poll_read(&mut self) -> Poll<(), Error> {
        if self.state != State::Active {
            trace!("poll_read: done");
            return Ok(Async::Ready(()));
        }

        loop {
            let message = match self.poll_response()? {
                Async::Ready(Some(message)) => message,
                Async::Ready(None) => {
                    return Err(disconnected());
                }
                Async::NotReady => {
                    trace!("poll_read: waiting on response");
                    return Ok(Async::NotReady);
                }
            };

            let message = match message {
                Message::NoticeResponse(_) | Message::NotificationResponse(_) => {
                    // FIXME handle these
                    continue;
                }
                Message::ParameterStatus(body) => {
                    self.parameters
                        .insert(body.name()?.to_string(), body.value()?.to_string());
                    continue;
                }
                m => m,
            };

            let mut sender = match self.responses.pop_front() {
                Some(sender) => sender,
                None => match message {
                    Message::ErrorResponse(error) => return Err(error::__db(error)),
                    _ => return Err(bad_response()),
                },
            };

            let request_complete = match message {
                Message::ReadyForQuery(_) => true,
                _ => false,
            };

            match sender.start_send(message) {
                // if the receiver's hung up we still need to page through the rest of the messages
                // designated to it
                Ok(AsyncSink::Ready) | Err(_) => {
                    if !request_complete {
                        self.responses.push_front(sender);
                    }
                }
                Ok(AsyncSink::NotReady(message)) => {
                    self.responses.push_front(sender);
                    self.pending_response = Some(message);
                    trace!("poll_read: waiting on socket");
                    return Ok(Async::NotReady);
                }
            }
        }
    }

    fn poll_request(&mut self) -> Poll<Option<Vec<u8>>, Error> {
        if let Some(message) = self.pending_request.take() {
            trace!("retrying pending request");
            return Ok(Async::Ready(Some(message)));
        }

        match try_receive!(self.receiver.poll()) {
            Some(request) => {
                trace!("polled new request");
                self.responses.push_back(request.sender);
                Ok(Async::Ready(Some(request.messages)))
            }
            None => Ok(Async::Ready(None)),
        }
    }

    fn poll_write(&mut self) -> Poll<(), Error> {
        loop {
            if self.state == State::Closing {
                trace!("poll_write: done");
                return Ok(Async::Ready(()));
            }

            let request = match self.poll_request()? {
                Async::Ready(Some(request)) => request,
                Async::Ready(None) if self.responses.is_empty() && self.state == State::Active => {
                    trace!("poll_write: at eof, terminating");
                    self.state = State::Terminating;
                    let mut request = vec![];
                    frontend::terminate(&mut request);
                    request
                }
                Async::Ready(None) => {
                    trace!(
                        "poll_write: at eof, pending responses {}",
                        self.responses.len(),
                    );
                    return Ok(Async::Ready(()));
                }
                Async::NotReady => {
                    trace!("poll_write: waiting on request");
                    self.taker.want();
                    return Ok(Async::NotReady);
                }
            };

            match self.stream.start_send(request)? {
                AsyncSink::Ready => {
                    if self.state == State::Terminating {
                        trace!("poll_write: sent eof, closing");
                        self.state = State::Closing;
                    }
                }
                AsyncSink::NotReady(request) => {
                    trace!("poll_write: waiting on socket");
                    self.pending_request = Some(request);
                    return Ok(Async::NotReady);
                }
            }
        }
    }

    fn poll_flush(&mut self) -> Poll<(), Error> {
        trace!("flushing");
        self.stream.poll_complete().map_err(Into::into)
    }

    fn poll_shutdown(&mut self) -> Poll<(), Error> {
        if self.state != State::Closing {
            return Ok(Async::NotReady);
        }

        match self.stream.close() {
            Ok(Async::Ready(())) => {
                trace!("poll_shutdown: complete");
                Ok(Async::Ready(()))
            }
            Ok(Async::NotReady) => {
                trace!("poll_shutdown: waiting on socket");
                Ok(Async::NotReady)
            }
            Err(e) => Err(Error::from(e)),
        }
    }
}

impl Future for Connection {
    type Item = ();
    type Error = Error;

    fn poll(&mut self) -> Poll<(), Error> {
        self.poll_read()?;
        self.poll_write()?;
        self.poll_flush()?;
        self.poll_shutdown()
    }
}
<commit_msg>Only flush if necessary<commit_after>use futures::sync::mpsc;
use futures::{Async, AsyncSink, Future, Poll, Sink, Stream};
use postgres_protocol::message::backend::Message;
use postgres_protocol::message::frontend;
use std::collections::{HashMap, VecDeque};
use std::io;
use tokio_codec::Framed;
use want::Taker;

use disconnected;
use error::{self, Error};
use proto::codec::PostgresCodec;
use proto::socket::Socket;
use {bad_response, CancelData};

pub struct Request {
    pub messages: Vec<u8>,
    pub sender: mpsc::Sender<Message>,
}

#[derive(PartialEq, Debug)]
enum State {
    Active,
    Terminating,
    Closing,
}

pub struct Connection {
    stream: Framed<Socket, PostgresCodec>,
    cancel_data: CancelData,
    parameters: HashMap<String, String>,
    receiver: mpsc::UnboundedReceiver<Request>,
    taker: Taker,
    pending_request: Option<Vec<u8>>,
    pending_response: Option<Message>,
    responses: VecDeque<mpsc::Sender<Message>>,
    state: State,
}

impl Connection {
    pub fn new(
        stream: Framed<Socket, PostgresCodec>,
        cancel_data: CancelData,
        parameters: HashMap<String, String>,
        receiver: mpsc::UnboundedReceiver<Request>,
        taker: Taker,
    ) -> Connection {
        Connection {
            stream,
            cancel_data,
            parameters,
            receiver,
            taker,
            pending_request: None,
            pending_response: None,
            responses: VecDeque::new(),
            state: State::Active,
        }
    }

    pub fn cancel_data(&self) -> CancelData {
        self.cancel_data
    }

    pub fn parameter(&self, name: &str) -> Option<&str> {
        self.parameters.get(name).map(|s| &**s)
    }

    fn poll_response(&mut self) -> Poll<Option<Message>, io::Error> {
        if let Some(message) = self.pending_response.take() {
            trace!("retrying pending response");
            return Ok(Async::Ready(Some(message)));
        }

        self.stream.poll()
    }

    fn poll_read(&mut self) -> Result<(), Error> {
        if self.state != State::Active {
            trace!("poll_read: done");
            return Ok(());
        }

        loop {
            let message = match self.poll_response()? {
                Async::Ready(Some(message)) => message,
                Async::Ready(None) => {
                    return Err(disconnected());
                }
                Async::NotReady => {
                    trace!("poll_read: waiting on response");
                    return Ok(());
                }
            };

            let message = match message {
                Message::NoticeResponse(_) | Message::NotificationResponse(_) => {
                    // FIXME handle these
                    continue;
                }
                Message::ParameterStatus(body) => {
                    self.parameters
                        .insert(body.name()?.to_string(), body.value()?.to_string());
                    continue;
                }
                m => m,
            };

            let mut sender = match self.responses.pop_front() {
                Some(sender) => sender,
                None => match message {
                    Message::ErrorResponse(error) => return Err(error::__db(error)),
                    _ => return Err(bad_response()),
                },
            };

            let request_complete = match message {
                Message::ReadyForQuery(_) => true,
                _ => false,
            };

            match sender.start_send(message) {
                // if the receiver's hung up we still need to page through the rest of the messages
                // designated to it
                Ok(AsyncSink::Ready) | Err(_) => {
                    if !request_complete {
                        self.responses.push_front(sender);
                    }
                }
                Ok(AsyncSink::NotReady(message)) => {
                    self.responses.push_front(sender);
                    self.pending_response = Some(message);
                    trace!("poll_read: waiting on socket");
                    return Ok(());
                }
            }
        }
    }

    fn poll_request(&mut self) -> Poll<Option<Vec<u8>>, Error> {
        if let Some(message) = self.pending_request.take() {
            trace!("retrying pending request");
            return Ok(Async::Ready(Some(message)));
        }

        match try_receive!(self.receiver.poll()) {
            Some(request) => {
                trace!("polled new request");
                self.responses.push_back(request.sender);
                Ok(Async::Ready(Some(request.messages)))
            }
            None => Ok(Async::Ready(None)),
        }
    }

    fn poll_write(&mut self) -> Result<bool, Error> {
        loop {
            if self.state == State::Closing {
                trace!("poll_write: done");
                return Ok(false);
            }

            let request = match self.poll_request()? {
                Async::Ready(Some(request)) => request,
                Async::Ready(None) if self.responses.is_empty() && self.state == State::Active => {
                    trace!("poll_write: at eof, terminating");
                    self.state = State::Terminating;
                    let mut request = vec![];
                    frontend::terminate(&mut request);
                    request
                }
                Async::Ready(None) => {
                    trace!(
                        "poll_write: at eof, pending responses {}",
                        self.responses.len(),
                    );
                    return Ok(true);
                }
                Async::NotReady => {
                    trace!("poll_write: waiting on request");
                    self.taker.want();
                    return Ok(true);
                }
            };

            match self.stream.start_send(request)? {
                AsyncSink::Ready => {
                    if self.state == State::Terminating {
                        trace!("poll_write: sent eof, closing");
                        self.state = State::Closing;
                    }
                }
                AsyncSink::NotReady(request) => {
                    trace!("poll_write: waiting on socket");
                    self.pending_request = Some(request);
                    return Ok(false);
                }
            }
        }
    }

    fn poll_flush(&mut self) -> Result<(), Error> {
        match self.stream.poll_complete() {
            Ok(Async::Ready(())) => {
                trace!("poll_flush: flushed");
                Ok(())
            }
            Ok(Async::NotReady) => {
                trace!("poll_flush: waiting on socket");
                Ok(())
            }
            Err(e) => Err(Error::from(e)),
        }
    }

    fn poll_shutdown(&mut self) -> Poll<(), Error> {
        if self.state != State::Closing {
            return Ok(Async::NotReady);
        }

        match self.stream.close() {
            Ok(Async::Ready(())) => {
                trace!("poll_shutdown: complete");
                Ok(Async::Ready(()))
            }
            Ok(Async::NotReady) => {
                trace!("poll_shutdown: waiting on socket");
                Ok(Async::NotReady)
            }
            Err(e) => Err(Error::from(e)),
        }
    }
}

impl Future for Connection {
    type Item = ();
    type Error = Error;

    fn poll(&mut self) -> Poll<(), Error> {
        self.poll_read()?;
        let want_flush = self.poll_write()?;
        if want_flush {
            self.poll_flush()?;
        }
        self.poll_shutdown()
    }
}
<|endoftext|>


<commit_before>#![deny(warnings)]

extern crate orbtk;

use orbtk::{Button, Point, Rect, TextBox, Window};
use orbtk::callback::Click;
use orbtk::place::Place;

use std::env;
use std::fs::File;
use std::io::{Read, Write};

fn main(){
    let path_option = env::args().nth(1);

    let title = if let Some(ref path) = path_option {
        format!("{} - Editor", path)
    } else {
        format!("Editor")
    };

    let mut window = Window::new(Rect::new(100, 100, 576, 420), &title);

    let text_box = TextBox::new()
        .position(0, 16)
        .size(576, 404)
        .place(&mut window);

    if let Some(ref path) = path_option {
        match File::open(path) {
            Ok(mut file) => {
                let mut text = String::new();
                match file.read_to_string(&mut text) {
                    Ok(_) => text_box.text.set(text),
                    Err(err) => println!("Failed to read {}: {}", path, err)
                }
            },
            Err(err) => println!("Failed to open {}: {}", path, err)
        }
    }

    Button::new()
        .position(0, 0)
        .size(32, 16)
        .text("Save")
        .on_click(move |_button: &Button, _point: Point| {
            if let Some(ref path) = path_option {
                match File::create(path) {
                    Ok(mut file) => {
                        let text = text_box.text.get();
                        match file.write(&mut text.as_bytes()) {
                            Ok(_) => match file.set_len(text.len() as u64) {
                                Ok(_) => println!("Successfully saved {}", path),
                                Err(err) => println!("Failed to truncate {}: {}", path, err)
                            },
                            Err(err) => println!("Failed to write {}: {}", path, err)
                        }
                    },
                    Err(err) => println!("Failed to open {}: {}", path, err)
                }
            } else {
                println!("Need to create file!");
            }
        })
        .place(&mut window);

    window.exec();
}
<commit_msg>Add menu<commit_after>#![deny(warnings)]

extern crate orbtk;

use orbtk::{Action, Menu, Point, Rect, TextBox, Window};
use orbtk::callback::Click;
use orbtk::place::Place;

use std::env;
use std::fs::File;
use std::io::{Read, Write};

fn main(){
    let path_option = env::args().nth(1);

    let title = if let Some(ref path) = path_option {
        format!("{} - Editor", path)
    } else {
        format!("Editor")
    };

    let mut window = Window::new(Rect::new(100, 100, 576, 420), &title);

    let text_box = TextBox::new()
        .position(0, 16)
        .size(576, 404)
        .place(&mut window);

    if let Some(ref path) = path_option {
        match File::open(path) {
            Ok(mut file) => {
                let mut text = String::new();
                match file.read_to_string(&mut text) {
                    Ok(_) => text_box.text.set(text),
                    Err(err) => println!("Failed to read {}: {}", path, err)
                }
            },
            Err(err) => println!("Failed to open {}: {}", path, err)
        }
    }

    let mut menu = Menu::new("File").position(0, 0).size(32, 16);

    menu.add_action(Action::new("Open").on_click(|_action: &Action, _point: Point| {
        println!("Open");
    }));

    menu.add_separator();

    menu.add_action(Action::new("Save").on_click(move |_action: &Action, _point: Point| {
        println!("Save");
        if let Some(ref path) = path_option {
            match File::create(path) {
                Ok(mut file) => {
                    let text = text_box.text.get();
                    match file.write(&mut text.as_bytes()) {
                        Ok(_) => match file.set_len(text.len() as u64) {
                            Ok(_) => println!("Successfully saved {}", path),
                            Err(err) => println!("Failed to truncate {}: {}", path, err)
                        },
                        Err(err) => println!("Failed to write {}: {}", path, err)
                    }
                },
                Err(err) => println!("Failed to open {}: {}", path, err)
            }
        } else {
            println!("Need to create file!");
        }
    }));

    menu.add_action(Action::new("Save As").on_click(|_action: &Action, _point: Point| {
        println!("Save As");
    }));

    menu.add_separator();

    menu.add_action(Action::new("Close").on_click(|_action: &Action, _point: Point| {
        println!("Close");
    }));

    menu.place(&mut window);

    window.exec();
}
<|endoftext|>


<commit_before>/*
    This file is a part of cargo-esr.

    Copyright (C) 2017 Mohammad AlSaleh <CE.Mohammad.AlSaleh at gmail.com>
    https://github.com/rust-alt/cargo-esr

    This Source Code Form is subject to the terms of the Mozilla Public
    License, v. 2.0. If a copy of the MPL was not distributed with this
    file, You can obtain one at <http://mozilla.org/MPL/2.0/>.
*/

use esr_errors::{Result, EsrError};
use tty_string::{TtyString, TtyStyle};
use tty_string::color as C;

const RED_BOLD : fn() -> TtyStyle = || TtyStyle::fg(C::RED).with_bold();
const GREEN_BOLD : fn() -> TtyStyle = || TtyStyle::fg(C::GREEN).with_bold();
const BLUE_BOLD : fn() -> TtyStyle = || TtyStyle::fg(C::BLUE).with_bold();
const YELLOW_BOLD : fn() -> TtyStyle = || TtyStyle::fg(C::YELLOW).with_bold();
const CYAN_BOLD : fn() -> TtyStyle = || TtyStyle::fg(C::CYAN).with_bold();

pub struct EsrPrinter;

impl EsrPrinter {
    pub fn msg_pair(msg: &str, val: impl Into<TtyString>) -> TtyString {
        let val_bold = val.into().with_style(TtyStyle::bold());
        TtyString::new(CYAN_BOLD(), msg) + ": " + val_bold  + "\n "
    }

    pub fn id(id: &str) -> TtyString {
        TtyString::new(BLUE_BOLD(), id)
    }

    pub fn err(val: &str) -> TtyString {
        TtyString::new(RED_BOLD(), val)
    }

    pub fn all_yanked() -> TtyString {
        TtyString::new(RED_BOLD(), "(empty/all yanked)")
    }

    pub fn desc(orig_desc: &str) -> String {
        let desc = String::from(orig_desc);

        // Replace white-space with a single space
        let mut tmp = desc.replace(&['\t', '\n'][..], " ");
        let fixed_ws = loop {
            let curr = tmp.replace("  ", " ");
            if curr == tmp {
                break curr.trim().to_string();
            }
            tmp = curr;
        };

        // Multi-line
        let mut last_n = fixed_ws.rfind('\n').unwrap_or(0);
        let mut multi_line = fixed_ws;

        while multi_line.len() - last_n > 64 {
            let new_n = multi_line
                .get(last_n+1..last_n+64)
                .and_then(|slice| slice.rfind(' '))
                .unwrap_or(last_n);

            if new_n != last_n {
                assert!(last_n+new_n+1 < multi_line.len());
                unsafe { multi_line.as_mut_vec()[last_n+new_n+1] = b'\0' };
                multi_line = multi_line.replace('\0', "\n              ");
                last_n += new_n + " Discription: ".len();
            }
            else {
                break;
            }
        }

        multi_line
    }

    pub fn release(ver_opt: Option<&str>, age_res_opt: Option<Result<f64>>) -> String {
        match (ver_opt, age_res_opt) {
            (Some(ver), Some(Ok(age))) => format!("{} (released {:.1} months ago)", ver, age),
            _ => "N/A".into(),
        }
    }

    pub fn releases(stable: usize, non_yanked_pre: usize, yanked: usize) -> TtyString {
        let stable_f = TtyString::new(GREEN_BOLD(), &format!("{}", stable));
        let non_yanked_pre_f = TtyString::new(YELLOW_BOLD(), &format!("{}", non_yanked_pre));
        let yanked_f = TtyString::new(RED_BOLD(), &format!("{}", yanked));
        stable_f + "+" + non_yanked_pre_f + "+" + yanked_f
    }

    pub fn score_error(msg: &str) -> TtyString {
        TtyString::new(RED_BOLD(), msg) + ": " + TtyString::new(TtyStyle::bold(), "Error") + "\n "
    }

    pub fn score_na(msg: &str) -> TtyString {
        Self::msg_pair(msg, "N/A")
    }

    pub fn score_overview(msg: &str, pos: f64, neg: f64) -> TtyString {
        let score_f = TtyString::new(YELLOW_BOLD(), &format!("{:.3}", pos + neg));
        let score_pos_f = TtyString::new(RED_BOLD(), &format!("{:.3}", neg));
        let score_neg_f = TtyString::new(GREEN_BOLD(), &format!("+{:.3}", pos));

        let tail = score_f + " (" + score_pos_f + " / " + score_neg_f + ")";
        Self::msg_pair(msg, tail)
    }

    pub fn score_details(msg: &str, table: &[(String, String, String)]) -> TtyString {
        let msg = format!("|{: ^83}|", msg);
        let frame ="-".repeat(85);

        let sep = || TtyString::new(CYAN_BOLD(), "| ");
        let frame_line = || TtyString::new(CYAN_BOLD(), &frame) + "\n";

        let mut score_formatted = "".into();
        score_formatted += frame_line();
        score_formatted += TtyString::new(CYAN_BOLD(), &*msg) + "\n";
        score_formatted += frame_line();

        for line in table {
            if line.1.find("* -").is_some() {
                score_formatted += sep() + TtyString::new(YELLOW_BOLD(), &*line.0) + sep();
                score_formatted += TtyString::new(RED_BOLD(), &*line.1) + sep();
                score_formatted += TtyString::new(RED_BOLD(), &format!("{: ^11}", line.2)) + sep() + "\n";
                score_formatted += frame_line();
            } else {
                score_formatted += sep() + TtyString::new(YELLOW_BOLD(), &*line.0) + sep();
                score_formatted += TtyString::new(GREEN_BOLD(), &*line.1) + sep();
                score_formatted += TtyString::new(GREEN_BOLD(), &format!("{: ^11}", "+".to_string() + &line.2)) + sep() + "\n";
                score_formatted += frame_line();
            }
        }

        score_formatted
    }

    pub fn crate_no_score(id: &str, e: &EsrError) -> TtyString {
        let msg = format!("{}.\nFailed to get scores for crate \"{}\". Maybe it does not exist.", e, id);
        TtyString::new(RED_BOLD(), &msg)
    }

    pub fn repo_no_score(repo: &str, e: &EsrError) -> TtyString {
        let msg = format!("{}.\nFailed to get scores for repo \"{}\". Maybe it does not exist.", e, repo);
        TtyString::new(RED_BOLD(), &msg)
    }

    pub fn search_no_results(search_pattern: &str) -> TtyString {
        let msg = format!("Searching for \"{}\" returned no results.", search_pattern);
        TtyString::new(YELLOW_BOLD(), &msg)
    }

    pub fn search_failed(search_pattern: &str, e: &EsrError) -> TtyString {
        let msg = format!("{}.\nSearch for \"{}\" failed.", e, search_pattern);
        TtyString::new(RED_BOLD(), &msg)
    }

    pub fn limit_out_of_range(limit: usize, min: usize, max: usize) -> TtyString {
        let msg = format!("{} is out of the range of valid limits. \
                          Please pass a value between {} and {}.", limit, min, max);
        TtyString::new(YELLOW_BOLD(), &msg)
    }

    pub fn limit_invalid(limit: &str) -> TtyString {
        let msg = format!("\"{}\" is an invalid limit value.", limit);
        TtyString::new(YELLOW_BOLD(), &msg)
    }

    pub fn no_token() -> TtyString {
        let msg = "Accessing GitHub's API wothout hitting rate-limits requires providing an access\
                   token.\n\n\
                   You can pass a token via -g/--gh-token option.\n\
                   Or by setting the variable CARGO_ESR_GH_TOKEN in the environment.\n\n\
                   To a acquire an access token, visit: <https://github.com/settings/tokens/new>\n\n\
                   Alternatively, you can pass -o/--crate-only to skip getting repository info.";
        TtyString::new(YELLOW_BOLD(), msg)
    }
}
<commit_msg>esr_printer: Fix a couple of small formatting issues<commit_after>/*
    This file is a part of cargo-esr.

    Copyright (C) 2017 Mohammad AlSaleh <CE.Mohammad.AlSaleh at gmail.com>
    https://github.com/rust-alt/cargo-esr

    This Source Code Form is subject to the terms of the Mozilla Public
    License, v. 2.0. If a copy of the MPL was not distributed with this
    file, You can obtain one at <http://mozilla.org/MPL/2.0/>.
*/

use esr_errors::{Result, EsrError};
use tty_string::{TtyString, TtyStyle};
use tty_string::color as C;

const BOLD : fn() -> TtyStyle = || TtyStyle::bold();
const RED_BOLD : fn() -> TtyStyle = || TtyStyle::fg(C::RED).with_bold();
const GREEN_BOLD : fn() -> TtyStyle = || TtyStyle::fg(C::GREEN).with_bold();
const BLUE_BOLD : fn() -> TtyStyle = || TtyStyle::fg(C::BLUE).with_bold();
const YELLOW_BOLD : fn() -> TtyStyle = || TtyStyle::fg(C::YELLOW).with_bold();
const CYAN_BOLD : fn() -> TtyStyle = || TtyStyle::fg(C::CYAN).with_bold();

pub struct EsrPrinter;

impl EsrPrinter {
    pub fn msg_pair(msg: &str, val: impl Into<TtyString>) -> TtyString {
        let val_bold = val.into().with_style(TtyStyle::bold());
        TtyString::new(CYAN_BOLD(), msg) + ": " + val_bold  + "\n "
    }

    pub fn id(id: &str) -> TtyString {
        TtyString::new(BLUE_BOLD(), id)
    }

    pub fn err(val: &str) -> TtyString {
        TtyString::new(RED_BOLD(), val)
    }

    pub fn all_yanked() -> TtyString {
        TtyString::new(RED_BOLD(), "(empty/all yanked)")
    }

    pub fn desc(orig_desc: &str) -> String {
        let desc = String::from(orig_desc);

        // Replace white-space with a single space
        let mut tmp = desc.replace(&['\t', '\n'][..], " ");
        let fixed_ws = loop {
            let curr = tmp.replace("  ", " ");
            if curr == tmp {
                break curr.trim().to_string();
            }
            tmp = curr;
        };

        // Multi-line
        let mut last_n = fixed_ws.rfind('\n').unwrap_or(0);
        let mut multi_line = fixed_ws;

        while multi_line.len() - last_n > 64 {
            let new_n = multi_line
                .get(last_n+1..last_n+64)
                .and_then(|slice| slice.rfind(' '))
                .unwrap_or(last_n);

            if new_n != last_n {
                assert!(last_n+new_n+1 < multi_line.len());
                unsafe { multi_line.as_mut_vec()[last_n+new_n+1] = b'\0' };
                multi_line = multi_line.replace('\0', "\n              ");
                last_n += new_n + " Discription: ".len();
            }
            else {
                break;
            }
        }

        multi_line
    }

    pub fn release(ver_opt: Option<&str>, age_res_opt: Option<Result<f64>>) -> String {
        match (ver_opt, age_res_opt) {
            (Some(ver), Some(Ok(age))) => format!("{} (released {:.1} months ago)", ver, age),
            _ => "N/A".into(),
        }
    }

    pub fn releases(stable: usize, non_yanked_pre: usize, yanked: usize) -> TtyString {
        let pos_sign = || TtyString::new(BOLD(), "+");
        let stable_f = TtyString::new(GREEN_BOLD(), &format!("{}", stable));
        let non_yanked_pre_f = TtyString::new(YELLOW_BOLD(), &format!("{}", non_yanked_pre));
        let yanked_f = TtyString::new(RED_BOLD(), &format!("{}", yanked));
        stable_f + pos_sign() + non_yanked_pre_f + pos_sign() + yanked_f
    }

    pub fn score_error(msg: &str) -> TtyString {
        TtyString::new(RED_BOLD(), msg) + ": " + TtyString::new(TtyStyle::bold(), "Error") + "\n "
    }

    pub fn score_na(msg: &str) -> TtyString {
        Self::msg_pair(msg, "N/A")
    }

    pub fn score_overview(msg: &str, pos: f64, neg: f64) -> TtyString {
        let b = |x| TtyString::new(BOLD(), x);
        let score_f = TtyString::new(YELLOW_BOLD(), &format!("{:.3}", pos + neg));
        let score_pos_f = TtyString::new(RED_BOLD(), &format!("{:.3}", neg));
        let score_neg_f = TtyString::new(GREEN_BOLD(), &format!("+{:.3}", pos));

        let tail = score_f + b(" (") + score_pos_f + b(" / ") + score_neg_f + b(")");
        Self::msg_pair(msg, tail)
    }

    pub fn score_details(msg: &str, table: &[(String, String, String)]) -> TtyString {
        let msg = format!("|{: ^83}|", msg);
        let frame ="-".repeat(85);

        let sep = || TtyString::new(CYAN_BOLD(), "| ");
        let frame_line = || TtyString::new(CYAN_BOLD(), &frame) + "\n";

        let mut score_formatted = "".into();
        score_formatted += frame_line();
        score_formatted += TtyString::new(CYAN_BOLD(), &*msg) + "\n";
        score_formatted += frame_line();

        for line in table {
            if line.1.find("* -").is_some() {
                score_formatted += sep() + TtyString::new(YELLOW_BOLD(), &*line.0) + sep();
                score_formatted += TtyString::new(RED_BOLD(), &*line.1) + sep();
                score_formatted += TtyString::new(RED_BOLD(), &format!("{: ^11}", line.2)) + sep() + "\n";
                score_formatted += frame_line();
            } else {
                score_formatted += sep() + TtyString::new(YELLOW_BOLD(), &*line.0) + sep();
                score_formatted += TtyString::new(GREEN_BOLD(), &*line.1) + sep();
                score_formatted += TtyString::new(GREEN_BOLD(), &format!("{: ^11}", "+".to_string() + &line.2)) + sep() + "\n";
                score_formatted += frame_line();
            }
        }

        score_formatted
    }

    pub fn crate_no_score(id: &str, e: &EsrError) -> TtyString {
        let msg = format!("{}.\nFailed to get scores for crate \"{}\". Maybe it does not exist.", e, id);
        TtyString::new(RED_BOLD(), &msg)
    }

    pub fn repo_no_score(repo: &str, e: &EsrError) -> TtyString {
        let msg = format!("{}.\nFailed to get scores for repo \"{}\". Maybe it does not exist.", e, repo);
        TtyString::new(RED_BOLD(), &msg)
    }

    pub fn search_no_results(search_pattern: &str) -> TtyString {
        let msg = format!("Searching for \"{}\" returned no results.", search_pattern);
        TtyString::new(YELLOW_BOLD(), &msg)
    }

    pub fn search_failed(search_pattern: &str, e: &EsrError) -> TtyString {
        let msg = format!("{}.\nSearch for \"{}\" failed.", e, search_pattern);
        TtyString::new(RED_BOLD(), &msg)
    }

    pub fn limit_out_of_range(limit: usize, min: usize, max: usize) -> TtyString {
        let msg = format!("{} is out of the range of valid limits. \
                          Please pass a value between {} and {}.", limit, min, max);
        TtyString::new(YELLOW_BOLD(), &msg)
    }

    pub fn limit_invalid(limit: &str) -> TtyString {
        let msg = format!("\"{}\" is an invalid limit value.", limit);
        TtyString::new(YELLOW_BOLD(), &msg)
    }

    pub fn no_token() -> TtyString {
        let msg = "Accessing GitHub's API wothout hitting rate-limits requires providing an access\
                   token.\n\n\
                   You can pass a token via -g/--gh-token option.\n\
                   Or by setting the variable CARGO_ESR_GH_TOKEN in the environment.\n\n\
                   To a acquire an access token, visit: <https://github.com/settings/tokens/new>\n\n\
                   Alternatively, you can pass -o/--crate-only to skip getting repository info.";
        TtyString::new(YELLOW_BOLD(), msg)
    }
}
<|endoftext|>