<commit_before>use std;

import std::math::*;
import std::float;
import c_int = std::ctypes::c_int;

#[test]
fn test_max_min() {
    assert max(0, 1) == 1;
    assert min(0, 1) == 0;
    assert max(0, -1) == 0;
    assert min(0, -1) == -1;
    assert max(0.0, 1.0) == 1.0;
    assert min(0.0, 1.0) == 0.0;
}

// FIXME use macros to execute the tests below for all float types

#[test]
fn test_trig() {
    assert sin(0.0) == 0.0;
    assert sin(-0.0) == 0.0;

    assert float::isNaN(sin(float::infinity));
    assert float::isNaN(sin(float::neg_infinity));

    assert cos(0.0) == 1.0;
    assert cos(-0.0) == 1.0;
    assert float::isNaN(cos(float::infinity));
    assert float::isNaN(cos(float::neg_infinity));

    assert tan(0.0) == 0.0;
    assert tan(-0.0) == 0.0;;
    assert float::isNaN(tan(float::infinity));
    assert float::isNaN(tan(float::neg_infinity));
}

#[test]
fn test_inv_trig() {
    assert asin(0.0) == 0.0;
    assert asin(-0.0) == -0.0;
    assert float::isNaN(asin(1.1));
    assert float::isNaN(asin(-1.1));

    assert acos(1.0) == 0.0;
    assert float::isNaN(acos(1.1));
    assert float::isNaN(acos(-1.1));

    assert atan(0.0) == 0.0;
    assert atan(-0.0) == 0.0;
    assert atan(float::infinity) == consts::frac_pi_2;
    assert atan(float::neg_infinity) == - consts::frac_pi_2;

    assert atan2(0.0, -0.0) == consts::pi;
    assert atan2(-0.0, -0.0) == -consts::pi;

    assert atan2(0.0, 0.0) == 0.0;
    assert atan2(-0.0, 0.0) == -0.0;

    assert atan2(0.0, -1.0) == consts::pi;
    assert atan2(-0.0, -1.0) == -consts::pi;

    assert atan2(0.0, 1.0) == 0.0;
    assert atan2(-0.0, 1.0) == -0.0;

    assert atan2(1.0, 0.0) == consts::frac_pi_2;
    assert atan2(1.0, -0.0) == consts::frac_pi_2;
}

#[test]
fn test_pow() {
    assert pow(2.0, 4.0) == 16.0;

    assert pow(0.0, -3.0) == float::infinity;
    assert pow(-0.0, -3.0) == float::neg_infinity;

    assert pow(0.0, -4.0) == float::infinity;
    assert pow(-0.0, -4.0) == float::infinity;

    assert pow(0.0, 3.0) == 0.0;
    assert pow(-0.0, 3.0) == -0.0;
    assert pow(0.0, 4.0) == 0.0;
    assert pow(-0.0, 4.0) == 0.0;

    assert pow(-1.0, float::infinity) == 1.0;
    assert pow(-1.0, float::neg_infinity) == 1.0;

    assert pow(1.0, 4.0) == 1.0;
    assert pow(1.0, 0.0) == 1.0;
    assert pow(1.0, -0.0) == 1.0;
    assert pow(1.0, float::NaN) == 1.0;
    assert pow(1.0, float::infinity) == 1.0;
    assert pow(1.0, float::neg_infinity) == 1.0;
    assert pow(1.0, -3.0) == 1.0;
    assert pow(1.0, -4.0) == 1.0;

    assert pow(4.0, 0.0) == 1.0;
    assert pow(0.0, 0.0) == 1.0;
    assert pow(-0.0, 0.0) == 1.0;
    assert pow(float::NaN, 0.0) == 1.0;
    assert pow(float::infinity, 0.0) == 1.0;
    assert pow(float::neg_infinity, 0.0) == 1.0;
    assert pow(-3.0, 0.0) == 1.0;
    assert pow(-4.0, 0.0) == 1.0;

    assert pow(4.0, -0.0) == 1.0;
    assert pow(0.0, -0.0) == 1.0;
    assert pow(-0.0, -0.0) == 1.0;
    assert pow(float::NaN, -0.0) == 1.0;
    assert pow(float::infinity, -0.0) == 1.0;
    assert pow(float::neg_infinity, -0.0) == 1.0;
    assert pow(-3.0, -0.0) == 1.0;
    assert pow(-4.0, -0.0) == 1.0;

    assert float::isNaN(pow(-1.0, -1.5));
    assert float::isNaN(pow(-1.0, 1.5));

    assert float::isNaN(pow(-1.2, -1.5));
    assert float::isNaN(pow(-1.2, 1.5));

    assert pow(0.5, float::neg_infinity) == float::infinity;
    assert pow(-0.5, float::neg_infinity) == float::infinity;

    assert pow(1.5, float::neg_infinity) == 0.0;
    assert pow(-1.5, float::neg_infinity) == 0.0;

    assert pow(0.5, float::infinity) == 0.0;
    assert pow(-0.5, float::infinity) == 0.0;

    assert pow(-1.5, float::infinity) == float::infinity;
    assert pow(1.5, float::infinity) == float::infinity;

    assert pow(float::neg_infinity, -3.0) == -0.0;
    assert pow(float::neg_infinity, -4.0) == 0.0;

    assert pow(float::neg_infinity, 3.0) == float::neg_infinity;
    assert pow(float::neg_infinity, 4.0) == float::infinity;

    assert pow(float::infinity, -16.0) == 0.0;
    assert pow(float::infinity, 16.0) == float::infinity;
}

#[test]
fn test_exp_and_mod() {
    assert exp(0.0) == 1.0;
    assert exp(-0.0) == 1.0;
    assert exp(float::neg_infinity) == 0.0;
    assert exp(float::infinity) == float::infinity;

    let d1: c_int = 1 as c_int;
    assert frexp(0.0, d1) == 0.0;
    assert frexp(-0.0, d1) == 0.0;
    assert frexp(float::infinity, d1) == float::infinity;
    assert frexp(float::neg_infinity, d1) == float::neg_infinity;
    assert float::isNaN(frexp(float::NaN, d1));

    let d2: float = 1.0;
    assert modf(float::infinity, d2) == 0.0;
    assert modf(float::neg_infinity, d2) == -0.0;
    assert float::isNaN(modf(float::NaN, d2));
}

#[test]
fn test_round_and_abs() {
    assert abs(0.0) == 0.0;
    assert abs(-0.0) == 0.0;
    assert abs(float::infinity) == float::infinity;
    assert abs(float::neg_infinity) == float::infinity;

    assert abs(-2.5) == 2.5;
    assert abs(2.5) == 2.5;

    assert ceil(0.0) == 0.0;
    assert ceil(-0.0) == -0.0;
    assert ceil(float::infinity) == float::infinity;
    assert ceil(float::neg_infinity) == float::neg_infinity;

    assert ceil(1.9) == 2.0;
    assert ceil(-1.9) == -1.0;

    assert floor(0.0) == 0.0;
    assert floor(-0.0) == -0.0;
    assert floor(float::infinity) == float::infinity;
    assert floor(float::neg_infinity) == float::neg_infinity;

    assert floor(1.9) == 1.0;
    assert floor(-1.9) == -2.0;

    assert trunc(0.0) == 0.0;
    assert trunc(-0.0) == -0.0;
    assert trunc(float::infinity) == float::infinity;
    assert trunc(float::neg_infinity) == float::neg_infinity;

    assert trunc(1.5) == 1.0;
    assert trunc(1.2) == 1.0;
    assert trunc(1.0) == 1.0;
    assert trunc(1.9) == 1.0;
    assert trunc(-1.5) == -1.0;
    assert trunc(-1.2) == -1.0;
    assert trunc(-1.0) == -1.0;
    assert trunc(-1.9) == -1.0;

    assert round(0.0) == 0.0;
    assert round(-0.0) == -0.0;
    assert round(float::infinity) == float::infinity;
    assert round(float::neg_infinity) == float::neg_infinity;

    assert rint(0.0) == 0.0;
    assert rint(-0.0) == -0.0;
    assert rint(float::infinity) == float::infinity;
    assert rint(float::neg_infinity) == float::neg_infinity;
}

#[test]
fn test_hyp_trig() {
    assert sinh(0.0) == 0.0;
    assert sinh(-0.0) == 0.0;
    assert sinh(float::infinity) == float::infinity;
    assert sinh(float::neg_infinity) == float::neg_infinity;

    assert cosh(0.0) == 1.0;
    assert cosh(-0.0) == 1.0;
    assert cosh(float::infinity) == float::infinity;
    assert cosh(float::neg_infinity) == float::infinity;

    assert tanh(0.0) == 0.0;
    assert tanh(-0.0) == 0.0;
    assert tanh(float::infinity) == 1.0;
    assert tanh(float::neg_infinity) == -1.0;
}

#[test]
fn test_sqrt() {
    assert sqrt(9.0) == 3.0;
    assert sqrt(4.0) == 2.0;
    assert sqrt(1.0) == 1.0;
    assert sqrt(0.0) == 0.0;
}

#[test]
fn test_angle() {
    fn angle(vec: (float, float)) -> float {
        alt vec {
          (0f, y) when y < 0f { 1.5 * consts::pi }
          (0f, y) { 0.5 * consts::pi }
          (x, y) { std::math::atan(y / x) }
        }
    }
    assert angle((1f, 0f)) == 0f;
    assert angle((1f, 1f)) == 0.25 * consts::pi;
    assert angle((0f, 1f)) == 0.5 * consts::pi;
}

#[test]
fn test_log_functions() {
    assert ln(1.0) == 0.0;
    assert log2(1.0) == 0.0;
    assert log10(1.0) == 0.0;

    // FIXME remove round-up due to valgrind weirdness
    assert ceil(ln(consts::e)) == 1.0; /* ln(e) == 0.999.. under valgrind */
    assert log2(2.0) == 1.0;
    assert log10(10.0) == 1.0;

    // FIXME remove round-up due to valgrind weirdness
    assert ceil(ln(consts::e*consts::e*consts::e*consts::e)) == 4.0;
    assert log2(256.0) == 8.0;
    assert log10(1000.0) == 3.0;

    assert ln(0.0) == float::neg_infinity;
    assert log2(0.0) == float::neg_infinity;
    assert log10(0.0) == float::neg_infinity;

    assert ln(-0.0) == float::neg_infinity;
    assert log2(-0.0) == float::neg_infinity;
    assert log10(-0.0) == float::neg_infinity;

    assert float::isNaN(ln(-1.0));
    assert float::isNaN(log2(-1.0));
    assert float::isNaN(log10(-1.0));

    assert ln(float::infinity) == float::infinity;
    assert log2(float::infinity) == float::infinity;
    assert log10(float::infinity) == float::infinity;

    assert ln1p(0.0) == 0.0;
    assert ln1p(-0.0) == 0.0;
    assert ln1p(-1.0) == float::neg_infinity;
    assert float::isNaN(ln1p(-2.0f));
    assert ln1p(float::infinity) == float::infinity;
}<commit_msg>Comment-out some math tests that produce different results on win32<commit_after>use std;

import std::math::*;
import std::float;
import c_int = std::ctypes::c_int;

#[test]
fn test_max_min() {
    assert max(0, 1) == 1;
    assert min(0, 1) == 0;
    assert max(0, -1) == 0;
    assert min(0, -1) == -1;
    assert max(0.0, 1.0) == 1.0;
    assert min(0.0, 1.0) == 0.0;
}

// FIXME use macros to execute the tests below for all float types

#[test]
fn test_trig() {
    assert sin(0.0) == 0.0;
    assert sin(-0.0) == 0.0;

    assert float::isNaN(sin(float::infinity));
    assert float::isNaN(sin(float::neg_infinity));

    assert cos(0.0) == 1.0;
    assert cos(-0.0) == 1.0;
    assert float::isNaN(cos(float::infinity));
    assert float::isNaN(cos(float::neg_infinity));

    assert tan(0.0) == 0.0;
    assert tan(-0.0) == 0.0;;
    assert float::isNaN(tan(float::infinity));
    assert float::isNaN(tan(float::neg_infinity));
}

#[test]
fn test_inv_trig() {
    assert asin(0.0) == 0.0;
    assert asin(-0.0) == -0.0;
    assert float::isNaN(asin(1.1));
    assert float::isNaN(asin(-1.1));

    assert acos(1.0) == 0.0;
    assert float::isNaN(acos(1.1));
    assert float::isNaN(acos(-1.1));

    assert atan(0.0) == 0.0;
    assert atan(-0.0) == 0.0;
    assert atan(float::infinity) == consts::frac_pi_2;
    assert atan(float::neg_infinity) == - consts::frac_pi_2;

    assert atan2(0.0, -0.0) == consts::pi;
    assert atan2(-0.0, -0.0) == -consts::pi;

    assert atan2(0.0, 0.0) == 0.0;
    assert atan2(-0.0, 0.0) == -0.0;

    assert atan2(0.0, -1.0) == consts::pi;
    assert atan2(-0.0, -1.0) == -consts::pi;

    assert atan2(0.0, 1.0) == 0.0;
    assert atan2(-0.0, 1.0) == -0.0;

    assert atan2(1.0, 0.0) == consts::frac_pi_2;
    assert atan2(1.0, -0.0) == consts::frac_pi_2;
}

// FIXME (1222): The commented-out tests give different results on windows
#[test]
fn test_pow() {
    assert pow(2.0, 4.0) == 16.0;

    assert pow(0.0, -3.0) == float::infinity;
    assert pow(-0.0, -3.0) == float::neg_infinity;

    assert pow(0.0, -4.0) == float::infinity;
    assert pow(-0.0, -4.0) == float::infinity;

    assert pow(0.0, 3.0) == 0.0;
    assert pow(-0.0, 3.0) == -0.0;
    assert pow(0.0, 4.0) == 0.0;
    assert pow(-0.0, 4.0) == 0.0;

    assert pow(-1.0, float::infinity) == 1.0;
    //assert pow(-1.0, float::neg_infinity) == 1.0;

    assert pow(1.0, 4.0) == 1.0;
    assert pow(1.0, 0.0) == 1.0;
    assert pow(1.0, -0.0) == 1.0;
    //assert pow(1.0, float::NaN) == 1.0;
    assert pow(1.0, float::infinity) == 1.0;
    //assert pow(1.0, float::neg_infinity) == 1.0;
    assert pow(1.0, -3.0) == 1.0;
    assert pow(1.0, -4.0) == 1.0;

    assert pow(4.0, 0.0) == 1.0;
    assert pow(0.0, 0.0) == 1.0;
    assert pow(-0.0, 0.0) == 1.0;
    //assert pow(float::NaN, 0.0) == 1.0;
    assert pow(float::infinity, 0.0) == 1.0;
    assert pow(float::neg_infinity, 0.0) == 1.0;
    assert pow(-3.0, 0.0) == 1.0;
    assert pow(-4.0, 0.0) == 1.0;

    assert pow(4.0, -0.0) == 1.0;
    assert pow(0.0, -0.0) == 1.0;
    assert pow(-0.0, -0.0) == 1.0;
    //assert pow(float::NaN, -0.0) == 1.0;
    assert pow(float::infinity, -0.0) == 1.0;
    assert pow(float::neg_infinity, -0.0) == 1.0;
    assert pow(-3.0, -0.0) == 1.0;
    assert pow(-4.0, -0.0) == 1.0;

    assert float::isNaN(pow(-1.0, -1.5));
    assert float::isNaN(pow(-1.0, 1.5));

    assert float::isNaN(pow(-1.2, -1.5));
    assert float::isNaN(pow(-1.2, 1.5));

    assert pow(0.5, float::neg_infinity) == float::infinity;
    assert pow(-0.5, float::neg_infinity) == float::infinity;

    assert pow(1.5, float::neg_infinity) == 0.0;
    assert pow(-1.5, float::neg_infinity) == 0.0;

    assert pow(0.5, float::infinity) == 0.0;
    assert pow(-0.5, float::infinity) == 0.0;

    assert pow(-1.5, float::infinity) == float::infinity;
    assert pow(1.5, float::infinity) == float::infinity;

    assert pow(float::neg_infinity, -3.0) == -0.0;
    assert pow(float::neg_infinity, -4.0) == 0.0;

    assert pow(float::neg_infinity, 3.0) == float::neg_infinity;
    assert pow(float::neg_infinity, 4.0) == float::infinity;

    assert pow(float::infinity, -16.0) == 0.0;
    assert pow(float::infinity, 16.0) == float::infinity;
}

// FIXME (1222): The commented-out tests give different results on windows
#[test]
fn test_exp_and_mod() {
    assert exp(0.0) == 1.0;
    assert exp(-0.0) == 1.0;
    assert exp(float::neg_infinity) == 0.0;
    assert exp(float::infinity) == float::infinity;

    let d1: c_int = 1 as c_int;
    assert frexp(0.0, d1) == 0.0;
    assert frexp(-0.0, d1) == 0.0;
    //assert frexp(float::infinity, d1) == float::infinity;
    //assert frexp(float::neg_infinity, d1) == float::neg_infinity;
    assert float::isNaN(frexp(float::NaN, d1));

    let d2: float = 1.0;
    assert modf(float::infinity, d2) == 0.0;
    assert modf(float::neg_infinity, d2) == -0.0;
    assert float::isNaN(modf(float::NaN, d2));
}

#[test]
fn test_round_and_abs() {
    assert abs(0.0) == 0.0;
    assert abs(-0.0) == 0.0;
    assert abs(float::infinity) == float::infinity;
    assert abs(float::neg_infinity) == float::infinity;

    assert abs(-2.5) == 2.5;
    assert abs(2.5) == 2.5;

    assert ceil(0.0) == 0.0;
    assert ceil(-0.0) == -0.0;
    assert ceil(float::infinity) == float::infinity;
    assert ceil(float::neg_infinity) == float::neg_infinity;

    assert ceil(1.9) == 2.0;
    assert ceil(-1.9) == -1.0;

    assert floor(0.0) == 0.0;
    assert floor(-0.0) == -0.0;
    assert floor(float::infinity) == float::infinity;
    assert floor(float::neg_infinity) == float::neg_infinity;

    assert floor(1.9) == 1.0;
    assert floor(-1.9) == -2.0;

    assert trunc(0.0) == 0.0;
    assert trunc(-0.0) == -0.0;
    assert trunc(float::infinity) == float::infinity;
    assert trunc(float::neg_infinity) == float::neg_infinity;

    assert trunc(1.5) == 1.0;
    assert trunc(1.2) == 1.0;
    assert trunc(1.0) == 1.0;
    assert trunc(1.9) == 1.0;
    assert trunc(-1.5) == -1.0;
    assert trunc(-1.2) == -1.0;
    assert trunc(-1.0) == -1.0;
    assert trunc(-1.9) == -1.0;

    assert round(0.0) == 0.0;
    assert round(-0.0) == -0.0;
    assert round(float::infinity) == float::infinity;
    assert round(float::neg_infinity) == float::neg_infinity;

    assert rint(0.0) == 0.0;
    assert rint(-0.0) == -0.0;
    assert rint(float::infinity) == float::infinity;
    assert rint(float::neg_infinity) == float::neg_infinity;
}

#[test]
fn test_hyp_trig() {
    assert sinh(0.0) == 0.0;
    assert sinh(-0.0) == 0.0;
    assert sinh(float::infinity) == float::infinity;
    assert sinh(float::neg_infinity) == float::neg_infinity;

    assert cosh(0.0) == 1.0;
    assert cosh(-0.0) == 1.0;
    assert cosh(float::infinity) == float::infinity;
    assert cosh(float::neg_infinity) == float::infinity;

    assert tanh(0.0) == 0.0;
    assert tanh(-0.0) == 0.0;
    assert tanh(float::infinity) == 1.0;
    assert tanh(float::neg_infinity) == -1.0;
}

#[test]
fn test_sqrt() {
    assert sqrt(9.0) == 3.0;
    assert sqrt(4.0) == 2.0;
    assert sqrt(1.0) == 1.0;
    assert sqrt(0.0) == 0.0;
}

#[test]
fn test_angle() {
    fn angle(vec: (float, float)) -> float {
        alt vec {
          (0f, y) when y < 0f { 1.5 * consts::pi }
          (0f, y) { 0.5 * consts::pi }
          (x, y) { std::math::atan(y / x) }
        }
    }
    assert angle((1f, 0f)) == 0f;
    assert angle((1f, 1f)) == 0.25 * consts::pi;
    assert angle((0f, 1f)) == 0.5 * consts::pi;
}

#[test]
fn test_log_functions() {
    assert ln(1.0) == 0.0;
    assert log2(1.0) == 0.0;
    assert log10(1.0) == 0.0;

    // FIXME remove round-up due to valgrind weirdness
    assert ceil(ln(consts::e)) == 1.0; /* ln(e) == 0.999.. under valgrind */
    assert log2(2.0) == 1.0;
    assert log10(10.0) == 1.0;

    // FIXME remove round-up due to valgrind weirdness
    assert ceil(ln(consts::e*consts::e*consts::e*consts::e)) == 4.0;
    assert log2(256.0) == 8.0;
    assert log10(1000.0) == 3.0;

    assert ln(0.0) == float::neg_infinity;
    assert log2(0.0) == float::neg_infinity;
    assert log10(0.0) == float::neg_infinity;

    assert ln(-0.0) == float::neg_infinity;
    assert log2(-0.0) == float::neg_infinity;
    assert log10(-0.0) == float::neg_infinity;

    assert float::isNaN(ln(-1.0));
    assert float::isNaN(log2(-1.0));
    assert float::isNaN(log10(-1.0));

    assert ln(float::infinity) == float::infinity;
    assert log2(float::infinity) == float::infinity;
    assert log10(float::infinity) == float::infinity;

    assert ln1p(0.0) == 0.0;
    assert ln1p(-0.0) == 0.0;
    assert ln1p(-1.0) == float::neg_infinity;
    assert float::isNaN(ln1p(-2.0f));
    assert ln1p(float::infinity) == float::infinity;
}<|endoftext|>


<commit_before>use crate::mem;
use crate::ptr;
use crate::sync::atomic::AtomicPtr;
use crate::sync::atomic::Ordering::SeqCst;
use crate::sys::c;

pub type Key = c::DWORD;
pub type Dtor = unsafe extern "C" fn(*mut u8);

// Turns out, like pretty much everything, Windows is pretty close the
// functionality that Unix provides, but slightly different! In the case of
// TLS, Windows does not provide an API to provide a destructor for a TLS
// variable. This ends up being pretty crucial to this implementation, so we
// need a way around this.
//
// The solution here ended up being a little obscure, but fear not, the
// internet has informed me [1][2] that this solution is not unique (no way
// I could have thought of it as well!). The key idea is to insert some hook
// somewhere to run arbitrary code on thread termination. With this in place
// we'll be able to run anything we like, including all TLS destructors!
//
// To accomplish this feat, we perform a number of threads, all contained
// within this module:
//
// * All TLS destructors are tracked by *us*, not the windows runtime. This
//   means that we have a global list of destructors for each TLS key that
//   we know about.
// * When a thread exits, we run over the entire list and run dtors for all
//   non-null keys. This attempts to match Unix semantics in this regard.
//
// This ends up having the overhead of using a global list, having some
// locks here and there, and in general just adding some more code bloat. We
// attempt to optimize runtime by forgetting keys that don't have
// destructors, but this only gets us so far.
//
// For more details and nitty-gritty, see the code sections below!
//
// [1]: http://www.codeproject.com/Articles/8113/Thread-Local-Storage-The-C-Way
// [2]: https://github.com/ChromiumWebApps/chromium/blob/master/base
//                        /threading/thread_local_storage_win.cc#L42

// -------------------------------------------------------------------------
// Native bindings
//
// This section is just raw bindings to the native functions that Windows
// provides, There's a few extra calls to deal with destructors.

#[inline]
pub unsafe fn create(dtor: Option<Dtor>) -> Key {
    let key = c::TlsAlloc();
    assert!(key != c::TLS_OUT_OF_INDEXES);
    if let Some(f) = dtor {
        register_dtor(key, f);
    }
    key
}

#[inline]
pub unsafe fn set(key: Key, value: *mut u8) {
    let r = c::TlsSetValue(key, value as c::LPVOID);
    debug_assert!(r != 0);
}

#[inline]
pub unsafe fn get(key: Key) -> *mut u8 {
    c::TlsGetValue(key) as *mut u8
}

#[inline]
pub unsafe fn destroy(_key: Key) {
    rtabort!("can't destroy tls keys on windows")
}

#[inline]
pub fn requires_synchronized_create() -> bool {
    true
}

// -------------------------------------------------------------------------
// Dtor registration
//
// Windows has no native support for running destructors so we manage our own
// list of destructors to keep track of how to destroy keys. We then install a
// callback later to get invoked whenever a thread exits, running all
// appropriate destructors.
//
// Currently unregistration from this list is not supported. A destructor can be
// registered but cannot be unregistered. There's various simplifying reasons
// for doing this, the big ones being:
//
// 1. Currently we don't even support deallocating TLS keys, so normal operation
//    doesn't need to deallocate a destructor.
// 2. There is no point in time where we know we can unregister a destructor
//    because it could always be getting run by some remote thread.
//
// Typically processes have a statically known set of TLS keys which is pretty
// small, and we'd want to keep this memory alive for the whole process anyway
// really.
//
// Perhaps one day we can fold the `Box` here into a static allocation,
// expanding the `StaticKey` structure to contain not only a slot for the TLS
// key but also a slot for the destructor queue on windows. An optimization for
// another day!

static DTORS: AtomicPtr<Node> = AtomicPtr::new(ptr::null_mut());

struct Node {
    dtor: Dtor,
    key: Key,
    next: *mut Node,
}

unsafe fn register_dtor(key: Key, dtor: Dtor) {
    let mut node = Box::new(Node { key, dtor, next: ptr::null_mut() });

    let mut head = DTORS.load(SeqCst);
    loop {
        node.next = head;
        match DTORS.compare_exchange(head, &mut *node, SeqCst, SeqCst) {
            Ok(_) => {
                mem::forget(node);
                return;
            }
            Err(cur) => head = cur,
        }
    }
}

// -------------------------------------------------------------------------
// Where the Magic (TM) Happens
//
// If you're looking at this code, and wondering "what is this doing?",
// you're not alone! I'll try to break this down step by step:
//
// # What's up with CRT$XLB?
//
// For anything about TLS destructors to work on Windows, we have to be able
// to run *something* when a thread exits. To do so, we place a very special
// static in a very special location. If this is encoded in just the right
// way, the kernel's loader is apparently nice enough to run some function
// of ours whenever a thread exits! How nice of the kernel!
//
// Lots of detailed information can be found in source [1] above, but the
// gist of it is that this is leveraging a feature of Microsoft's PE format
// (executable format) which is not actually used by any compilers today.
// This apparently translates to any callbacks in the ".CRT$XLB" section
// being run on certain events.
//
// So after all that, we use the compiler's #[link_section] feature to place
// a callback pointer into the magic section so it ends up being called.
//
// # What's up with this callback?
//
// The callback specified receives a number of parameters from... someone!
// (the kernel? the runtime? I'm not quite sure!) There are a few events that
// this gets invoked for, but we're currently only interested on when a
// thread or a process "detaches" (exits). The process part happens for the
// last thread and the thread part happens for any normal thread.
//
// # Ok, what's up with running all these destructors?
//
// This will likely need to be improved over time, but this function
// attempts a "poor man's" destructor callback system. Once we've got a list
// of what to run, we iterate over all keys, check their values, and then run
// destructors if the values turn out to be non null (setting them to null just
// beforehand). We do this a few times in a loop to basically match Unix
// semantics. If we don't reach a fixed point after a short while then we just
// inevitably leak something most likely.
//
// # The article mentions weird stuff about "/INCLUDE"?
//
// It sure does! Specifically we're talking about this quote:
//
//      The Microsoft run-time library facilitates this process by defining a
//      memory image of the TLS Directory and giving it the special name
//      “__tls_used” (Intel x86 platforms) or “_tls_used” (other platforms). The
//      linker looks for this memory image and uses the data there to create the
//      TLS Directory. Other compilers that support TLS and work with the
//      Microsoft linker must use this same technique.
//
// Basically what this means is that if we want support for our TLS
// destructors/our hook being called then we need to make sure the linker does
// not omit this symbol. Otherwise it will omit it and our callback won't be
// wired up.
//
// We don't actually use the `/INCLUDE` linker flag here like the article
// mentions because the Rust compiler doesn't propagate linker flags, but
// instead we use a shim function which performs a volatile 1-byte load from
// the address of the symbol to ensure it sticks around.

#[link_section = ".CRT$XLB"]
#[allow(dead_code, unused_variables)]
#[used] // we don't want LLVM eliminating this symbol for any reason, and
// when the symbol makes it to the linker the linker will take over
pub static p_thread_callback: unsafe extern "system" fn(c::LPVOID, c::DWORD, c::LPVOID) =
    on_tls_callback;

#[allow(dead_code, unused_variables)]
unsafe extern "system" fn on_tls_callback(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID) {
    if dwReason == c::DLL_THREAD_DETACH || dwReason == c::DLL_PROCESS_DETACH {
        run_dtors();
    }

    // See comments above for what this is doing. Note that we don't need this
    // trickery on GNU windows, just on MSVC.
    reference_tls_used();
    #[cfg(target_env = "msvc")]
    unsafe fn reference_tls_used() {
        extern "C" {
            static _tls_used: u8;
        }
        crate::intrinsics::volatile_load(&_tls_used);
    }
    #[cfg(not(target_env = "msvc"))]
    unsafe fn reference_tls_used() {}
}

#[allow(dead_code)] // actually called above
unsafe fn run_dtors() {
    let mut any_run = true;
    for _ in 0..5 {
        if !any_run {
            break;
        }
        any_run = false;
        let mut cur = DTORS.load(SeqCst);
        while !cur.is_null() {
            let ptr = c::TlsGetValue((*cur).key);

            if !ptr.is_null() {
                c::TlsSetValue((*cur).key, ptr::null_mut());
                ((*cur).dtor)(ptr as *mut _);
                any_run = true;
            }

            cur = (*cur).next;
        }
    }
}
<commit_msg>Windows TLS: ManuallyDrop instead of mem::forget<commit_after>use crate::mem::ManuallyDrop;
use crate::ptr;
use crate::sync::atomic::AtomicPtr;
use crate::sync::atomic::Ordering::SeqCst;
use crate::sys::c;

pub type Key = c::DWORD;
pub type Dtor = unsafe extern "C" fn(*mut u8);

// Turns out, like pretty much everything, Windows is pretty close the
// functionality that Unix provides, but slightly different! In the case of
// TLS, Windows does not provide an API to provide a destructor for a TLS
// variable. This ends up being pretty crucial to this implementation, so we
// need a way around this.
//
// The solution here ended up being a little obscure, but fear not, the
// internet has informed me [1][2] that this solution is not unique (no way
// I could have thought of it as well!). The key idea is to insert some hook
// somewhere to run arbitrary code on thread termination. With this in place
// we'll be able to run anything we like, including all TLS destructors!
//
// To accomplish this feat, we perform a number of threads, all contained
// within this module:
//
// * All TLS destructors are tracked by *us*, not the windows runtime. This
//   means that we have a global list of destructors for each TLS key that
//   we know about.
// * When a thread exits, we run over the entire list and run dtors for all
//   non-null keys. This attempts to match Unix semantics in this regard.
//
// This ends up having the overhead of using a global list, having some
// locks here and there, and in general just adding some more code bloat. We
// attempt to optimize runtime by forgetting keys that don't have
// destructors, but this only gets us so far.
//
// For more details and nitty-gritty, see the code sections below!
//
// [1]: http://www.codeproject.com/Articles/8113/Thread-Local-Storage-The-C-Way
// [2]: https://github.com/ChromiumWebApps/chromium/blob/master/base
//                        /threading/thread_local_storage_win.cc#L42

// -------------------------------------------------------------------------
// Native bindings
//
// This section is just raw bindings to the native functions that Windows
// provides, There's a few extra calls to deal with destructors.

#[inline]
pub unsafe fn create(dtor: Option<Dtor>) -> Key {
    let key = c::TlsAlloc();
    assert!(key != c::TLS_OUT_OF_INDEXES);
    if let Some(f) = dtor {
        register_dtor(key, f);
    }
    key
}

#[inline]
pub unsafe fn set(key: Key, value: *mut u8) {
    let r = c::TlsSetValue(key, value as c::LPVOID);
    debug_assert!(r != 0);
}

#[inline]
pub unsafe fn get(key: Key) -> *mut u8 {
    c::TlsGetValue(key) as *mut u8
}

#[inline]
pub unsafe fn destroy(_key: Key) {
    rtabort!("can't destroy tls keys on windows")
}

#[inline]
pub fn requires_synchronized_create() -> bool {
    true
}

// -------------------------------------------------------------------------
// Dtor registration
//
// Windows has no native support for running destructors so we manage our own
// list of destructors to keep track of how to destroy keys. We then install a
// callback later to get invoked whenever a thread exits, running all
// appropriate destructors.
//
// Currently unregistration from this list is not supported. A destructor can be
// registered but cannot be unregistered. There's various simplifying reasons
// for doing this, the big ones being:
//
// 1. Currently we don't even support deallocating TLS keys, so normal operation
//    doesn't need to deallocate a destructor.
// 2. There is no point in time where we know we can unregister a destructor
//    because it could always be getting run by some remote thread.
//
// Typically processes have a statically known set of TLS keys which is pretty
// small, and we'd want to keep this memory alive for the whole process anyway
// really.
//
// Perhaps one day we can fold the `Box` here into a static allocation,
// expanding the `StaticKey` structure to contain not only a slot for the TLS
// key but also a slot for the destructor queue on windows. An optimization for
// another day!

static DTORS: AtomicPtr<Node> = AtomicPtr::new(ptr::null_mut());

struct Node {
    dtor: Dtor,
    key: Key,
    next: *mut Node,
}

unsafe fn register_dtor(key: Key, dtor: Dtor) {
    let mut node = ManuallyDrop::new(Box::new(Node { key, dtor, next: ptr::null_mut() }));

    let mut head = DTORS.load(SeqCst);
    loop {
        node.next = head;
        match DTORS.compare_exchange(head, &mut **node, SeqCst, SeqCst) {
            Ok(_) => return, // nothing to drop, we successfully added the node to the list
            Err(cur) => head = cur,
        }
    }
}

// -------------------------------------------------------------------------
// Where the Magic (TM) Happens
//
// If you're looking at this code, and wondering "what is this doing?",
// you're not alone! I'll try to break this down step by step:
//
// # What's up with CRT$XLB?
//
// For anything about TLS destructors to work on Windows, we have to be able
// to run *something* when a thread exits. To do so, we place a very special
// static in a very special location. If this is encoded in just the right
// way, the kernel's loader is apparently nice enough to run some function
// of ours whenever a thread exits! How nice of the kernel!
//
// Lots of detailed information can be found in source [1] above, but the
// gist of it is that this is leveraging a feature of Microsoft's PE format
// (executable format) which is not actually used by any compilers today.
// This apparently translates to any callbacks in the ".CRT$XLB" section
// being run on certain events.
//
// So after all that, we use the compiler's #[link_section] feature to place
// a callback pointer into the magic section so it ends up being called.
//
// # What's up with this callback?
//
// The callback specified receives a number of parameters from... someone!
// (the kernel? the runtime? I'm not quite sure!) There are a few events that
// this gets invoked for, but we're currently only interested on when a
// thread or a process "detaches" (exits). The process part happens for the
// last thread and the thread part happens for any normal thread.
//
// # Ok, what's up with running all these destructors?
//
// This will likely need to be improved over time, but this function
// attempts a "poor man's" destructor callback system. Once we've got a list
// of what to run, we iterate over all keys, check their values, and then run
// destructors if the values turn out to be non null (setting them to null just
// beforehand). We do this a few times in a loop to basically match Unix
// semantics. If we don't reach a fixed point after a short while then we just
// inevitably leak something most likely.
//
// # The article mentions weird stuff about "/INCLUDE"?
//
// It sure does! Specifically we're talking about this quote:
//
//      The Microsoft run-time library facilitates this process by defining a
//      memory image of the TLS Directory and giving it the special name
//      “__tls_used” (Intel x86 platforms) or “_tls_used” (other platforms). The
//      linker looks for this memory image and uses the data there to create the
//      TLS Directory. Other compilers that support TLS and work with the
//      Microsoft linker must use this same technique.
//
// Basically what this means is that if we want support for our TLS
// destructors/our hook being called then we need to make sure the linker does
// not omit this symbol. Otherwise it will omit it and our callback won't be
// wired up.
//
// We don't actually use the `/INCLUDE` linker flag here like the article
// mentions because the Rust compiler doesn't propagate linker flags, but
// instead we use a shim function which performs a volatile 1-byte load from
// the address of the symbol to ensure it sticks around.

#[link_section = ".CRT$XLB"]
#[allow(dead_code, unused_variables)]
#[used] // we don't want LLVM eliminating this symbol for any reason, and
// when the symbol makes it to the linker the linker will take over
pub static p_thread_callback: unsafe extern "system" fn(c::LPVOID, c::DWORD, c::LPVOID) =
    on_tls_callback;

#[allow(dead_code, unused_variables)]
unsafe extern "system" fn on_tls_callback(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID) {
    if dwReason == c::DLL_THREAD_DETACH || dwReason == c::DLL_PROCESS_DETACH {
        run_dtors();
    }

    // See comments above for what this is doing. Note that we don't need this
    // trickery on GNU windows, just on MSVC.
    reference_tls_used();
    #[cfg(target_env = "msvc")]
    unsafe fn reference_tls_used() {
        extern "C" {
            static _tls_used: u8;
        }
        crate::intrinsics::volatile_load(&_tls_used);
    }
    #[cfg(not(target_env = "msvc"))]
    unsafe fn reference_tls_used() {}
}

#[allow(dead_code)] // actually called above
unsafe fn run_dtors() {
    let mut any_run = true;
    for _ in 0..5 {
        if !any_run {
            break;
        }
        any_run = false;
        let mut cur = DTORS.load(SeqCst);
        while !cur.is_null() {
            let ptr = c::TlsGetValue((*cur).key);

            if !ptr.is_null() {
                c::TlsSetValue((*cur).key, ptr::null_mut());
                ((*cur).dtor)(ptr as *mut _);
                any_run = true;
            }

            cur = (*cur).next;
        }
    }
}
<|endoftext|>


<commit_before>#[link(name = "fibonacci", vers = "1.0", author = "eliovir")];
#[crate_type = "lib"];
#[license = "MIT"];
#[desc = "Fibonacci library" ];
#[comment = "Example of library: compute Fibonacci"];
/**
 * Compute fibonacci.
 *
 * @license MIT license <http://www.opensource.org/licenses/mit-license.php>
 */

extern mod extra;
/**
* Calcule les elements de la suite de Fibonnaci.
*
* REGLE RG024 Le projet permet de calculer les membres de la Suite de
* Fibonacci.
*
* REGLE RG024.1 : f(1) = 1
* REGLE RG024.2 : f(2) = 1
*
* REGLE RG024.3 : f(n) = f(n-1) + f(n-2) si n > 2
*
* REGLE RG024.4 : il n'est pas possible de calculer la valeur de la Suite
* de Fibonacci pour un rang negatif.
*
* REGLE RG024.5 : le calcul de n'importe quel element de la Suite de
* Fibonacci doit s'effectuer en moins de deux secondes.
*
* REGLE RG024.6 : le calcul de n'importe quel element de la Suite de
* Fibonacci, pour un rang inferieur a 50, doit s'effectuer en moins d'une
* seconde.
*
* @param n le rang pour lequel on calcule le membre.
* @return Le membre de rang n dans la Suite.
*/
pub fn fibonacci(n: int) -> uint {
	if n < 0 {
		fail!(fmt!("%d is negative!", n));
	}
	match n {
		0     => fail!("zero is not a right argument to fibonacci()!"),
		1 | 2 => 1,
		3     => 2,
		/*
		50    => 12586269025,
		*/
		_     => fibonacci(n - 1) + fibonacci(n - 2)
	}
}
/*
#[cfg(test)]
mod tests {
}
*/
fn RG024_x(n: int, expected: uint) {
	// println(fmt!("RG024_x(%d, %u)", n, expected));
	let found = fibonacci(n);
	assert!(expected == found);
}
/**
 * Test du calcul de la suite de Fibonnaci.
 *
 * REGLE RG024.1 : f(1) = 1
 */
#[test]
fn RG024_1() {
	RG024_x(1, 1);
}
/**
 * Test du calcul de la suite de Fibonnaci.
 *
 * REGLE RG024.2 : f(2) = 1
 */
#[test]
fn RG024_2() {
	RG024_x(2, 1);
}
/**
 * Test du calcul de la suite de Fibonnaci.
 *
 * REGLE RG024.3.a : f(3) = 2
 */
#[test]
fn RG024_3_a() {
	RG024_x(3, 2);
}
/**
 * Test du calcul de la suite de Fibonnaci.
 *
 * REGLE RG024.4.a : il n'est pas possible de calculer la valeur de la Suite
 * de Fibonacci pour un rang negatif ou nul.
 */
#[test]
#[should_fail]
fn RG024_4_a() {
	fibonacci(-1);
	fibonacci(0);
}
/**
 * Test du calcul de la suite de Fibonnaci.
 *
 * REGLE RG024.5 : f(55) = 139583862445
 */
#[test]
fn RG024_5() {
	/*RG024_x(55, 139583862445);*/
	RG024_x(30, 832040);
}
#[bench]
fn bench_fibonacci_20(b: &mut extra::test::BenchHarness) {
	do b.iter {
		fibonacci(20);
	}
}
<commit_msg>libfibonacci.rs : Add non reccursive Fibonnacci function<commit_after>#[link(name = "fibonacci", vers = "1.0", author = "eliovir")];
#[crate_type = "lib"];
#[license = "MIT"];
#[desc = "Fibonacci library" ];
#[comment = "Example of library: compute Fibonacci"];
/**
 * Compute fibonacci.
 *
 * @license MIT license <http://www.opensource.org/licenses/mit-license.php>
 */

extern mod extra;
/**
* Calcule les elements de la suite de Fibonnaci.
*
* REGLE RG024 Le projet permet de calculer les membres de la Suite de
* Fibonacci.
*
* REGLE RG024.1 : f(1) = 1
* REGLE RG024.2 : f(2) = 1
*
* REGLE RG024.3 : f(n) = f(n-1) + f(n-2) si n > 2
*
* REGLE RG024.4 : il n'est pas possible de calculer la valeur de la Suite
* de Fibonacci pour un rang negatif.
*
* REGLE RG024.5 : le calcul de n'importe quel element de la Suite de
* Fibonacci doit s'effectuer en moins de deux secondes.
*
* REGLE RG024.6 : le calcul de n'importe quel element de la Suite de
* Fibonacci, pour un rang inferieur a 50, doit s'effectuer en moins d'une
* seconde.
*
* @param n le rang pour lequel on calcule le membre.
* @return Le membre de rang n dans la Suite.
*/
pub fn fibonacci_reccursive(n: int) -> uint {
	if n < 0 {
		fail!(fmt!("%d is negative!", n));
	}
	match n {
		0     => fail!("zero is not a right argument to fibonacci_reccursive()!"),
		1 | 2 => 1,
		3     => 2,
		/*
		50    => 12586269025,
		*/
		_     => fibonacci(n - 1) + fibonacci(n - 2)
	}
}

/**
 * Non reccursive function.
 */
pub fn fibonacci(n: int) -> uint {
	if n < 0 {
		fail!(fmt!("%d is negative!", n));
	} else if n == 0 {
		fail!("zero is not a right argument to fibonacci()!");
	} else if n == 1 {
		return 1u;
	}
	let mut i = 0;
	let mut sum = 0;
	let mut last = 0;
	let mut curr = 1;
	while (i < n - 1) {
		sum = last + curr;
		last = curr;
		curr = sum;
		i += 1;
	}
	sum
}

/*
#[cfg(test)]
mod tests {
}
*/
fn RG024_x(n: int, expected: uint) {
	// println(fmt!("RG024_x(%d, %u)", n, expected));
	let found = fibonacci(n);
	assert!(expected == found, fmt!("fib(%d): expected (%u) != found (%u)", n, expected, found));
}
/**
 * Test du calcul de la suite de Fibonnaci.
 *
 * REGLE RG024.1 : f(1) = 1
 */
#[test]
fn RG024_1() {
	RG024_x(1, 1);
}
/**
 * Test du calcul de la suite de Fibonnaci.
 *
 * REGLE RG024.2 : f(2) = 1
 */
#[test]
fn RG024_2() {
	RG024_x(2, 1);
}
/**
 * Test du calcul de la suite de Fibonnaci.
 *
 * REGLE RG024.3.a : f(3) = 2
 */
#[test]
fn RG024_3_a() {
	RG024_x(3, 2);
}
/**
 * Test du calcul de la suite de Fibonnaci.
 *
 * REGLE RG024.4.a : il n'est pas possible de calculer la valeur de la Suite
 * de Fibonacci pour un rang negatif ou nul.
 */
#[test]
#[should_fail]
fn RG024_4_a() {
	fibonacci(-1);
	fibonacci(0);
}
/**
 * Test du calcul de la suite de Fibonnaci.
 *
 * REGLE RG024.5 : f(55) = 139583862445
 */
#[test]
fn RG024_5() {
	/*RG024_x(55, 139583862445);*/
	RG024_x(30, 832040);
}
#[bench]
fn bench_fibonacci_reccursive_20(b: &mut extra::test::BenchHarness) {
	do b.iter {
		fibonacci_reccursive(20);
	}
}
#[bench]
fn bench_fibonacci_20(b: &mut extra::test::BenchHarness) {
	do b.iter {
		fibonacci(20);
	}
}
<|endoftext|>


<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use std::path::PathBuf;

use clap::{Arg, ArgMatches};

use libimagstore::storeid::StoreId;

use error::InteractionError as IE;
use error::Result;
use error::InteractionErrorKind as IEK;
use error::ResultExt;

pub fn id_argument<'a, 'b>() -> Arg<'a, 'b> {
    Arg::with_name(id_argument_name())
        .short(id_argument_short())
        .long(id_argument_long())
        .takes_value(true)
        .multiple(true)
        .help("Specify the Store-Id")
}

pub fn id_argument_name() -> &'static str {
    "id-argument"
}

pub fn id_argument_short() -> &'static str {
    "i"
}

pub fn id_argument_long() -> &'static str {
    "id"
}

pub fn get_id(matches: &ArgMatches) -> Result<Vec<StoreId>> {
    matches
        .values_of(id_argument_name())
        .ok_or(IE::from_kind(IEK::IdMissingError))
        .chain_err(|| IEK::CLIError)
        .and_then(|vals| {
            vals.into_iter()
                .fold(Ok(vec![]), |acc, elem| {
                    acc.and_then(|mut v| {
                        let elem = StoreId::new_baseless(PathBuf::from(String::from(elem)));
                        let elem = elem.chain_err(|| IEK::StoreIdParsingError)?;
                        v.push(elem);
                        Ok(v)
                    })
                })
        })
}

pub fn get_or_select_id(matches: &ArgMatches, store_path: &PathBuf) -> Result<Vec<StoreId>> {
    use interactor::{pick_file, default_menu_cmd};

    match get_id(matches).chain_err(|| IEK::IdSelectingError) {
        Ok(v) => Ok(v),
        Err(_) => {
            let path = store_path.clone();
            let p  = pick_file(default_menu_cmd, path).chain_err(|| IEK::IdSelectingError)?;
            let id = StoreId::new_baseless(p).chain_err(|| IEK::StoreIdParsingError)?;
            Ok(vec![id])
        },
    }
}

<commit_msg>Replace matching with command chaining<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use std::path::PathBuf;

use clap::{Arg, ArgMatches};

use libimagstore::storeid::StoreId;

use error::InteractionError as IE;
use error::Result;
use error::InteractionErrorKind as IEK;
use error::ResultExt;

pub fn id_argument<'a, 'b>() -> Arg<'a, 'b> {
    Arg::with_name(id_argument_name())
        .short(id_argument_short())
        .long(id_argument_long())
        .takes_value(true)
        .multiple(true)
        .help("Specify the Store-Id")
}

pub fn id_argument_name() -> &'static str {
    "id-argument"
}

pub fn id_argument_short() -> &'static str {
    "i"
}

pub fn id_argument_long() -> &'static str {
    "id"
}

pub fn get_id(matches: &ArgMatches) -> Result<Vec<StoreId>> {
    matches
        .values_of(id_argument_name())
        .ok_or(IE::from_kind(IEK::IdMissingError))
        .chain_err(|| IEK::CLIError)
        .and_then(|vals| {
            vals.into_iter()
                .fold(Ok(vec![]), |acc, elem| {
                    acc.and_then(|mut v| {
                        let elem = StoreId::new_baseless(PathBuf::from(String::from(elem)));
                        let elem = elem.chain_err(|| IEK::StoreIdParsingError)?;
                        v.push(elem);
                        Ok(v)
                    })
                })
        })
}

pub fn get_or_select_id(matches: &ArgMatches, store_path: &PathBuf) -> Result<Vec<StoreId>> {
    use interactor::{pick_file, default_menu_cmd};

    get_id(matches)
        .chain_err(|| IEK::IdSelectingError)
        .or_else(|_| {
            let path = store_path.clone();
            let p    = pick_file(default_menu_cmd, path).chain_err(|| IEK::IdSelectingError)?;
            let id   = StoreId::new_baseless(p).chain_err(|| IEK::StoreIdParsingError)?;
            Ok(vec![id])
        })
}

<|endoftext|>


<commit_before>use crate::{convert, ops};

/// Used to tell an operation whether it should exit early or go on as usual.
///
/// This is used when exposing things (like graph traversals or visitors) where
/// you want the user to be able to choose whether to exit early.
/// Having the enum makes it clearer -- no more wondering "wait, what did `false`
/// mean again?" -- and allows including a value.
///
/// # Examples
///
/// Early-exiting from [`Iterator::try_for_each`]:
/// ```
/// use std::ops::ControlFlow;
///
/// let r = (2..100).try_for_each(|x| {
///     if 403 % x == 0 {
///         return ControlFlow::Break(x)
///     }
///
///     ControlFlow::Continue(())
/// });
/// assert_eq!(r, ControlFlow::Break(13));
/// ```
///
/// A basic tree traversal:
/// ```no_run
/// use std::ops::ControlFlow;
///
/// pub struct TreeNode<T> {
///     value: T,
///     left: Option<Box<TreeNode<T>>>,
///     right: Option<Box<TreeNode<T>>>,
/// }
///
/// impl<T> TreeNode<T> {
///     pub fn traverse_inorder<B>(&self, mut f: impl FnMut(&T) -> ControlFlow<B>) -> ControlFlow<B> {
///         if let Some(left) = &self.left {
///             left.traverse_inorder(&mut f)?;
///         }
///         f(&self.value)?;
///         if let Some(right) = &self.right {
///             right.traverse_inorder(&mut f)?;
///         }
///         ControlFlow::Continue(())
///     }
/// }
/// ```
#[stable(feature = "control_flow_enum_type", since = "1.55.0")]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ControlFlow<B, C = ()> {
    /// Move on to the next phase of the operation as normal.
    #[stable(feature = "control_flow_enum_type", since = "1.55.0")]
    #[lang = "Continue"]
    Continue(C),
    /// Exit the operation without running subsequent phases.
    #[stable(feature = "control_flow_enum_type", since = "1.55.0")]
    #[lang = "Break"]
    Break(B),
    // Yes, the order of the variants doesn't match the type parameters.
    // They're in this order so that `ControlFlow<A, B>` <-> `Result<B, A>`
    // is a no-op conversion in the `Try` implementation.
}

#[unstable(feature = "try_trait_v2", issue = "84277")]
impl<B, C> ops::Try for ControlFlow<B, C> {
    type Output = C;
    type Residual = ControlFlow<B, convert::Infallible>;

    #[inline]
    fn from_output(output: Self::Output) -> Self {
        ControlFlow::Continue(output)
    }

    #[inline]
    fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
        match self {
            ControlFlow::Continue(c) => ControlFlow::Continue(c),
            ControlFlow::Break(b) => ControlFlow::Break(ControlFlow::Break(b)),
        }
    }
}

#[unstable(feature = "try_trait_v2", issue = "84277")]
impl<B, C> ops::FromResidual for ControlFlow<B, C> {
    #[inline]
    fn from_residual(residual: ControlFlow<B, convert::Infallible>) -> Self {
        match residual {
            ControlFlow::Break(b) => ControlFlow::Break(b),
        }
    }
}

impl<B, C> ControlFlow<B, C> {
    /// Returns `true` if this is a `Break` variant.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(control_flow_enum)]
    /// use std::ops::ControlFlow;
    ///
    /// assert!(ControlFlow::<i32, String>::Break(3).is_break());
    /// assert!(!ControlFlow::<String, i32>::Continue(3).is_break());
    /// ```
    #[inline]
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    pub fn is_break(&self) -> bool {
        matches!(*self, ControlFlow::Break(_))
    }

    /// Returns `true` if this is a `Continue` variant.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(control_flow_enum)]
    /// use std::ops::ControlFlow;
    ///
    /// assert!(!ControlFlow::<i32, String>::Break(3).is_continue());
    /// assert!(ControlFlow::<String, i32>::Continue(3).is_continue());
    /// ```
    #[inline]
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    pub fn is_continue(&self) -> bool {
        matches!(*self, ControlFlow::Continue(_))
    }

    /// Converts the `ControlFlow` into an `Option` which is `Some` if the
    /// `ControlFlow` was `Break` and `None` otherwise.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(control_flow_enum)]
    /// use std::ops::ControlFlow;
    ///
    /// assert_eq!(ControlFlow::<i32, String>::Break(3).break_value(), Some(3));
    /// assert_eq!(ControlFlow::<String, i32>::Continue(3).break_value(), None);
    /// ```
    #[inline]
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    pub fn break_value(self) -> Option<B> {
        match self {
            ControlFlow::Continue(..) => None,
            ControlFlow::Break(x) => Some(x),
        }
    }

    /// Maps `ControlFlow<B, C>` to `ControlFlow<T, C>` by applying a function
    /// to the break value in case it exists.
    #[inline]
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    pub fn map_break<T, F>(self, f: F) -> ControlFlow<T, C>
    where
        F: FnOnce(B) -> T,
    {
        match self {
            ControlFlow::Continue(x) => ControlFlow::Continue(x),
            ControlFlow::Break(x) => ControlFlow::Break(f(x)),
        }
    }
}

/// These are used only as part of implementing the iterator adapters.
/// They have mediocre names and non-obvious semantics, so aren't
/// currently on a path to potential stabilization.
impl<R: ops::Try> ControlFlow<R, R::Output> {
    /// Create a `ControlFlow` from any type implementing `Try`.
    #[inline]
    pub(crate) fn from_try(r: R) -> Self {
        match R::branch(r) {
            ControlFlow::Continue(v) => ControlFlow::Continue(v),
            ControlFlow::Break(v) => ControlFlow::Break(R::from_residual(v)),
        }
    }

    /// Convert a `ControlFlow` into any type implementing `Try`;
    #[inline]
    pub(crate) fn into_try(self) -> R {
        match self {
            ControlFlow::Continue(v) => R::from_output(v),
            ControlFlow::Break(v) => v,
        }
    }
}

impl<B> ControlFlow<B, ()> {
    /// It's frequently the case that there's no value needed with `Continue`,
    /// so this provides a way to avoid typing `(())`, if you prefer it.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(control_flow_enum)]
    /// use std::ops::ControlFlow;
    ///
    /// let mut partial_sum = 0;
    /// let last_used = (1..10).chain(20..25).try_for_each(|x| {
    ///     partial_sum += x;
    ///     if partial_sum > 100 { ControlFlow::Break(x) }
    ///     else { ControlFlow::CONTINUE }
    /// });
    /// assert_eq!(last_used.break_value(), Some(22));
    /// ```
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    pub const CONTINUE: Self = ControlFlow::Continue(());
}

impl<C> ControlFlow<(), C> {
    /// APIs like `try_for_each` don't need values with `Break`,
    /// so this provides a way to avoid typing `(())`, if you prefer it.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(control_flow_enum)]
    /// use std::ops::ControlFlow;
    ///
    /// let mut partial_sum = 0;
    /// (1..10).chain(20..25).try_for_each(|x| {
    ///     if partial_sum > 100 { ControlFlow::BREAK }
    ///     else { partial_sum += x; ControlFlow::CONTINUE }
    /// });
    /// assert_eq!(partial_sum, 108);
    /// ```
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    pub const BREAK: Self = ControlFlow::Break(());
}
<commit_msg>Add paragraph to ControlFlow docs to menion it works with the ? operator (#88715)<commit_after>use crate::{convert, ops};

/// Used to tell an operation whether it should exit early or go on as usual.
///
/// This is used when exposing things (like graph traversals or visitors) where
/// you want the user to be able to choose whether to exit early.
/// Having the enum makes it clearer -- no more wondering "wait, what did `false`
/// mean again?" -- and allows including a value.
///
/// Similar to [`Option`] and [`Result`], this enum can be used with the `?` operator
/// to return immediatly if the [`Break`] variant is present or to continue normally
/// with the value inside the [`Continue`] variant.
///
/// # Examples
///
/// Early-exiting from [`Iterator::try_for_each`]:
/// ```
/// use std::ops::ControlFlow;
///
/// let r = (2..100).try_for_each(|x| {
///     if 403 % x == 0 {
///         return ControlFlow::Break(x)
///     }
///
///     ControlFlow::Continue(())
/// });
/// assert_eq!(r, ControlFlow::Break(13));
/// ```
///
/// A basic tree traversal:
/// ```no_run
/// use std::ops::ControlFlow;
///
/// pub struct TreeNode<T> {
///     value: T,
///     left: Option<Box<TreeNode<T>>>,
///     right: Option<Box<TreeNode<T>>>,
/// }
///
/// impl<T> TreeNode<T> {
///     pub fn traverse_inorder<B>(&self, mut f: impl FnMut(&T) -> ControlFlow<B>) -> ControlFlow<B> {
///         if let Some(left) = &self.left {
///             left.traverse_inorder(&mut f)?;
///         }
///         f(&self.value)?;
///         if let Some(right) = &self.right {
///             right.traverse_inorder(&mut f)?;
///         }
///         ControlFlow::Continue(())
///     }
/// }
/// ```
///
/// [`Break`]: ControlFlow::Break
/// [`Continue`]: ControlFlow::Continue
#[stable(feature = "control_flow_enum_type", since = "1.55.0")]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ControlFlow<B, C = ()> {
    /// Move on to the next phase of the operation as normal.
    #[stable(feature = "control_flow_enum_type", since = "1.55.0")]
    #[lang = "Continue"]
    Continue(C),
    /// Exit the operation without running subsequent phases.
    #[stable(feature = "control_flow_enum_type", since = "1.55.0")]
    #[lang = "Break"]
    Break(B),
    // Yes, the order of the variants doesn't match the type parameters.
    // They're in this order so that `ControlFlow<A, B>` <-> `Result<B, A>`
    // is a no-op conversion in the `Try` implementation.
}

#[unstable(feature = "try_trait_v2", issue = "84277")]
impl<B, C> ops::Try for ControlFlow<B, C> {
    type Output = C;
    type Residual = ControlFlow<B, convert::Infallible>;

    #[inline]
    fn from_output(output: Self::Output) -> Self {
        ControlFlow::Continue(output)
    }

    #[inline]
    fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
        match self {
            ControlFlow::Continue(c) => ControlFlow::Continue(c),
            ControlFlow::Break(b) => ControlFlow::Break(ControlFlow::Break(b)),
        }
    }
}

#[unstable(feature = "try_trait_v2", issue = "84277")]
impl<B, C> ops::FromResidual for ControlFlow<B, C> {
    #[inline]
    fn from_residual(residual: ControlFlow<B, convert::Infallible>) -> Self {
        match residual {
            ControlFlow::Break(b) => ControlFlow::Break(b),
        }
    }
}

impl<B, C> ControlFlow<B, C> {
    /// Returns `true` if this is a `Break` variant.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(control_flow_enum)]
    /// use std::ops::ControlFlow;
    ///
    /// assert!(ControlFlow::<i32, String>::Break(3).is_break());
    /// assert!(!ControlFlow::<String, i32>::Continue(3).is_break());
    /// ```
    #[inline]
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    pub fn is_break(&self) -> bool {
        matches!(*self, ControlFlow::Break(_))
    }

    /// Returns `true` if this is a `Continue` variant.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(control_flow_enum)]
    /// use std::ops::ControlFlow;
    ///
    /// assert!(!ControlFlow::<i32, String>::Break(3).is_continue());
    /// assert!(ControlFlow::<String, i32>::Continue(3).is_continue());
    /// ```
    #[inline]
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    pub fn is_continue(&self) -> bool {
        matches!(*self, ControlFlow::Continue(_))
    }

    /// Converts the `ControlFlow` into an `Option` which is `Some` if the
    /// `ControlFlow` was `Break` and `None` otherwise.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(control_flow_enum)]
    /// use std::ops::ControlFlow;
    ///
    /// assert_eq!(ControlFlow::<i32, String>::Break(3).break_value(), Some(3));
    /// assert_eq!(ControlFlow::<String, i32>::Continue(3).break_value(), None);
    /// ```
    #[inline]
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    pub fn break_value(self) -> Option<B> {
        match self {
            ControlFlow::Continue(..) => None,
            ControlFlow::Break(x) => Some(x),
        }
    }

    /// Maps `ControlFlow<B, C>` to `ControlFlow<T, C>` by applying a function
    /// to the break value in case it exists.
    #[inline]
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    pub fn map_break<T, F>(self, f: F) -> ControlFlow<T, C>
    where
        F: FnOnce(B) -> T,
    {
        match self {
            ControlFlow::Continue(x) => ControlFlow::Continue(x),
            ControlFlow::Break(x) => ControlFlow::Break(f(x)),
        }
    }
}

/// These are used only as part of implementing the iterator adapters.
/// They have mediocre names and non-obvious semantics, so aren't
/// currently on a path to potential stabilization.
impl<R: ops::Try> ControlFlow<R, R::Output> {
    /// Create a `ControlFlow` from any type implementing `Try`.
    #[inline]
    pub(crate) fn from_try(r: R) -> Self {
        match R::branch(r) {
            ControlFlow::Continue(v) => ControlFlow::Continue(v),
            ControlFlow::Break(v) => ControlFlow::Break(R::from_residual(v)),
        }
    }

    /// Convert a `ControlFlow` into any type implementing `Try`;
    #[inline]
    pub(crate) fn into_try(self) -> R {
        match self {
            ControlFlow::Continue(v) => R::from_output(v),
            ControlFlow::Break(v) => v,
        }
    }
}

impl<B> ControlFlow<B, ()> {
    /// It's frequently the case that there's no value needed with `Continue`,
    /// so this provides a way to avoid typing `(())`, if you prefer it.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(control_flow_enum)]
    /// use std::ops::ControlFlow;
    ///
    /// let mut partial_sum = 0;
    /// let last_used = (1..10).chain(20..25).try_for_each(|x| {
    ///     partial_sum += x;
    ///     if partial_sum > 100 { ControlFlow::Break(x) }
    ///     else { ControlFlow::CONTINUE }
    /// });
    /// assert_eq!(last_used.break_value(), Some(22));
    /// ```
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    pub const CONTINUE: Self = ControlFlow::Continue(());
}

impl<C> ControlFlow<(), C> {
    /// APIs like `try_for_each` don't need values with `Break`,
    /// so this provides a way to avoid typing `(())`, if you prefer it.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(control_flow_enum)]
    /// use std::ops::ControlFlow;
    ///
    /// let mut partial_sum = 0;
    /// (1..10).chain(20..25).try_for_each(|x| {
    ///     if partial_sum > 100 { ControlFlow::BREAK }
    ///     else { partial_sum += x; ControlFlow::CONTINUE }
    /// });
    /// assert_eq!(partial_sum, 108);
    /// ```
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    pub const BREAK: Self = ControlFlow::Break(());
}
<|endoftext|>


<commit_before>use crate::{convert, ops};

/// Used to tell an operation whether it should exit early or go on as usual.
///
/// This is used when exposing things (like graph traversals or visitors) where
/// you want the user to be able to choose whether to exit early.
/// Having the enum makes it clearer -- no more wondering "wait, what did `false`
/// mean again?" -- and allows including a value.
///
/// # Examples
///
/// Early-exiting from [`Iterator::try_for_each`]:
/// ```
/// use std::ops::ControlFlow;
///
/// let r = (2..100).try_for_each(|x| {
///     if 403 % x == 0 {
///         return ControlFlow::Break(x)
///     }
///
///     ControlFlow::Continue(())
/// });
/// assert_eq!(r, ControlFlow::Break(13));
/// ```
///
/// A basic tree traversal:
/// ```no_run
/// use std::ops::ControlFlow;
///
/// pub struct TreeNode<T> {
///     value: T,
///     left: Option<Box<TreeNode<T>>>,
///     right: Option<Box<TreeNode<T>>>,
/// }
///
/// impl<T> TreeNode<T> {
///     pub fn traverse_inorder<B>(&self, mut f: impl FnMut(&T) -> ControlFlow<B>) -> ControlFlow<B> {
///         if let Some(left) = &self.left {
///             left.traverse_inorder(&mut f)?;
///         }
///         f(&self.value)?;
///         if let Some(right) = &self.right {
///             right.traverse_inorder(&mut f)?;
///         }
///         ControlFlow::Continue(())
///     }
/// }
/// ```
#[stable(feature = "control_flow_enum_type", since = "1.55.0")]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ControlFlow<B, C = ()> {
    /// Move on to the next phase of the operation as normal.
    #[stable(feature = "control_flow_enum_type", since = "1.55.0")]
    #[lang = "Continue"]
    Continue(C),
    /// Exit the operation without running subsequent phases.
    #[stable(feature = "control_flow_enum_type", since = "1.55.0")]
    #[lang = "Break"]
    Break(B),
    // Yes, the order of the variants doesn't match the type parameters.
    // They're in this order so that `ControlFlow<A, B>` <-> `Result<B, A>`
    // is a no-op conversion in the `Try` implementation.
}

#[unstable(feature = "try_trait_v2", issue = "84277")]
impl<B, C> ops::Try for ControlFlow<B, C> {
    type Output = C;
    type Residual = ControlFlow<B, convert::Infallible>;

    #[inline]
    fn from_output(output: Self::Output) -> Self {
        ControlFlow::Continue(output)
    }

    #[inline]
    fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
        match self {
            ControlFlow::Continue(c) => ControlFlow::Continue(c),
            ControlFlow::Break(b) => ControlFlow::Break(ControlFlow::Break(b)),
        }
    }
}

#[unstable(feature = "try_trait_v2", issue = "84277")]
impl<B, C> ops::FromResidual for ControlFlow<B, C> {
    #[inline]
    fn from_residual(residual: ControlFlow<B, convert::Infallible>) -> Self {
        match residual {
            ControlFlow::Break(b) => ControlFlow::Break(b),
        }
    }
}

impl<B, C> ControlFlow<B, C> {
    /// Returns `true` if this is a `Break` variant.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(control_flow_enum)]
    /// use std::ops::ControlFlow;
    ///
    /// assert!(ControlFlow::<i32, String>::Break(3).is_break());
    /// assert!(!ControlFlow::<String, i32>::Continue(3).is_break());
    /// ```
    #[inline]
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    pub fn is_break(&self) -> bool {
        matches!(*self, ControlFlow::Break(_))
    }

    /// Returns `true` if this is a `Continue` variant.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(control_flow_enum)]
    /// use std::ops::ControlFlow;
    ///
    /// assert!(!ControlFlow::<i32, String>::Break(3).is_continue());
    /// assert!(ControlFlow::<String, i32>::Continue(3).is_continue());
    /// ```
    #[inline]
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    pub fn is_continue(&self) -> bool {
        matches!(*self, ControlFlow::Continue(_))
    }

    /// Converts the `ControlFlow` into an `Option` which is `Some` if the
    /// `ControlFlow` was `Break` and `None` otherwise.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(control_flow_enum)]
    /// use std::ops::ControlFlow;
    ///
    /// assert_eq!(ControlFlow::<i32, String>::Break(3).break_value(), Some(3));
    /// assert_eq!(ControlFlow::<String, i32>::Continue(3).break_value(), None);
    /// ```
    #[inline]
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    pub fn break_value(self) -> Option<B> {
        match self {
            ControlFlow::Continue(..) => None,
            ControlFlow::Break(x) => Some(x),
        }
    }

    /// Maps `ControlFlow<B, C>` to `ControlFlow<T, C>` by applying a function
    /// to the break value in case it exists.
    #[inline]
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    pub fn map_break<T, F>(self, f: F) -> ControlFlow<T, C>
    where
        F: FnOnce(B) -> T,
    {
        match self {
            ControlFlow::Continue(x) => ControlFlow::Continue(x),
            ControlFlow::Break(x) => ControlFlow::Break(f(x)),
        }
    }
}

/// These are used only as part of implementing the iterator adapters.
/// They have mediocre names and non-obvious semantics, so aren't
/// currently on a path to potential stabilization.
impl<R: ops::Try> ControlFlow<R, R::Output> {
    /// Create a `ControlFlow` from any type implementing `Try`.
    #[inline]
    pub(crate) fn from_try(r: R) -> Self {
        match R::branch(r) {
            ControlFlow::Continue(v) => ControlFlow::Continue(v),
            ControlFlow::Break(v) => ControlFlow::Break(R::from_residual(v)),
        }
    }

    /// Convert a `ControlFlow` into any type implementing `Try`;
    #[inline]
    pub(crate) fn into_try(self) -> R {
        match self {
            ControlFlow::Continue(v) => R::from_output(v),
            ControlFlow::Break(v) => v,
        }
    }
}

impl<B> ControlFlow<B, ()> {
    /// It's frequently the case that there's no value needed with `Continue`,
    /// so this provides a way to avoid typing `(())`, if you prefer it.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(control_flow_enum)]
    /// use std::ops::ControlFlow;
    ///
    /// let mut partial_sum = 0;
    /// let last_used = (1..10).chain(20..25).try_for_each(|x| {
    ///     partial_sum += x;
    ///     if partial_sum > 100 { ControlFlow::Break(x) }
    ///     else { ControlFlow::CONTINUE }
    /// });
    /// assert_eq!(last_used.break_value(), Some(22));
    /// ```
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    pub const CONTINUE: Self = ControlFlow::Continue(());
}

impl<C> ControlFlow<(), C> {
    /// APIs like `try_for_each` don't need values with `Break`,
    /// so this provides a way to avoid typing `(())`, if you prefer it.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(control_flow_enum)]
    /// use std::ops::ControlFlow;
    ///
    /// let mut partial_sum = 0;
    /// (1..10).chain(20..25).try_for_each(|x| {
    ///     if partial_sum > 100 { ControlFlow::BREAK }
    ///     else { partial_sum += x; ControlFlow::CONTINUE }
    /// });
    /// assert_eq!(partial_sum, 108);
    /// ```
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    pub const BREAK: Self = ControlFlow::Break(());
}
<commit_msg>Rollup merge of #90196 - yanok:master, r=scottmcm<commit_after>use crate::{convert, ops};

/// Used to tell an operation whether it should exit early or go on as usual.
///
/// This is used when exposing things (like graph traversals or visitors) where
/// you want the user to be able to choose whether to exit early.
/// Having the enum makes it clearer -- no more wondering "wait, what did `false`
/// mean again?" -- and allows including a value.
///
/// # Examples
///
/// Early-exiting from [`Iterator::try_for_each`]:
/// ```
/// use std::ops::ControlFlow;
///
/// let r = (2..100).try_for_each(|x| {
///     if 403 % x == 0 {
///         return ControlFlow::Break(x)
///     }
///
///     ControlFlow::Continue(())
/// });
/// assert_eq!(r, ControlFlow::Break(13));
/// ```
///
/// A basic tree traversal:
/// ```
/// use std::ops::ControlFlow;
///
/// pub struct TreeNode<T> {
///     value: T,
///     left: Option<Box<TreeNode<T>>>,
///     right: Option<Box<TreeNode<T>>>,
/// }
///
/// impl<T> TreeNode<T> {
///     pub fn traverse_inorder<B>(&self, f: &mut impl FnMut(&T) -> ControlFlow<B>) -> ControlFlow<B> {
///         if let Some(left) = &self.left {
///             left.traverse_inorder(f)?;
///         }
///         f(&self.value)?;
///         if let Some(right) = &self.right {
///             right.traverse_inorder(f)?;
///         }
///         ControlFlow::Continue(())
///     }
///     fn leaf(value: T) -> Option<Box<TreeNode<T>>> {
///         Some(Box::new(Self { value, left: None, right: None }))
///     }
/// }
///
/// let node = TreeNode {
///     value: 0,
///     left: TreeNode::leaf(1),
///     right: Some(Box::new(TreeNode {
///         value: -1,
///         left: TreeNode::leaf(5),
///         right: TreeNode::leaf(2),
///     }))
/// };
/// let mut sum = 0;
///
/// let res = node.traverse_inorder(&mut |val| {
///     if *val < 0 {
///         ControlFlow::Break(*val)
///     } else {
///         sum += *val;
///         ControlFlow::Continue(())
///     }
/// });
/// assert_eq!(res, ControlFlow::Break(-1));
/// assert_eq!(sum, 6);
/// ```
#[stable(feature = "control_flow_enum_type", since = "1.55.0")]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ControlFlow<B, C = ()> {
    /// Move on to the next phase of the operation as normal.
    #[stable(feature = "control_flow_enum_type", since = "1.55.0")]
    #[lang = "Continue"]
    Continue(C),
    /// Exit the operation without running subsequent phases.
    #[stable(feature = "control_flow_enum_type", since = "1.55.0")]
    #[lang = "Break"]
    Break(B),
    // Yes, the order of the variants doesn't match the type parameters.
    // They're in this order so that `ControlFlow<A, B>` <-> `Result<B, A>`
    // is a no-op conversion in the `Try` implementation.
}

#[unstable(feature = "try_trait_v2", issue = "84277")]
impl<B, C> ops::Try for ControlFlow<B, C> {
    type Output = C;
    type Residual = ControlFlow<B, convert::Infallible>;

    #[inline]
    fn from_output(output: Self::Output) -> Self {
        ControlFlow::Continue(output)
    }

    #[inline]
    fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
        match self {
            ControlFlow::Continue(c) => ControlFlow::Continue(c),
            ControlFlow::Break(b) => ControlFlow::Break(ControlFlow::Break(b)),
        }
    }
}

#[unstable(feature = "try_trait_v2", issue = "84277")]
impl<B, C> ops::FromResidual for ControlFlow<B, C> {
    #[inline]
    fn from_residual(residual: ControlFlow<B, convert::Infallible>) -> Self {
        match residual {
            ControlFlow::Break(b) => ControlFlow::Break(b),
        }
    }
}

impl<B, C> ControlFlow<B, C> {
    /// Returns `true` if this is a `Break` variant.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(control_flow_enum)]
    /// use std::ops::ControlFlow;
    ///
    /// assert!(ControlFlow::<i32, String>::Break(3).is_break());
    /// assert!(!ControlFlow::<String, i32>::Continue(3).is_break());
    /// ```
    #[inline]
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    pub fn is_break(&self) -> bool {
        matches!(*self, ControlFlow::Break(_))
    }

    /// Returns `true` if this is a `Continue` variant.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(control_flow_enum)]
    /// use std::ops::ControlFlow;
    ///
    /// assert!(!ControlFlow::<i32, String>::Break(3).is_continue());
    /// assert!(ControlFlow::<String, i32>::Continue(3).is_continue());
    /// ```
    #[inline]
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    pub fn is_continue(&self) -> bool {
        matches!(*self, ControlFlow::Continue(_))
    }

    /// Converts the `ControlFlow` into an `Option` which is `Some` if the
    /// `ControlFlow` was `Break` and `None` otherwise.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(control_flow_enum)]
    /// use std::ops::ControlFlow;
    ///
    /// assert_eq!(ControlFlow::<i32, String>::Break(3).break_value(), Some(3));
    /// assert_eq!(ControlFlow::<String, i32>::Continue(3).break_value(), None);
    /// ```
    #[inline]
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    pub fn break_value(self) -> Option<B> {
        match self {
            ControlFlow::Continue(..) => None,
            ControlFlow::Break(x) => Some(x),
        }
    }

    /// Maps `ControlFlow<B, C>` to `ControlFlow<T, C>` by applying a function
    /// to the break value in case it exists.
    #[inline]
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    pub fn map_break<T, F>(self, f: F) -> ControlFlow<T, C>
    where
        F: FnOnce(B) -> T,
    {
        match self {
            ControlFlow::Continue(x) => ControlFlow::Continue(x),
            ControlFlow::Break(x) => ControlFlow::Break(f(x)),
        }
    }
}

/// These are used only as part of implementing the iterator adapters.
/// They have mediocre names and non-obvious semantics, so aren't
/// currently on a path to potential stabilization.
impl<R: ops::Try> ControlFlow<R, R::Output> {
    /// Create a `ControlFlow` from any type implementing `Try`.
    #[inline]
    pub(crate) fn from_try(r: R) -> Self {
        match R::branch(r) {
            ControlFlow::Continue(v) => ControlFlow::Continue(v),
            ControlFlow::Break(v) => ControlFlow::Break(R::from_residual(v)),
        }
    }

    /// Convert a `ControlFlow` into any type implementing `Try`;
    #[inline]
    pub(crate) fn into_try(self) -> R {
        match self {
            ControlFlow::Continue(v) => R::from_output(v),
            ControlFlow::Break(v) => v,
        }
    }
}

impl<B> ControlFlow<B, ()> {
    /// It's frequently the case that there's no value needed with `Continue`,
    /// so this provides a way to avoid typing `(())`, if you prefer it.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(control_flow_enum)]
    /// use std::ops::ControlFlow;
    ///
    /// let mut partial_sum = 0;
    /// let last_used = (1..10).chain(20..25).try_for_each(|x| {
    ///     partial_sum += x;
    ///     if partial_sum > 100 { ControlFlow::Break(x) }
    ///     else { ControlFlow::CONTINUE }
    /// });
    /// assert_eq!(last_used.break_value(), Some(22));
    /// ```
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    pub const CONTINUE: Self = ControlFlow::Continue(());
}

impl<C> ControlFlow<(), C> {
    /// APIs like `try_for_each` don't need values with `Break`,
    /// so this provides a way to avoid typing `(())`, if you prefer it.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(control_flow_enum)]
    /// use std::ops::ControlFlow;
    ///
    /// let mut partial_sum = 0;
    /// (1..10).chain(20..25).try_for_each(|x| {
    ///     if partial_sum > 100 { ControlFlow::BREAK }
    ///     else { partial_sum += x; ControlFlow::CONTINUE }
    /// });
    /// assert_eq!(partial_sum, 108);
    /// ```
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    pub const BREAK: Self = ControlFlow::Break(());
}
<|endoftext|>


<commit_before>use std::time::SystemTime;

use aws_sigv4::{
    http_request::{self, SignableRequest, SigningSettings},
    SigningParams,
};
use reqwest::blocking::Client;

#[derive(Clone)]
pub struct CloudFront {
    distribution_id: String,
    access_key: String,
    secret_key: String,
}

impl CloudFront {
    pub fn from_environment() -> Option<Self> {
        let distribution_id = dotenv::var("CLOUDFRONT_DISTRIBUTION").ok()?;
        let access_key = dotenv::var("AWS_ACCESS_KEY").expect("missing AWS_ACCESS_KEY");
        let secret_key = dotenv::var("AWS_SECRET_KEY").expect("missing AWS_SECRET_KEY");
        Some(Self {
            distribution_id,
            access_key,
            secret_key,
        })
    }

    /// Invalidate a file on CloudFront
    ///
    /// `path` is the path to the file to invalidate, such as `config.json`, or `re/ge/regex`
    pub fn invalidate(&self, client: &Client, path: &str) -> anyhow::Result<()> {
        let path = path.trim_start_matches('/');
        let url = format!(
            "https://cloudfront.amazonaws.com/2020-05-31/distribution/{}/invalidation",
            self.distribution_id
        );
        let now = chrono::offset::Utc::now().timestamp_micros();
        let body = format!(
            r#"
<?xml version="1.0" encoding="UTF-8"?>
<InvalidationBatch xmlns="http://cloudfront.amazonaws.com/doc/2020-05-31/">
    <CallerReference>{now}</CallerReference>
    <Paths>
        <Items>
            <Path>/{path}</Path>
        </Items>
        <Quantity>1</Quantity>
    </Paths>
</InvalidationBatch>
"#
        );

        let request = http::Request::post(&url).body(&body)?;
        let request = SignableRequest::from(&request);
        let params = SigningParams::builder()
            .access_key(&self.access_key)
            .secret_key(&self.secret_key)
            .region("us-east-1") // cloudfront is a regionless service, use the default region for signing.
            .service_name("cloudfront")
            .settings(SigningSettings::default())
            .time(SystemTime::now())
            .build()
            .unwrap(); // all required fields are set
        let (mut signature_headers, _) = http_request::sign(request, &params).unwrap().into_parts();
        client
            .post(url)
            .headers(signature_headers.take_headers().unwrap_or_default())
            .body(body)
            .send()?
            .error_for_status()?;
        Ok(())
    }
}
<commit_msg>Add additional HTTP logging for cloudfront invalidation failures (#5447)<commit_after>use std::time::SystemTime;

use anyhow::Context;
use aws_sigv4::{
    http_request::{self, SignableRequest, SigningSettings},
    SigningParams,
};
use reqwest::blocking::Client;

#[derive(Clone)]
pub struct CloudFront {
    distribution_id: String,
    access_key: String,
    secret_key: String,
}

impl CloudFront {
    pub fn from_environment() -> Option<Self> {
        let distribution_id = dotenv::var("CLOUDFRONT_DISTRIBUTION").ok()?;
        let access_key = dotenv::var("AWS_ACCESS_KEY").expect("missing AWS_ACCESS_KEY");
        let secret_key = dotenv::var("AWS_SECRET_KEY").expect("missing AWS_SECRET_KEY");
        Some(Self {
            distribution_id,
            access_key,
            secret_key,
        })
    }

    /// Invalidate a file on CloudFront
    ///
    /// `path` is the path to the file to invalidate, such as `config.json`, or `re/ge/regex`
    pub fn invalidate(&self, client: &Client, path: &str) -> anyhow::Result<()> {
        let path = path.trim_start_matches('/');
        let url = format!(
            "https://cloudfront.amazonaws.com/2020-05-31/distribution/{}/invalidation",
            self.distribution_id
        );
        let now = chrono::offset::Utc::now().timestamp_micros();
        let body = format!(
            r#"
<?xml version="1.0" encoding="UTF-8"?>
<InvalidationBatch xmlns="http://cloudfront.amazonaws.com/doc/2020-05-31/">
    <CallerReference>{now}</CallerReference>
    <Paths>
        <Items>
            <Path>/{path}</Path>
        </Items>
        <Quantity>1</Quantity>
    </Paths>
</InvalidationBatch>
"#
        );

        let request = http::Request::post(&url).body(&body)?;
        let request = SignableRequest::from(&request);
        let params = SigningParams::builder()
            .access_key(&self.access_key)
            .secret_key(&self.secret_key)
            .region("us-east-1") // cloudfront is a regionless service, use the default region for signing.
            .service_name("cloudfront")
            .settings(SigningSettings::default())
            .time(SystemTime::now())
            .build()
            .unwrap(); // all required fields are set
        let (mut signature_headers, _) = http_request::sign(request, &params).unwrap().into_parts();
        let response = client
            .post(url)
            .headers(signature_headers.take_headers().unwrap_or_default())
            .body(body)
            .send()?;
        if let Some(err) = response.error_for_status_ref().err() {
            let headers = format!("{:?}", response.headers());
            let body = response.text()?;
            return Err(err).context(format!("{headers}; body: {body}"));
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>// $ cargo bench --features full --bench rust

#![recursion_limit = "256"]
#![feature(rustc_private)]

extern crate rustc_data_structures;
extern crate syntax;
extern crate syntax_pos;

#[macro_use]
#[path = "../tests/macros/mod.rs"]
mod macros;

#[path = "../tests/common/mod.rs"]
mod common;

use proc_macro2::TokenStream;
use rustc_data_structures::sync::Lrc;
use std::fs;
use std::str::FromStr;
use std::time::{Duration, Instant};
use syntax::edition::Edition;
use syntax::errors::{emitter::Emitter, DiagnosticBuilder, Handler};
use syntax::parse::ParseSess;
use syntax::source_map::{FilePathMapping, SourceMap};
use syntax_pos::FileName;

fn tokenstream_parse(content: &str) -> Result<(), ()> {
    TokenStream::from_str(content).map(drop).map_err(drop)
}

fn syn_parse(content: &str) -> Result<(), ()> {
    syn::parse_file(content).map(drop).map_err(drop)
}

fn libsyntax_parse(content: &str) -> Result<(), ()> {
    struct SilentEmitter;

    impl Emitter for SilentEmitter {
        fn emit_diagnostic(&mut self, _db: &DiagnosticBuilder) {}
    }

    syntax::with_globals(Edition::Edition2018, || {
        let cm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
        let emitter = Box::new(SilentEmitter);
        let handler = Handler::with_emitter(false, None, emitter);
        let sess = ParseSess::with_span_handler(handler, cm);
        if let Err(mut diagnostic) = syntax::parse::parse_crate_from_source_str(
            FileName::Custom("bench".to_owned()),
            content.to_owned(),
            &sess,
        ) {
            diagnostic.cancel();
            return Err(());
        };
        Ok(())
    })
}

fn read_from_disk(content: &str) -> Result<(), ()> {
    let _ = content;
    Ok(())
}

fn exec(mut codepath: impl FnMut(&str) -> Result<(), ()>) -> Duration {
    let begin = Instant::now();
    let mut success = 0;
    let mut total = 0;

    walkdir::WalkDir::new("tests/rust/src")
        .into_iter()
        .filter_entry(common::base_dir_filter)
        .for_each(|entry| {
            let entry = entry.unwrap();
            let path = entry.path();
            if path.is_dir() {
                return;
            }
            let content = fs::read_to_string(path).unwrap();
            let ok = codepath(&content).is_ok();
            success += ok as usize;
            total += 1;
            if !ok {
                eprintln!("FAIL {}", path.display());
            }
        });

    assert_eq!(success, total);
    begin.elapsed()
}

fn main() {
    common::clone_rust();

    macro_rules! testcases {
        ($($name:ident,)*) => {
            vec![
                $(
                    (stringify!($name), $name as fn(&str) -> Result<(), ()>),
                )*
            ]
        };
    }

    let mut lines = 0;
    exec(|content| {
        lines += content.lines().count();
        Ok(())
    });
    eprintln!("\n{} lines", lines);

    for (name, f) in testcases!(
        read_from_disk,
        tokenstream_parse,
        syn_parse,
        libsyntax_parse,
    ) {
        eprint!("{:20}", format!("{}:", name));
        let elapsed = exec(f);
        eprintln!(
            "elapsed={}.{:03}s",
            elapsed.as_secs(),
            elapsed.subsec_millis(),
        );
    }
    eprintln!();
}
<commit_msg>Print benchmark file count<commit_after>// $ cargo bench --features full --bench rust

#![recursion_limit = "256"]
#![feature(rustc_private)]

extern crate rustc_data_structures;
extern crate syntax;
extern crate syntax_pos;

#[macro_use]
#[path = "../tests/macros/mod.rs"]
mod macros;

#[path = "../tests/common/mod.rs"]
mod common;

use proc_macro2::TokenStream;
use rustc_data_structures::sync::Lrc;
use std::fs;
use std::str::FromStr;
use std::time::{Duration, Instant};
use syntax::edition::Edition;
use syntax::errors::{emitter::Emitter, DiagnosticBuilder, Handler};
use syntax::parse::ParseSess;
use syntax::source_map::{FilePathMapping, SourceMap};
use syntax_pos::FileName;

fn tokenstream_parse(content: &str) -> Result<(), ()> {
    TokenStream::from_str(content).map(drop).map_err(drop)
}

fn syn_parse(content: &str) -> Result<(), ()> {
    syn::parse_file(content).map(drop).map_err(drop)
}

fn libsyntax_parse(content: &str) -> Result<(), ()> {
    struct SilentEmitter;

    impl Emitter for SilentEmitter {
        fn emit_diagnostic(&mut self, _db: &DiagnosticBuilder) {}
    }

    syntax::with_globals(Edition::Edition2018, || {
        let cm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
        let emitter = Box::new(SilentEmitter);
        let handler = Handler::with_emitter(false, None, emitter);
        let sess = ParseSess::with_span_handler(handler, cm);
        if let Err(mut diagnostic) = syntax::parse::parse_crate_from_source_str(
            FileName::Custom("bench".to_owned()),
            content.to_owned(),
            &sess,
        ) {
            diagnostic.cancel();
            return Err(());
        };
        Ok(())
    })
}

fn read_from_disk(content: &str) -> Result<(), ()> {
    let _ = content;
    Ok(())
}

fn exec(mut codepath: impl FnMut(&str) -> Result<(), ()>) -> Duration {
    let begin = Instant::now();
    let mut success = 0;
    let mut total = 0;

    walkdir::WalkDir::new("tests/rust/src")
        .into_iter()
        .filter_entry(common::base_dir_filter)
        .for_each(|entry| {
            let entry = entry.unwrap();
            let path = entry.path();
            if path.is_dir() {
                return;
            }
            let content = fs::read_to_string(path).unwrap();
            let ok = codepath(&content).is_ok();
            success += ok as usize;
            total += 1;
            if !ok {
                eprintln!("FAIL {}", path.display());
            }
        });

    assert_eq!(success, total);
    begin.elapsed()
}

fn main() {
    common::clone_rust();

    macro_rules! testcases {
        ($($name:ident,)*) => {
            vec![
                $(
                    (stringify!($name), $name as fn(&str) -> Result<(), ()>),
                )*
            ]
        };
    }

    let mut lines = 0;
    let mut files = 0;
    exec(|content| {
        lines += content.lines().count();
        files += 1;
        Ok(())
    });
    eprintln!("\n{} lines in {} files", lines, files);

    for (name, f) in testcases!(
        read_from_disk,
        tokenstream_parse,
        syn_parse,
        libsyntax_parse,
    ) {
        eprint!("{:20}", format!("{}:", name));
        let elapsed = exec(f);
        eprintln!(
            "elapsed={}.{:03}s",
            elapsed.as_secs(),
            elapsed.subsec_millis(),
        );
    }
    eprintln!();
}
<|endoftext|>