<commit_before><commit_msg>storage: Add ttl snapshot and iterator (#9758)<commit_after>// Copyright 2021 TiKV Project Authors. Licensed under Apache-2.0.

use crate::storage::kv::{Iterator, Result, Snapshot};
use crate::storage::Statistics;

use engine_traits::util::{get_expire_ts, strip_expire_ts, truncate_expire_ts};
use engine_traits::CfName;
use engine_traits::{IterOptions, ReadOptions};
#[cfg(not(test))]
use tikv_util::time::UnixSecs;
use txn_types::{Key, Value};

#[cfg(test)]
pub const TEST_CURRENT_TS: u64 = 15;

#[derive(Clone)]
pub struct TTLSnapshot<S: Snapshot> {
    s: S,
    current_ts: u64,
}

impl<S: Snapshot> TTLSnapshot<S> {
    fn map_value(&self, value_with_ttl: Result<Option<Value>>) -> Result<Option<Value>> {
        match value_with_ttl? {
            Some(mut v) => {
                let expire_ts = get_expire_ts(&v)?;
                if expire_ts != 0 && expire_ts <= self.current_ts {
                    return Ok(None);
                }
                truncate_expire_ts(&mut v).unwrap();
                Ok(Some(v))
            },
            None => Ok(None)
        }
    }

    #[cfg(not(test))]
    #[inline]
    pub fn current_ts() -> u64 {
        UnixSecs::now().into_inner()
    }

    #[cfg(test)]
    #[inline]
    pub fn current_ts() -> u64 {
        TEST_CURRENT_TS
    }

    pub fn get_key_ttl_cf(
        &self,
        cf: CfName,
        key: &Key,
        stats: &mut Statistics,
    ) -> Result<Option<u64>> {
        let value_with_ttl = self.s.get_cf(cf, key)?;

        stats.data.flow_stats.read_keys = 1;
        stats.data.flow_stats.read_bytes = key.as_encoded().len();
        if let Some(v) = value_with_ttl {
            stats.data.flow_stats.read_bytes += v.len();
            let expire_ts = get_expire_ts(&v)?;
            if expire_ts == 0 {
                return Ok(Some(0));
            }
            return if expire_ts <= self.current_ts {
                Ok(None)
            } else {
                Ok(Some(expire_ts - self.current_ts))
            };
        }
        Ok(None)
    }
}

impl<S: Snapshot> From<S> for TTLSnapshot<S> {
    fn from(s: S) -> Self {
        TTLSnapshot {
            s,
            current_ts: Self::current_ts(),
        }
    }
}

impl<S: Snapshot> Snapshot for TTLSnapshot<S> {
    type Iter = TTLIterator<S::Iter>;

    fn get(&self, key: &Key) -> Result<Option<Value>> {
        self.map_value(self.s.get(key))
    }

    fn get_cf(&self, cf: CfName, key: &Key) -> Result<Option<Value>> {
        self.map_value(self.s.get_cf(cf, key))
    }

    fn get_cf_opt(&self, opts: ReadOptions, cf: CfName, key: &Key) -> Result<Option<Value>> {
        self.map_value(self.s.get_cf_opt(opts, cf, key))
    }

    fn iter(&self, iter_opt: IterOptions) -> Result<Self::Iter> {
        Ok(TTLIterator::new(self.s.iter(iter_opt)?, self.current_ts))
    }

    fn iter_cf(&self, cf: CfName, iter_opt: IterOptions) -> Result<Self::Iter> {
        Ok(TTLIterator::new(
            self.s.iter_cf(cf, iter_opt)?,
            self.current_ts,
        ))
    }

    #[inline]
    fn lower_bound(&self) -> Option<&[u8]> {
        self.s.lower_bound()
    }

    #[inline]
    fn upper_bound(&self) -> Option<&[u8]> {
        self.s.upper_bound()
    }

    #[inline]
    fn get_data_version(&self) -> Option<u64> {
        self.s.get_data_version()
    }

    fn is_max_ts_synced(&self) -> bool {
        self.s.is_max_ts_synced()
    }
}

pub struct TTLIterator<I: Iterator> {
    i: I,
    current_ts: u64,
}

impl<I: Iterator> TTLIterator<I> {
    fn new(i: I, current_ts: u64) -> Self {
        TTLIterator { i, current_ts }
    }

    fn find_valid_value(&mut self, mut res: Result<bool>, forward: bool) -> Result<bool> {
        loop {
            if res.is_err() {
                break;
            }

            if *res.as_ref().unwrap() {
                let expire_ts = get_expire_ts(self.i.value())?;
                if expire_ts != 0 && expire_ts <= self.current_ts {
                    res = if forward {
                        self.i.next()
                    } else {
                        self.i.prev()
                    };
                    continue;
                }
            }
            break;
        }
        res
    }
}

impl<I: Iterator> Iterator for TTLIterator<I> {
    fn next(&mut self) -> Result<bool> {
        let res = self.i.next();
        self.find_valid_value(res, true)
    }

    fn prev(&mut self) -> Result<bool> {
        let res = self.i.prev();
        self.find_valid_value(res, false)
    }

    fn seek(&mut self, key: &Key) -> Result<bool> {
        let res = self.i.seek(key);
        self.find_valid_value(res, true)
    }

    fn seek_for_prev(&mut self, key: &Key) -> Result<bool> {
        let res = self.i.seek_for_prev(key);
        self.find_valid_value(res, false)
    }

    fn seek_to_first(&mut self) -> Result<bool> {
        let res = self.i.seek_to_first();
        self.find_valid_value(res, true)
    }

    fn seek_to_last(&mut self) -> Result<bool> {
        let res = self.i.seek_to_last();
        self.find_valid_value(res, false)
    }

    fn valid(&self) -> Result<bool> {
        self.i.valid()
    }

    fn validate_key(&self, key: &Key) -> Result<()> {
        self.i.validate_key(key)
    }

    fn key(&self) -> &[u8] {
        self.i.key()
    }

    fn value(&self) -> &[u8] {
        strip_expire_ts(self.i.value())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::storage::kv::Engine;
    use crate::storage::{SnapContext, TestEngineBuilder};

    use engine_traits::util::append_expire_ts;
    use engine_traits::{SyncMutable, CF_DEFAULT};

    #[test]
    fn test_ttl_snapshot() {
        let dir = tempfile::TempDir::new().unwrap();
        let engine = TestEngineBuilder::new()
            .path(dir.path())
            .ttl(true)
            .build()
            .unwrap();
        let kvdb = engine.get_rocksdb();

        let key1 = b"key1";
        let mut value1 = b"value1".to_vec();
        append_expire_ts(&mut value1, 10);
        kvdb.put_cf(CF_DEFAULT, key1, &value1).unwrap();
        let mut value10 = b"value1".to_vec();
        append_expire_ts(&mut value10, 20);
        kvdb.put_cf(CF_DEFAULT, key1, &value10).unwrap();

        let key2 = b"key2";
        let mut value2 = b"value2".to_vec();
        append_expire_ts(&mut value2, 20);
        kvdb.put_cf(CF_DEFAULT, key2, &value2).unwrap();
        let mut value20 = b"value2".to_vec();
        append_expire_ts(&mut value20, 10);
        kvdb.put_cf(CF_DEFAULT, key2, &value20).unwrap();

        let key3 = b"key3";
        let mut value3 = b"value3".to_vec();
        append_expire_ts(&mut value3, 0);
        kvdb.put_cf(CF_DEFAULT, key3, &value3).unwrap();

        let snapshot = engine.snapshot(SnapContext::default()).unwrap();
        let ttl_snapshot = TTLSnapshot::from(snapshot);
        assert_eq!(
            ttl_snapshot.get(&Key::from_encoded_slice(b"key1")).unwrap(),
            Some(b"value1".to_vec())
        );
        assert_eq!(
            ttl_snapshot.get(&Key::from_encoded_slice(b"key2")).unwrap(),
            None
        );
        assert_eq!(
            ttl_snapshot.get(&Key::from_encoded_slice(b"key3")).unwrap(),
            Some(b"value3".to_vec())
        );
        let mut stats = Statistics::default();
        assert_eq!(
            ttl_snapshot
                .get_key_ttl_cf(CF_DEFAULT, &Key::from_encoded_slice(b"key1"), &mut stats)
                .unwrap(),
            Some(5)
        );
        assert_eq!(
            ttl_snapshot
                .get_key_ttl_cf(CF_DEFAULT, &Key::from_encoded_slice(b"key2"), &mut stats)
                .unwrap(),
            None
        );
        assert_eq!(
            ttl_snapshot
                .get_key_ttl_cf(CF_DEFAULT, &Key::from_encoded_slice(b"key3"), &mut stats)
                .unwrap(),
            Some(0)
        );
    }

    #[test]
    fn test_ttl_iterator() {
        let dir = tempfile::TempDir::new().unwrap();
        let engine = TestEngineBuilder::new()
            .path(dir.path())
            .ttl(true)
            .build()
            .unwrap();
        let kvdb = engine.get_rocksdb();

        let key1 = b"key1";
        let mut value1 = b"value1".to_vec();
        append_expire_ts(&mut value1, 10);
        kvdb.put_cf(CF_DEFAULT, key1, &value1).unwrap();
        let mut value10 = b"value1".to_vec();
        append_expire_ts(&mut value10, 20);
        kvdb.put_cf(CF_DEFAULT, key1, &value10).unwrap();

        let key2 = b"key2";
        let mut value2 = b"value2".to_vec();
        append_expire_ts(&mut value2, 20);
        kvdb.put_cf(CF_DEFAULT, key2, &value2).unwrap();
        let mut value20 = b"value2".to_vec();
        append_expire_ts(&mut value20, 10);
        kvdb.put_cf(CF_DEFAULT, key2, &value20).unwrap();

        let key3 = b"key3";
        let mut value3 = b"value3".to_vec();
        append_expire_ts(&mut value3, 0);
        kvdb.put_cf(CF_DEFAULT, key3, &value3).unwrap();

        let key4 = b"key4";
        let mut value4 = b"value4".to_vec();
        append_expire_ts(&mut value4, 10);
        kvdb.put_cf(CF_DEFAULT, key4, &value4).unwrap();

        let key5 = b"key5";
        let mut value5 = b"value5".to_vec();
        append_expire_ts(&mut value5, 0);
        kvdb.put_cf(CF_DEFAULT, key5, &value5).unwrap();
        let mut value50 = b"value5".to_vec();
        append_expire_ts(&mut value50, 10);
        kvdb.put_cf(CF_DEFAULT, key5, &value50).unwrap();

        let snapshot = engine.snapshot(SnapContext::default()).unwrap();
        let ttl_snapshot = TTLSnapshot::from(snapshot);
        let mut iter = ttl_snapshot
            .iter(IterOptions::new(None, None, false))
            .unwrap();
        iter.seek_to_first().unwrap();
        assert_eq!(iter.key(), b"key1");
        assert_eq!(iter.value(), b"value1");
        assert_eq!(iter.next().unwrap(), true);
        assert_eq!(iter.key(), b"key3");
        assert_eq!(iter.value(), b"value3");
        assert_eq!(iter.next().unwrap(), false);

        iter.seek_to_last().unwrap();
        assert_eq!(iter.key(), b"key3");
        assert_eq!(iter.value(), b"value3");
        assert_eq!(iter.prev().unwrap(), true);
        assert_eq!(iter.key(), b"key1");
        assert_eq!(iter.value(), b"value1");
        assert_eq!(iter.prev().unwrap(), false);

        iter.seek(&Key::from_encoded_slice(b"key2")).unwrap();
        assert_eq!(iter.valid().unwrap(), true);
        assert_eq!(iter.key(), b"key3");
        assert_eq!(iter.value(), b"value3");
        iter.seek(&Key::from_encoded_slice(b"key4")).unwrap();
        assert_eq!(iter.valid().unwrap(), false);

        iter.seek_for_prev(&Key::from_encoded_slice(b"key2"))
            .unwrap();
        assert_eq!(iter.valid().unwrap(), true);
        assert_eq!(iter.key(), b"key1");
        assert_eq!(iter.value(), b"value1");
        iter.seek_for_prev(&Key::from_encoded_slice(b"key1"))
            .unwrap();
        assert_eq!(iter.valid().unwrap(), true);
        assert_eq!(iter.key(), b"key1");
        assert_eq!(iter.value(), b"value1");
    }
}
<|endoftext|>


<commit_before><commit_msg>Add Wiki::delete_entry()<commit_after><|endoftext|>


<commit_before><commit_msg>added special random unsigned vector generator<commit_after><|endoftext|>


<commit_before><commit_msg>Var name<commit_after><|endoftext|>


<commit_before><commit_msg>Rename formatter impl<commit_after><|endoftext|>


<commit_before><commit_msg>Changed Option<T> to Rc<T> for entities<commit_after><|endoftext|>


<commit_before>//! A type representing either success or failure

import cmp::Eq;
import either::Either;

/// The result type
enum Result<T, U> {
    /// Contains the successful result value
    Ok(T),
    /// Contains the error value
    Err(U)
}

/**
 * Get the value out of a successful result
 *
 * # Failure
 *
 * If the result is an error
 */
pure fn get<T: copy, U>(res: Result<T, U>) -> T {
    match res {
      Ok(t) => t,
      Err(the_err) => unchecked {
        fail fmt!("get called on error result: %?", the_err)
      }
    }
}

/**
 * Get a reference to the value out of a successful result
 *
 * # Failure
 *
 * If the result is an error
 */
pure fn get_ref<T, U>(res: &a/Result<T, U>) -> &a/T {
    match *res {
        Ok(ref t) => t,
        Err(ref the_err) => unchecked {
            fail fmt!("get_ref called on error result: %?", the_err)
        }
    }
}

/**
 * Get the value out of an error result
 *
 * # Failure
 *
 * If the result is not an error
 */
pure fn get_err<T, U: copy>(res: Result<T, U>) -> U {
    match res {
      Err(u) => u,
      Ok(_) => fail ~"get_err called on ok result"
    }
}

/// Returns true if the result is `ok`
pure fn is_ok<T, U>(res: Result<T, U>) -> bool {
    match res {
      Ok(_) => true,
      Err(_) => false
    }
}

/// Returns true if the result is `err`
pure fn is_err<T, U>(res: Result<T, U>) -> bool {
    !is_ok(res)
}

/**
 * Convert to the `either` type
 *
 * `ok` result variants are converted to `either::right` variants, `err`
 * result variants are converted to `either::left`.
 */
pure fn to_either<T: copy, U: copy>(res: Result<U, T>) -> Either<T, U> {
    match res {
      Ok(res) => either::Right(res),
      Err(fail_) => either::Left(fail_)
    }
}

/**
 * Call a function based on a previous result
 *
 * If `res` is `ok` then the value is extracted and passed to `op` whereupon
 * `op`s result is returned. if `res` is `err` then it is immediately
 * returned. This function can be used to compose the results of two
 * functions.
 *
 * Example:
 *
 *     let res = chain(read_file(file)) { |buf|
 *         ok(parse_buf(buf))
 *     }
 */
fn chain<T, U: copy, V: copy>(res: Result<T, V>, op: fn(T) -> Result<U, V>)
    -> Result<U, V> {
    match res {
      Ok(t) => op(t),
      Err(e) => Err(e)
    }
}

/**
 * Call a function based on a previous result
 *
 * If `res` is `err` then the value is extracted and passed to `op`
 * whereupon `op`s result is returned. if `res` is `ok` then it is
 * immediately returned.  This function can be used to pass through a
 * successful result while handling an error.
 */
fn chain_err<T: copy, U: copy, V: copy>(
    res: Result<T, V>,
    op: fn(V) -> Result<T, U>)
    -> Result<T, U> {
    match res {
      Ok(t) => Ok(t),
      Err(v) => op(v)
    }
}

/**
 * Call a function based on a previous result
 *
 * If `res` is `ok` then the value is extracted and passed to `op` whereupon
 * `op`s result is returned. if `res` is `err` then it is immediately
 * returned. This function can be used to compose the results of two
 * functions.
 *
 * Example:
 *
 *     iter(read_file(file)) { |buf|
 *         print_buf(buf)
 *     }
 */
fn iter<T, E>(res: Result<T, E>, f: fn(T)) {
    match res {
      Ok(t) => f(t),
      Err(_) => ()
    }
}

/**
 * Call a function based on a previous result
 *
 * If `res` is `err` then the value is extracted and passed to `op` whereupon
 * `op`s result is returned. if `res` is `ok` then it is immediately returned.
 * This function can be used to pass through a successful result while
 * handling an error.
 */
fn iter_err<T, E>(res: Result<T, E>, f: fn(E)) {
    match res {
      Ok(_) => (),
      Err(e) => f(e)
    }
}

/**
 * Call a function based on a previous result
 *
 * If `res` is `ok` then the value is extracted and passed to `op` whereupon
 * `op`s result is wrapped in `ok` and returned. if `res` is `err` then it is
 * immediately returned.  This function can be used to compose the results of
 * two functions.
 *
 * Example:
 *
 *     let res = map(read_file(file)) { |buf|
 *         parse_buf(buf)
 *     }
 */
fn map<T, E: copy, U: copy>(res: Result<T, E>, op: fn(T) -> U)
  -> Result<U, E> {
    match res {
      Ok(t) => Ok(op(t)),
      Err(e) => Err(e)
    }
}

/**
 * Call a function based on a previous result
 *
 * If `res` is `err` then the value is extracted and passed to `op` whereupon
 * `op`s result is wrapped in an `err` and returned. if `res` is `ok` then it
 * is immediately returned.  This function can be used to pass through a
 * successful result while handling an error.
 */
fn map_err<T: copy, E, F: copy>(res: Result<T, E>, op: fn(E) -> F)
  -> Result<T, F> {
    match res {
      Ok(t) => Ok(t),
      Err(e) => Err(op(e))
    }
}

impl<T, E> Result<T, E> {
    fn is_ok() -> bool { is_ok(self) }

    fn is_err() -> bool { is_err(self) }

    fn iter(f: fn(T)) {
        match self {
          Ok(t) => f(t),
          Err(_) => ()
        }
    }

    fn iter_err(f: fn(E)) {
        match self {
          Ok(_) => (),
          Err(e) => f(e)
        }
    }
}

impl<T: copy, E> Result<T, E> {
    fn get() -> T { get(self) }

    fn map_err<F:copy>(op: fn(E) -> F) -> Result<T,F> {
        match self {
          Ok(t) => Ok(t),
          Err(e) => Err(op(e))
        }
    }
}

impl<T, E: copy> Result<T, E> {
    fn get_err() -> E { get_err(self) }

    fn map<U:copy>(op: fn(T) -> U) -> Result<U,E> {
        match self {
          Ok(t) => Ok(op(t)),
          Err(e) => Err(e)
        }
    }
}

impl<T: copy, E: copy> Result<T, E> {
    fn chain<U:copy>(op: fn(T) -> Result<U,E>) -> Result<U,E> {
        chain(self, op)
    }

    fn chain_err<F:copy>(op: fn(E) -> Result<T,F>) -> Result<T,F> {
        chain_err(self, op)
    }
}

/**
 * Maps each element in the vector `ts` using the operation `op`.  Should an
 * error occur, no further mappings are performed and the error is returned.
 * Should no error occur, a vector containing the result of each map is
 * returned.
 *
 * Here is an example which increments every integer in a vector,
 * checking for overflow:
 *
 *     fn inc_conditionally(x: uint) -> result<uint,str> {
 *         if x == uint::max_value { return err("overflow"); }
 *         else { return ok(x+1u); }
 *     }
 *     map(~[1u, 2u, 3u], inc_conditionally).chain {|incd|
 *         assert incd == ~[2u, 3u, 4u];
 *     }
 */
fn map_vec<T,U:copy,V:copy>(
    ts: &[T], op: fn(T) -> Result<V,U>) -> Result<~[V],U> {

    let mut vs: ~[V] = ~[];
    vec::reserve(vs, vec::len(ts));
    for vec::each(ts) |t| {
        match op(t) {
          Ok(v) => vec::push(vs, v),
          Err(u) => return Err(u)
        }
    }
    return Ok(vs);
}

fn map_opt<T,U:copy,V:copy>(
    o_t: Option<T>, op: fn(T) -> Result<V,U>) -> Result<Option<V>,U> {

    match o_t {
      None => Ok(None),
      Some(t) => match op(t) {
        Ok(v) => Ok(Some(v)),
        Err(e) => Err(e)
      }
    }
}

/**
 * Same as map, but it operates over two parallel vectors.
 *
 * A precondition is used here to ensure that the vectors are the same
 * length.  While we do not often use preconditions in the standard
 * library, a precondition is used here because result::t is generally
 * used in 'careful' code contexts where it is both appropriate and easy
 * to accommodate an error like the vectors being of different lengths.
 */
fn map_vec2<S,T,U:copy,V:copy>(ss: &[S], ts: &[T],
                               op: fn(S,T) -> Result<V,U>) -> Result<~[V],U> {

    assert vec::same_length(ss, ts);
    let n = vec::len(ts);
    let mut vs = ~[];
    vec::reserve(vs, n);
    let mut i = 0u;
    while i < n {
        match op(ss[i],ts[i]) {
          Ok(v) => vec::push(vs, v),
          Err(u) => return Err(u)
        }
        i += 1u;
    }
    return Ok(vs);
}

/**
 * Applies op to the pairwise elements from `ss` and `ts`, aborting on
 * error.  This could be implemented using `map2()` but it is more efficient
 * on its own as no result vector is built.
 */
fn iter_vec2<S,T,U:copy>(ss: &[S], ts: &[T],
                         op: fn(S,T) -> Result<(),U>) -> Result<(),U> {

    assert vec::same_length(ss, ts);
    let n = vec::len(ts);
    let mut i = 0u;
    while i < n {
        match op(ss[i],ts[i]) {
          Ok(()) => (),
          Err(u) => return Err(u)
        }
        i += 1u;
    }
    return Ok(());
}

/// Unwraps a result, assuming it is an `ok(T)`
fn unwrap<T, U>(-res: Result<T, U>) -> T {
    unsafe {
        let addr = match res {
          Ok(x) => ptr::addr_of(x),
          Err(_) => fail ~"error result"
        };
        let liberated_value = unsafe::reinterpret_cast(*addr);
        unsafe::forget(res);
        return liberated_value;
    }
}

impl<T:Eq,U:Eq> Result<T,U> : Eq {
    pure fn eq(&&other: Result<T,U>) -> bool {
        match self {
            Ok(e0a) => {
                match other {
                    Ok(e0b) => e0a == e0b,
                    _ => false
                }
            }
            Err(e0a) => {
                match other {
                    Err(e0b) => e0a == e0b,
                    _ => false
                }
            }
        }
    }
}

#[cfg(test)]
mod tests {
    fn op1() -> result::Result<int, ~str> { result::Ok(666) }

    fn op2(&&i: int) -> result::Result<uint, ~str> {
        result::Ok(i as uint + 1u)
    }

    fn op3() -> result::Result<int, ~str> { result::Err(~"sadface") }

    #[test]
    fn chain_success() {
        assert get(chain(op1(), op2)) == 667u;
    }

    #[test]
    fn chain_failure() {
        assert get_err(chain(op3(), op2)) == ~"sadface";
    }

    #[test]
    fn test_impl_iter() {
        let mut valid = false;
        Ok::<~str, ~str>(~"a").iter(|_x| valid = true);
        assert valid;

        Err::<~str, ~str>(~"b").iter(|_x| valid = false);
        assert valid;
    }

    #[test]
    fn test_impl_iter_err() {
        let mut valid = true;
        Ok::<~str, ~str>(~"a").iter_err(|_x| valid = false);
        assert valid;

        valid = false;
        Err::<~str, ~str>(~"b").iter_err(|_x| valid = true);
        assert valid;
    }

    #[test]
    fn test_impl_map() {
        assert Ok::<~str, ~str>(~"a").map(|_x| ~"b") == Ok(~"b");
        assert Err::<~str, ~str>(~"a").map(|_x| ~"b") == Err(~"a");
    }

    #[test]
    fn test_impl_map_err() {
        assert Ok::<~str, ~str>(~"a").map_err(|_x| ~"b") == Ok(~"a");
        assert Err::<~str, ~str>(~"a").map_err(|_x| ~"b") == Err(~"b");
    }
}
<commit_msg>libcore: result::unwrap should use moves<commit_after>//! A type representing either success or failure

import cmp::Eq;
import either::Either;

/// The result type
enum Result<T, U> {
    /// Contains the successful result value
    Ok(T),
    /// Contains the error value
    Err(U)
}

/**
 * Get the value out of a successful result
 *
 * # Failure
 *
 * If the result is an error
 */
pure fn get<T: copy, U>(res: Result<T, U>) -> T {
    match res {
      Ok(t) => t,
      Err(the_err) => unchecked {
        fail fmt!("get called on error result: %?", the_err)
      }
    }
}

/**
 * Get a reference to the value out of a successful result
 *
 * # Failure
 *
 * If the result is an error
 */
pure fn get_ref<T, U>(res: &a/Result<T, U>) -> &a/T {
    match *res {
        Ok(ref t) => t,
        Err(ref the_err) => unchecked {
            fail fmt!("get_ref called on error result: %?", the_err)
        }
    }
}

/**
 * Get the value out of an error result
 *
 * # Failure
 *
 * If the result is not an error
 */
pure fn get_err<T, U: copy>(res: Result<T, U>) -> U {
    match res {
      Err(u) => u,
      Ok(_) => fail ~"get_err called on ok result"
    }
}

/// Returns true if the result is `ok`
pure fn is_ok<T, U>(res: Result<T, U>) -> bool {
    match res {
      Ok(_) => true,
      Err(_) => false
    }
}

/// Returns true if the result is `err`
pure fn is_err<T, U>(res: Result<T, U>) -> bool {
    !is_ok(res)
}

/**
 * Convert to the `either` type
 *
 * `ok` result variants are converted to `either::right` variants, `err`
 * result variants are converted to `either::left`.
 */
pure fn to_either<T: copy, U: copy>(res: Result<U, T>) -> Either<T, U> {
    match res {
      Ok(res) => either::Right(res),
      Err(fail_) => either::Left(fail_)
    }
}

/**
 * Call a function based on a previous result
 *
 * If `res` is `ok` then the value is extracted and passed to `op` whereupon
 * `op`s result is returned. if `res` is `err` then it is immediately
 * returned. This function can be used to compose the results of two
 * functions.
 *
 * Example:
 *
 *     let res = chain(read_file(file)) { |buf|
 *         ok(parse_buf(buf))
 *     }
 */
fn chain<T, U: copy, V: copy>(res: Result<T, V>, op: fn(T) -> Result<U, V>)
    -> Result<U, V> {
    match res {
      Ok(t) => op(t),
      Err(e) => Err(e)
    }
}

/**
 * Call a function based on a previous result
 *
 * If `res` is `err` then the value is extracted and passed to `op`
 * whereupon `op`s result is returned. if `res` is `ok` then it is
 * immediately returned.  This function can be used to pass through a
 * successful result while handling an error.
 */
fn chain_err<T: copy, U: copy, V: copy>(
    res: Result<T, V>,
    op: fn(V) -> Result<T, U>)
    -> Result<T, U> {
    match res {
      Ok(t) => Ok(t),
      Err(v) => op(v)
    }
}

/**
 * Call a function based on a previous result
 *
 * If `res` is `ok` then the value is extracted and passed to `op` whereupon
 * `op`s result is returned. if `res` is `err` then it is immediately
 * returned. This function can be used to compose the results of two
 * functions.
 *
 * Example:
 *
 *     iter(read_file(file)) { |buf|
 *         print_buf(buf)
 *     }
 */
fn iter<T, E>(res: Result<T, E>, f: fn(T)) {
    match res {
      Ok(t) => f(t),
      Err(_) => ()
    }
}

/**
 * Call a function based on a previous result
 *
 * If `res` is `err` then the value is extracted and passed to `op` whereupon
 * `op`s result is returned. if `res` is `ok` then it is immediately returned.
 * This function can be used to pass through a successful result while
 * handling an error.
 */
fn iter_err<T, E>(res: Result<T, E>, f: fn(E)) {
    match res {
      Ok(_) => (),
      Err(e) => f(e)
    }
}

/**
 * Call a function based on a previous result
 *
 * If `res` is `ok` then the value is extracted and passed to `op` whereupon
 * `op`s result is wrapped in `ok` and returned. if `res` is `err` then it is
 * immediately returned.  This function can be used to compose the results of
 * two functions.
 *
 * Example:
 *
 *     let res = map(read_file(file)) { |buf|
 *         parse_buf(buf)
 *     }
 */
fn map<T, E: copy, U: copy>(res: Result<T, E>, op: fn(T) -> U)
  -> Result<U, E> {
    match res {
      Ok(t) => Ok(op(t)),
      Err(e) => Err(e)
    }
}

/**
 * Call a function based on a previous result
 *
 * If `res` is `err` then the value is extracted and passed to `op` whereupon
 * `op`s result is wrapped in an `err` and returned. if `res` is `ok` then it
 * is immediately returned.  This function can be used to pass through a
 * successful result while handling an error.
 */
fn map_err<T: copy, E, F: copy>(res: Result<T, E>, op: fn(E) -> F)
  -> Result<T, F> {
    match res {
      Ok(t) => Ok(t),
      Err(e) => Err(op(e))
    }
}

impl<T, E> Result<T, E> {
    fn is_ok() -> bool { is_ok(self) }

    fn is_err() -> bool { is_err(self) }

    fn iter(f: fn(T)) {
        match self {
          Ok(t) => f(t),
          Err(_) => ()
        }
    }

    fn iter_err(f: fn(E)) {
        match self {
          Ok(_) => (),
          Err(e) => f(e)
        }
    }
}

impl<T: copy, E> Result<T, E> {
    fn get() -> T { get(self) }

    fn map_err<F:copy>(op: fn(E) -> F) -> Result<T,F> {
        match self {
          Ok(t) => Ok(t),
          Err(e) => Err(op(e))
        }
    }
}

impl<T, E: copy> Result<T, E> {
    fn get_err() -> E { get_err(self) }

    fn map<U:copy>(op: fn(T) -> U) -> Result<U,E> {
        match self {
          Ok(t) => Ok(op(t)),
          Err(e) => Err(e)
        }
    }
}

impl<T: copy, E: copy> Result<T, E> {
    fn chain<U:copy>(op: fn(T) -> Result<U,E>) -> Result<U,E> {
        chain(self, op)
    }

    fn chain_err<F:copy>(op: fn(E) -> Result<T,F>) -> Result<T,F> {
        chain_err(self, op)
    }
}

/**
 * Maps each element in the vector `ts` using the operation `op`.  Should an
 * error occur, no further mappings are performed and the error is returned.
 * Should no error occur, a vector containing the result of each map is
 * returned.
 *
 * Here is an example which increments every integer in a vector,
 * checking for overflow:
 *
 *     fn inc_conditionally(x: uint) -> result<uint,str> {
 *         if x == uint::max_value { return err("overflow"); }
 *         else { return ok(x+1u); }
 *     }
 *     map(~[1u, 2u, 3u], inc_conditionally).chain {|incd|
 *         assert incd == ~[2u, 3u, 4u];
 *     }
 */
fn map_vec<T,U:copy,V:copy>(
    ts: &[T], op: fn(T) -> Result<V,U>) -> Result<~[V],U> {

    let mut vs: ~[V] = ~[];
    vec::reserve(vs, vec::len(ts));
    for vec::each(ts) |t| {
        match op(t) {
          Ok(v) => vec::push(vs, v),
          Err(u) => return Err(u)
        }
    }
    return Ok(vs);
}

fn map_opt<T,U:copy,V:copy>(
    o_t: Option<T>, op: fn(T) -> Result<V,U>) -> Result<Option<V>,U> {

    match o_t {
      None => Ok(None),
      Some(t) => match op(t) {
        Ok(v) => Ok(Some(v)),
        Err(e) => Err(e)
      }
    }
}

/**
 * Same as map, but it operates over two parallel vectors.
 *
 * A precondition is used here to ensure that the vectors are the same
 * length.  While we do not often use preconditions in the standard
 * library, a precondition is used here because result::t is generally
 * used in 'careful' code contexts where it is both appropriate and easy
 * to accommodate an error like the vectors being of different lengths.
 */
fn map_vec2<S,T,U:copy,V:copy>(ss: &[S], ts: &[T],
                               op: fn(S,T) -> Result<V,U>) -> Result<~[V],U> {

    assert vec::same_length(ss, ts);
    let n = vec::len(ts);
    let mut vs = ~[];
    vec::reserve(vs, n);
    let mut i = 0u;
    while i < n {
        match op(ss[i],ts[i]) {
          Ok(v) => vec::push(vs, v),
          Err(u) => return Err(u)
        }
        i += 1u;
    }
    return Ok(vs);
}

/**
 * Applies op to the pairwise elements from `ss` and `ts`, aborting on
 * error.  This could be implemented using `map2()` but it is more efficient
 * on its own as no result vector is built.
 */
fn iter_vec2<S,T,U:copy>(ss: &[S], ts: &[T],
                         op: fn(S,T) -> Result<(),U>) -> Result<(),U> {

    assert vec::same_length(ss, ts);
    let n = vec::len(ts);
    let mut i = 0u;
    while i < n {
        match op(ss[i],ts[i]) {
          Ok(()) => (),
          Err(u) => return Err(u)
        }
        i += 1u;
    }
    return Ok(());
}

/// Unwraps a result, assuming it is an `ok(T)`
fn unwrap<T, U>(+res: Result<T, U>) -> T {
    match move res {
      Ok(move t) => t,
      Err(_) => fail ~"unwrap called on an err result"
    }
}

impl<T:Eq,U:Eq> Result<T,U> : Eq {
    pure fn eq(&&other: Result<T,U>) -> bool {
        match self {
            Ok(e0a) => {
                match other {
                    Ok(e0b) => e0a == e0b,
                    _ => false
                }
            }
            Err(e0a) => {
                match other {
                    Err(e0b) => e0a == e0b,
                    _ => false
                }
            }
        }
    }
}

#[cfg(test)]
mod tests {
    fn op1() -> result::Result<int, ~str> { result::Ok(666) }

    fn op2(&&i: int) -> result::Result<uint, ~str> {
        result::Ok(i as uint + 1u)
    }

    fn op3() -> result::Result<int, ~str> { result::Err(~"sadface") }

    #[test]
    fn chain_success() {
        assert get(chain(op1(), op2)) == 667u;
    }

    #[test]
    fn chain_failure() {
        assert get_err(chain(op3(), op2)) == ~"sadface";
    }

    #[test]
    fn test_impl_iter() {
        let mut valid = false;
        Ok::<~str, ~str>(~"a").iter(|_x| valid = true);
        assert valid;

        Err::<~str, ~str>(~"b").iter(|_x| valid = false);
        assert valid;
    }

    #[test]
    fn test_impl_iter_err() {
        let mut valid = true;
        Ok::<~str, ~str>(~"a").iter_err(|_x| valid = false);
        assert valid;

        valid = false;
        Err::<~str, ~str>(~"b").iter_err(|_x| valid = true);
        assert valid;
    }

    #[test]
    fn test_impl_map() {
        assert Ok::<~str, ~str>(~"a").map(|_x| ~"b") == Ok(~"b");
        assert Err::<~str, ~str>(~"a").map(|_x| ~"b") == Err(~"a");
    }

    #[test]
    fn test_impl_map_err() {
        assert Ok::<~str, ~str>(~"a").map_err(|_x| ~"b") == Ok(~"a");
        assert Err::<~str, ~str>(~"a").map_err(|_x| ~"b") == Err(~"b");
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use libc;
use uint;
use option::{Some, None};
use cell::Cell;
use clone::Clone;
use container::Container;
use iterator::IteratorUtil;
use vec::{OwnedVector, MutableVector};
use super::io::net::ip::{IpAddr, Ipv4, Ipv6};
use rt::sched::Scheduler;
use rt::local::Local;
use unstable::run_in_bare_thread;
use rt::thread::Thread;
use rt::task::Task;
use rt::uv::uvio::UvEventLoop;
use rt::work_queue::WorkQueue;
use rt::sleeper_list::SleeperList;
use rt::task::{Sched};
use rt::comm::oneshot;
use result::{Result, Ok, Err};

pub fn new_test_uv_sched() -> Scheduler {

    let mut sched = Scheduler::new(~UvEventLoop::new(),
                                   WorkQueue::new(),
                                   SleeperList::new());
    // Don't wait for the Shutdown message
    sched.no_sleep = true;
    return sched;
}

/// Creates a new scheduler in a new thread and runs a task in it,
/// then waits for the scheduler to exit. Failure of the task
/// will abort the process.
pub fn run_in_newsched_task(f: ~fn()) {
    let f = Cell::new(f);

    do run_in_bare_thread {
        let mut sched = ~new_test_uv_sched();
        let on_exit: ~fn(bool) = |exit_status| rtassert!(exit_status);
        let mut task = ~Task::new_root(&mut sched.stack_pool,
                                       f.take());
        rtdebug!("newsched_task: %x", to_uint(task));
        task.on_exit = Some(on_exit);
        sched.enqueue_task(task);
        sched.run();
    }
}

/// Create more than one scheduler and run a function in a task
/// in one of the schedulers. The schedulers will stay alive
/// until the function `f` returns.
pub fn run_in_mt_newsched_task(f: ~fn()) {
    use os;
    use from_str::FromStr;
    use rt::sched::Shutdown;
    use rt::util;

    let f_cell = Cell::new(f);

    do run_in_bare_thread {
        let nthreads = match os::getenv("RUST_TEST_THREADS") {
            Some(nstr) => FromStr::from_str(nstr).get(),
            None => {
                // Using more threads than cores in test code
                // to force the OS to preempt them frequently.
                // Assuming that this help stress test concurrent types.
                util::num_cpus() * 2
            }
        };

        let sleepers = SleeperList::new();
        let work_queue = WorkQueue::new();

        let mut handles = ~[];
        let mut scheds = ~[];

        for uint::range(0, nthreads) |_| {
            let loop_ = ~UvEventLoop::new();
            let mut sched = ~Scheduler::new(loop_,
                                            work_queue.clone(),
                                            sleepers.clone());
            let handle = sched.make_handle();

            handles.push(handle);
            scheds.push(sched);
        }

        let f_cell = Cell::new(f_cell.take());
        let handles = Cell::new(handles);
        let on_exit: ~fn(bool) = |exit_status| {
            let mut handles = handles.take();
            // Tell schedulers to exit
            for handles.mut_iter().advance |handle| {
                handle.send(Shutdown);
            }

            rtassert!(exit_status);
        };
        let mut main_task = ~Task::new_root(&mut scheds[0].stack_pool,
                                        f_cell.take());
        main_task.on_exit = Some(on_exit);
        scheds[0].enqueue_task(main_task);

        let mut threads = ~[];

        while !scheds.is_empty() {
            let sched = scheds.pop();
            let sched_cell = Cell::new(sched);
            let thread = do Thread::start {
                let sched = sched_cell.take();
                sched.run();
            };

            threads.push(thread);
        }

        // Wait for schedulers
        let _threads = threads;
    }

}

/// Test tasks will abort on failure instead of unwinding
pub fn spawntask(f: ~fn()) {
    use super::sched::*;
    let f = Cell::new(f);

    let task = unsafe {
        let sched = Local::unsafe_borrow::<Scheduler>();
        rtdebug!("spawntask taking the scheduler from TLS");

        do Local::borrow::<Task, ~Task>() |running_task| {
            ~running_task.new_child(&mut (*sched).stack_pool, f.take())
        }
    };

    rtdebug!("new task pointer: %x", to_uint(task));

    let sched = Local::take::<Scheduler>();
    rtdebug!("spawntask scheduling the new task");
    sched.schedule_task(task);
}

/// Create a new task and run it right now. Aborts on failure
pub fn spawntask_immediately(f: ~fn()) {
    use super::sched::*;

    let f = Cell::new(f);

    let task = unsafe {
        let sched = Local::unsafe_borrow::<Scheduler>();
        do Local::borrow::<Task, ~Task>() |running_task| {
            ~running_task.new_child(&mut (*sched).stack_pool,
                                    f.take())
        }
    };

    let sched = Local::take::<Scheduler>();
    do sched.switch_running_tasks_and_then(task) |sched, task| {
        sched.enqueue_task(task);
    }
}

/// Create a new task and run it right now. Aborts on failure
pub fn spawntask_later(f: ~fn()) {
    use super::sched::*;
    let f = Cell::new(f);

    let task = unsafe {
        let sched = Local::unsafe_borrow::<Scheduler>();
        do Local::borrow::<Task, ~Task>() |running_task| {
            ~running_task.new_child(&mut (*sched).stack_pool, f.take())
        }
    };

    let mut sched = Local::take::<Scheduler>();
    sched.enqueue_task(task);
    Local::put(sched);
}

/// Spawn a task and either run it immediately or run it later
pub fn spawntask_random(f: ~fn()) {
    use super::sched::*;
    use rand::{Rand, rng};

    let f = Cell::new(f);

    let task = unsafe {
        let sched = Local::unsafe_borrow::<Scheduler>();
        do Local::borrow::<Task, ~Task>() |running_task| {
            ~running_task.new_child(&mut (*sched).stack_pool,
                                    f.take())

        }
    };

    let mut sched = Local::take::<Scheduler>();

    let mut rng = rng();
    let run_now: bool = Rand::rand(&mut rng);

    if run_now {
        do sched.switch_running_tasks_and_then(task) |sched, task| {
            sched.enqueue_task(task);
        }
    } else {
        sched.enqueue_task(task);
        Local::put(sched);
    }
}

/// Spawn a task, with the current scheduler as home, and queue it to
/// run later.
pub fn spawntask_homed(scheds: &mut ~[~Scheduler], f: ~fn()) {
    use super::sched::*;
    use rand::{rng, RngUtil};
    let mut rng = rng();

    let task = {
        let sched = &mut scheds[rng.gen_int_range(0,scheds.len() as int)];
        let handle = sched.make_handle();
        let home_id = handle.sched_id;

        // now that we know where this is going, build a new function
        // that can assert it is in the right place
        let af: ~fn() = || {
            do Local::borrow::<Scheduler,()>() |sched| {
                rtdebug!("home_id: %u, runtime loc: %u",
                         home_id,
                         sched.sched_id());
                assert!(home_id == sched.sched_id());
            };
            f()
        };

        ~Task::new_root_homed(&mut sched.stack_pool,
                              Sched(handle),
                              af)
    };
    let dest_sched = &mut scheds[rng.gen_int_range(0,scheds.len() as int)];
    // enqueue it for future execution
    dest_sched.enqueue_task(task);
}

/// Spawn a task and wait for it to finish, returning whether it
/// completed successfully or failed
pub fn spawntask_try(f: ~fn()) -> Result<(), ()> {
    use cell::Cell;
    use super::sched::*;

    let f = Cell::new(f);

    let (port, chan) = oneshot();
    let chan = Cell::new(chan);
    let on_exit: ~fn(bool) = |exit_status| chan.take().send(exit_status);
    let mut new_task = unsafe {
        let sched = Local::unsafe_borrow::<Scheduler>();
        do Local::borrow::<Task, ~Task> |_running_task| {

            // I don't understand why using a child task here fails. I
            // think the fail status is propogating back up the task
            // tree and triggering a fail for the parent, which we
            // aren't correctly expecting.

            // ~running_task.new_child(&mut (*sched).stack_pool,
            ~Task::new_root(&mut (*sched).stack_pool,
                           f.take())
        }
    };
    new_task.on_exit = Some(on_exit);

    let sched = Local::take::<Scheduler>();
    do sched.switch_running_tasks_and_then(new_task) |sched, old_task| {
        sched.enqueue_task(old_task);
    }

    rtdebug!("enqueued the new task, now waiting on exit_status");

    let exit_status = port.recv();
    if exit_status { Ok(()) } else { Err(()) }
}

// Spawn a new task in a new scheduler and return a thread handle.
pub fn spawntask_thread(f: ~fn()) -> Thread {
    use rt::sched::*;

    let f = Cell::new(f);

    let task = unsafe {
        let sched = Local::unsafe_borrow::<Scheduler>();
        do Local::borrow::<Task, ~Task>() |running_task| {
            ~running_task.new_child(&mut (*sched).stack_pool,
                                    f.take())
        }
    };

    let task = Cell::new(task);

    let thread = do Thread::start {
        let mut sched = ~new_test_uv_sched();
        sched.enqueue_task(task.take());
        sched.run();
    };
    return thread;
}

/// Get a port number, starting at 9600, for use in tests
pub fn next_test_port() -> u16 {
    unsafe {
        return rust_dbg_next_port(base_port() as libc::uintptr_t) as u16;
    }
    extern {
        fn rust_dbg_next_port(base: libc::uintptr_t) -> libc::uintptr_t;
    }
}

/// Get a unique IPv4 localhost:port pair starting at 9600
pub fn next_test_ip4() -> IpAddr {
    Ipv4(127, 0, 0, 1, next_test_port())
}

/// Get a unique IPv6 localhost:port pair starting at 9600
pub fn next_test_ip6() -> IpAddr {
    Ipv6(0, 0, 0, 0, 0, 0, 0, 1, next_test_port())
}

/*
XXX: Welcome to MegaHack City.

The bots run multiple builds at the same time, and these builds
all want to use ports. This function figures out which workspace
it is running in and assigns a port range based on it.
*/
fn base_port() -> uint {
    use os;
    use str::StrSlice;
    use to_str::ToStr;
    use vec::ImmutableVector;

    let base = 9600u;
    let range = 1000;

    let bases = [
        ("32-opt", base + range * 1),
        ("32-noopt", base + range * 2),
        ("64-opt", base + range * 3),
        ("64-noopt", base + range * 4),
        ("64-opt-vg", base + range * 5),
        ("all-opt", base + range * 6),
        ("snap3", base + range * 7),
        ("dist", base + range * 8)
    ];

    let path = os::getcwd().to_str();

    let mut final_base = base;

    for bases.iter().advance |&(dir, base)| {
        if path.contains(dir) {
            final_base = base;
            break;
        }
    }

    return final_base;
}

/// Get a constant that represents the number of times to repeat
/// stress tests. Default 1.
pub fn stress_factor() -> uint {
    use os::getenv;

    match getenv("RUST_RT_STRESS") {
        Some(val) => uint::from_str(val).get(),
        None => 1
    }
}
<commit_msg>auto merge of #7854 : brson/rust/rt-test-threads, r=pcwalton<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use libc;
use uint;
use option::{Some, None};
use cell::Cell;
use clone::Clone;
use container::Container;
use iterator::IteratorUtil;
use vec::{OwnedVector, MutableVector};
use super::io::net::ip::{IpAddr, Ipv4, Ipv6};
use rt::sched::Scheduler;
use rt::local::Local;
use unstable::run_in_bare_thread;
use rt::thread::Thread;
use rt::task::Task;
use rt::uv::uvio::UvEventLoop;
use rt::work_queue::WorkQueue;
use rt::sleeper_list::SleeperList;
use rt::task::{Sched};
use rt::comm::oneshot;
use result::{Result, Ok, Err};

pub fn new_test_uv_sched() -> Scheduler {

    let mut sched = Scheduler::new(~UvEventLoop::new(),
                                   WorkQueue::new(),
                                   SleeperList::new());
    // Don't wait for the Shutdown message
    sched.no_sleep = true;
    return sched;
}

/// Creates a new scheduler in a new thread and runs a task in it,
/// then waits for the scheduler to exit. Failure of the task
/// will abort the process.
pub fn run_in_newsched_task(f: ~fn()) {
    let f = Cell::new(f);

    do run_in_bare_thread {
        let mut sched = ~new_test_uv_sched();
        let on_exit: ~fn(bool) = |exit_status| rtassert!(exit_status);
        let mut task = ~Task::new_root(&mut sched.stack_pool,
                                       f.take());
        rtdebug!("newsched_task: %x", to_uint(task));
        task.on_exit = Some(on_exit);
        sched.enqueue_task(task);
        sched.run();
    }
}

/// Create more than one scheduler and run a function in a task
/// in one of the schedulers. The schedulers will stay alive
/// until the function `f` returns.
pub fn run_in_mt_newsched_task(f: ~fn()) {
    use os;
    use from_str::FromStr;
    use rt::sched::Shutdown;
    use rt::util;

    let f_cell = Cell::new(f);

    do run_in_bare_thread {
        let nthreads = match os::getenv("RUST_RT_TEST_THREADS") {
            Some(nstr) => FromStr::from_str(nstr).get(),
            None => {
                // Using more threads than cores in test code
                // to force the OS to preempt them frequently.
                // Assuming that this help stress test concurrent types.
                util::num_cpus() * 2
            }
        };

        let sleepers = SleeperList::new();
        let work_queue = WorkQueue::new();

        let mut handles = ~[];
        let mut scheds = ~[];

        for uint::range(0, nthreads) |_| {
            let loop_ = ~UvEventLoop::new();
            let mut sched = ~Scheduler::new(loop_,
                                            work_queue.clone(),
                                            sleepers.clone());
            let handle = sched.make_handle();

            handles.push(handle);
            scheds.push(sched);
        }

        let f_cell = Cell::new(f_cell.take());
        let handles = Cell::new(handles);
        let on_exit: ~fn(bool) = |exit_status| {
            let mut handles = handles.take();
            // Tell schedulers to exit
            for handles.mut_iter().advance |handle| {
                handle.send(Shutdown);
            }

            rtassert!(exit_status);
        };
        let mut main_task = ~Task::new_root(&mut scheds[0].stack_pool,
                                        f_cell.take());
        main_task.on_exit = Some(on_exit);
        scheds[0].enqueue_task(main_task);

        let mut threads = ~[];

        while !scheds.is_empty() {
            let sched = scheds.pop();
            let sched_cell = Cell::new(sched);
            let thread = do Thread::start {
                let sched = sched_cell.take();
                sched.run();
            };

            threads.push(thread);
        }

        // Wait for schedulers
        let _threads = threads;
    }

}

/// Test tasks will abort on failure instead of unwinding
pub fn spawntask(f: ~fn()) {
    use super::sched::*;
    let f = Cell::new(f);

    let task = unsafe {
        let sched = Local::unsafe_borrow::<Scheduler>();
        rtdebug!("spawntask taking the scheduler from TLS");

        do Local::borrow::<Task, ~Task>() |running_task| {
            ~running_task.new_child(&mut (*sched).stack_pool, f.take())
        }
    };

    rtdebug!("new task pointer: %x", to_uint(task));

    let sched = Local::take::<Scheduler>();
    rtdebug!("spawntask scheduling the new task");
    sched.schedule_task(task);
}

/// Create a new task and run it right now. Aborts on failure
pub fn spawntask_immediately(f: ~fn()) {
    use super::sched::*;

    let f = Cell::new(f);

    let task = unsafe {
        let sched = Local::unsafe_borrow::<Scheduler>();
        do Local::borrow::<Task, ~Task>() |running_task| {
            ~running_task.new_child(&mut (*sched).stack_pool,
                                    f.take())
        }
    };

    let sched = Local::take::<Scheduler>();
    do sched.switch_running_tasks_and_then(task) |sched, task| {
        sched.enqueue_task(task);
    }
}

/// Create a new task and run it right now. Aborts on failure
pub fn spawntask_later(f: ~fn()) {
    use super::sched::*;
    let f = Cell::new(f);

    let task = unsafe {
        let sched = Local::unsafe_borrow::<Scheduler>();
        do Local::borrow::<Task, ~Task>() |running_task| {
            ~running_task.new_child(&mut (*sched).stack_pool, f.take())
        }
    };

    let mut sched = Local::take::<Scheduler>();
    sched.enqueue_task(task);
    Local::put(sched);
}

/// Spawn a task and either run it immediately or run it later
pub fn spawntask_random(f: ~fn()) {
    use super::sched::*;
    use rand::{Rand, rng};

    let f = Cell::new(f);

    let task = unsafe {
        let sched = Local::unsafe_borrow::<Scheduler>();
        do Local::borrow::<Task, ~Task>() |running_task| {
            ~running_task.new_child(&mut (*sched).stack_pool,
                                    f.take())

        }
    };

    let mut sched = Local::take::<Scheduler>();

    let mut rng = rng();
    let run_now: bool = Rand::rand(&mut rng);

    if run_now {
        do sched.switch_running_tasks_and_then(task) |sched, task| {
            sched.enqueue_task(task);
        }
    } else {
        sched.enqueue_task(task);
        Local::put(sched);
    }
}

/// Spawn a task, with the current scheduler as home, and queue it to
/// run later.
pub fn spawntask_homed(scheds: &mut ~[~Scheduler], f: ~fn()) {
    use super::sched::*;
    use rand::{rng, RngUtil};
    let mut rng = rng();

    let task = {
        let sched = &mut scheds[rng.gen_int_range(0,scheds.len() as int)];
        let handle = sched.make_handle();
        let home_id = handle.sched_id;

        // now that we know where this is going, build a new function
        // that can assert it is in the right place
        let af: ~fn() = || {
            do Local::borrow::<Scheduler,()>() |sched| {
                rtdebug!("home_id: %u, runtime loc: %u",
                         home_id,
                         sched.sched_id());
                assert!(home_id == sched.sched_id());
            };
            f()
        };

        ~Task::new_root_homed(&mut sched.stack_pool,
                              Sched(handle),
                              af)
    };
    let dest_sched = &mut scheds[rng.gen_int_range(0,scheds.len() as int)];
    // enqueue it for future execution
    dest_sched.enqueue_task(task);
}

/// Spawn a task and wait for it to finish, returning whether it
/// completed successfully or failed
pub fn spawntask_try(f: ~fn()) -> Result<(), ()> {
    use cell::Cell;
    use super::sched::*;

    let f = Cell::new(f);

    let (port, chan) = oneshot();
    let chan = Cell::new(chan);
    let on_exit: ~fn(bool) = |exit_status| chan.take().send(exit_status);
    let mut new_task = unsafe {
        let sched = Local::unsafe_borrow::<Scheduler>();
        do Local::borrow::<Task, ~Task> |_running_task| {

            // I don't understand why using a child task here fails. I
            // think the fail status is propogating back up the task
            // tree and triggering a fail for the parent, which we
            // aren't correctly expecting.

            // ~running_task.new_child(&mut (*sched).stack_pool,
            ~Task::new_root(&mut (*sched).stack_pool,
                           f.take())
        }
    };
    new_task.on_exit = Some(on_exit);

    let sched = Local::take::<Scheduler>();
    do sched.switch_running_tasks_and_then(new_task) |sched, old_task| {
        sched.enqueue_task(old_task);
    }

    rtdebug!("enqueued the new task, now waiting on exit_status");

    let exit_status = port.recv();
    if exit_status { Ok(()) } else { Err(()) }
}

// Spawn a new task in a new scheduler and return a thread handle.
pub fn spawntask_thread(f: ~fn()) -> Thread {
    use rt::sched::*;

    let f = Cell::new(f);

    let task = unsafe {
        let sched = Local::unsafe_borrow::<Scheduler>();
        do Local::borrow::<Task, ~Task>() |running_task| {
            ~running_task.new_child(&mut (*sched).stack_pool,
                                    f.take())
        }
    };

    let task = Cell::new(task);

    let thread = do Thread::start {
        let mut sched = ~new_test_uv_sched();
        sched.enqueue_task(task.take());
        sched.run();
    };
    return thread;
}

/// Get a port number, starting at 9600, for use in tests
pub fn next_test_port() -> u16 {
    unsafe {
        return rust_dbg_next_port(base_port() as libc::uintptr_t) as u16;
    }
    extern {
        fn rust_dbg_next_port(base: libc::uintptr_t) -> libc::uintptr_t;
    }
}

/// Get a unique IPv4 localhost:port pair starting at 9600
pub fn next_test_ip4() -> IpAddr {
    Ipv4(127, 0, 0, 1, next_test_port())
}

/// Get a unique IPv6 localhost:port pair starting at 9600
pub fn next_test_ip6() -> IpAddr {
    Ipv6(0, 0, 0, 0, 0, 0, 0, 1, next_test_port())
}

/*
XXX: Welcome to MegaHack City.

The bots run multiple builds at the same time, and these builds
all want to use ports. This function figures out which workspace
it is running in and assigns a port range based on it.
*/
fn base_port() -> uint {
    use os;
    use str::StrSlice;
    use to_str::ToStr;
    use vec::ImmutableVector;

    let base = 9600u;
    let range = 1000;

    let bases = [
        ("32-opt", base + range * 1),
        ("32-noopt", base + range * 2),
        ("64-opt", base + range * 3),
        ("64-noopt", base + range * 4),
        ("64-opt-vg", base + range * 5),
        ("all-opt", base + range * 6),
        ("snap3", base + range * 7),
        ("dist", base + range * 8)
    ];

    let path = os::getcwd().to_str();

    let mut final_base = base;

    for bases.iter().advance |&(dir, base)| {
        if path.contains(dir) {
            final_base = base;
            break;
        }
    }

    return final_base;
}

/// Get a constant that represents the number of times to repeat
/// stress tests. Default 1.
pub fn stress_factor() -> uint {
    use os::getenv;

    match getenv("RUST_RT_STRESS") {
        Some(val) => uint::from_str(val).get(),
        None => 1
    }
}
<|endoftext|>


<commit_before><commit_msg>run rustfmt on std::path<commit_after><|endoftext|>


<commit_before>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use core::prelude::*;

use ast;
use ast::{token_tree, tt_delim, tt_tok, tt_seq, tt_nonterminal,ident};
use ast_util;
use codemap::{span, dummy_sp};
use diagnostic::span_handler;
use ext::tt::macro_parser::{named_match, matched_seq, matched_nonterminal};
use parse::token::{EOF, INTERPOLATED, IDENT, Token, nt_ident, ident_interner};
use parse::lexer::TokenAndSpan;

use core::option;
use core::vec;
use std;
use std::oldmap::HashMap;

/* FIXME #2811: figure out how to have a uniquely linked stack, and change to
   `~` */
///an unzipping of `token_tree`s
struct TtFrame {
    readme: ~[ast::token_tree],
    idx: uint,
    dotdotdoted: bool,
    sep: Option<Token>,
    up: Option<@mut TtFrame>,
}

pub struct TtReader {
    sp_diag: span_handler,
    interner: @ident_interner,
    cur: @mut TtFrame,
    /* for MBE-style macro transcription */
    interpolations: std::oldmap::HashMap<ident, @named_match>,
    repeat_idx: ~[uint],
    repeat_len: ~[uint],
    /* cached: */
    cur_tok: Token,
    cur_span: span
}

/** This can do Macro-By-Example transcription. On the other hand, if
 *  `src` contains no `tt_seq`s and `tt_nonterminal`s, `interp` can (and
 *  should) be none. */
pub fn new_tt_reader(sp_diag: span_handler,
                     itr: @ident_interner,
                     interp: Option<std::oldmap::HashMap<ident,@named_match>>,
                     src: ~[ast::token_tree])
                  -> @mut TtReader {
    let r = @mut TtReader {
        sp_diag: sp_diag,
        interner: itr,
        mut cur: @mut TtFrame {
            readme: src,
            idx: 0u,
            dotdotdoted: false,
            sep: None,
            up: option::None
        },
        interpolations: match interp { /* just a convienience */
            None => std::oldmap::HashMap(),
            Some(x) => x
        },
        repeat_idx: ~[],
        repeat_len: ~[],
        /* dummy values, never read: */
        cur_tok: EOF,
        cur_span: dummy_sp()
    };
    tt_next_token(r); /* get cur_tok and cur_span set up */
    return r;
}

pure fn dup_tt_frame(f: @mut TtFrame) -> @mut TtFrame {
    @mut TtFrame {
        readme: f.readme,
        idx: f.idx,
        dotdotdoted: f.dotdotdoted,
        sep: f.sep,
        up: match f.up {
            Some(up_frame) => Some(dup_tt_frame(up_frame)),
            None => None
        }
    }
}

pub pure fn dup_tt_reader(r: @mut TtReader) -> @mut TtReader {
    @mut TtReader {
        sp_diag: r.sp_diag,
        interner: r.interner,
        cur: dup_tt_frame(r.cur),
        interpolations: r.interpolations,
        repeat_idx: copy r.repeat_idx,
        repeat_len: copy r.repeat_len,
        cur_tok: r.cur_tok,
        cur_span: r.cur_span
    }
}

pure fn lookup_cur_matched_by_matched(r: @mut TtReader,
                                      start: @named_match) -> @named_match {
    pure fn red(+ad: @named_match, idx: &uint) -> @named_match {
        match *ad {
          matched_nonterminal(_) => {
            // end of the line; duplicate henceforth
            ad
          }
          matched_seq(ads, _) => ads[*idx]
        }
    }
    vec::foldl(start, r.repeat_idx, red)
}

fn lookup_cur_matched(r: &TtReader, name: ident) -> @named_match {
    lookup_cur_matched_by_matched(r, r.interpolations.get(&name))
}
enum lis {
    lis_unconstrained, lis_constraint(uint, ident), lis_contradiction(~str)
}

fn lockstep_iter_size(t: token_tree, r: &TtReader) -> lis {
    fn lis_merge(lhs: lis, rhs: lis, r: &TtReader) -> lis {
        match lhs {
          lis_unconstrained => rhs,
          lis_contradiction(_) => lhs,
          lis_constraint(l_len, l_id) => match rhs {
            lis_unconstrained => lhs,
            lis_contradiction(_) => rhs,
            lis_constraint(r_len, _) if l_len == r_len => lhs,
            lis_constraint(r_len, r_id) => {
                let l_n = *r.interner.get(l_id);
                let r_n = *r.interner.get(r_id);
                lis_contradiction(fmt!("Inconsistent lockstep iteration: \
                                       '%s' has %u items, but '%s' has %u",
                                        l_n, l_len, r_n, r_len))
            }
          }
        }
    }
    match t {
      tt_delim(ref tts) | tt_seq(_, ref tts, _, _) => {
        vec::foldl(lis_unconstrained, (*tts), |lis, tt|
            lis_merge(lis, lockstep_iter_size(*tt, r), r))
      }
      tt_tok(*) => lis_unconstrained,
      tt_nonterminal(_, name) => match *lookup_cur_matched(r, name) {
        matched_nonterminal(_) => lis_unconstrained,
        matched_seq(ads, _) => lis_constraint(ads.len(), name)
      }
    }
}

pub fn tt_next_token(r: @mut TtReader) -> TokenAndSpan {
    let ret_val = TokenAndSpan { tok: r.cur_tok, sp: r.cur_span };
    while r.cur.idx >= r.cur.readme.len() {
        /* done with this set; pop or repeat? */
        if ! r.cur.dotdotdoted
            || r.repeat_idx.last() == r.repeat_len.last() - 1 {

            match r.cur.up {
              None => {
                r.cur_tok = EOF;
                return ret_val;
              }
              Some(tt_f) => {
                if r.cur.dotdotdoted {
                    r.repeat_idx.pop();
                    r.repeat_len.pop();
                }

                r.cur = tt_f;
                r.cur.idx += 1u;
              }
            }

        } else { /* repeat */
            r.cur.idx = 0u;
            r.repeat_idx[r.repeat_idx.len() - 1u] += 1u;
            match r.cur.sep {
              Some(tk) => {
                r.cur_tok = tk; /* repeat same span, I guess */
                return ret_val;
              }
              None => ()
            }
        }
    }
    loop { /* because it's easiest, this handles `tt_delim` not starting
    with a `tt_tok`, even though it won't happen */
        match r.cur.readme[r.cur.idx] {
          tt_delim(copy tts) => {
            r.cur = @mut TtFrame {
                readme: tts,
                idx: 0u,
                dotdotdoted: false,
                sep: None,
                up: option::Some(r.cur)
            };
            // if this could be 0-length, we'd need to potentially recur here
          }
          tt_tok(sp, copy tok) => {
            r.cur_span = sp; r.cur_tok = tok;
            r.cur.idx += 1u;
            return ret_val;
          }
          tt_seq(sp, copy tts, copy sep, zerok) => {
            match lockstep_iter_size(tt_seq(sp, tts, sep, zerok), r) {
              lis_unconstrained => {
                r.sp_diag.span_fatal(
                    sp, /* blame macro writer */
                      ~"attempted to repeat an expression \
                        containing no syntax \
                        variables matched as repeating at this depth");
                  }
                  lis_contradiction(ref msg) => {
                      /* FIXME #2887 blame macro invoker instead*/
                      r.sp_diag.span_fatal(sp, (*msg));
                  }
                  lis_constraint(len, _) => {
                    if len == 0 {
                      if !zerok {
                        r.sp_diag.span_fatal(sp, /* FIXME #2887 blame invoker
                        */
                                             ~"this must repeat at least \
                                               once");
                          }

                    r.cur.idx += 1u;
                    return tt_next_token(r);
                } else {
                    r.repeat_len.push(len);
                    r.repeat_idx.push(0u);
                    r.cur = @mut TtFrame {
                        readme: tts,
                        idx: 0u,
                        dotdotdoted: true,
                        sep: sep,
                        up: option::Some(r.cur)
                    };
                }
              }
            }
          }
          // FIXME #2887: think about span stuff here
          tt_nonterminal(sp, ident) => {
            match *lookup_cur_matched(r, ident) {
              /* sidestep the interpolation tricks for ident because
              (a) idents can be in lots of places, so it'd be a pain
              (b) we actually can, since it's a token. */
              matched_nonterminal(nt_ident(sn,b)) => {
                r.cur_span = sp; r.cur_tok = IDENT(sn,b);
                r.cur.idx += 1u;
                return ret_val;
              }
              matched_nonterminal(ref other_whole_nt) => {
                r.cur_span = sp; r.cur_tok = INTERPOLATED((*other_whole_nt));
                r.cur.idx += 1u;
                return ret_val;
              }
              matched_seq(*) => {
                r.sp_diag.span_fatal(
                    copy r.cur_span, /* blame the macro writer */
                    fmt!("variable '%s' is still repeating at this depth",
                         *r.interner.get(ident)));
              }
            }
          }
        }
    }

}
<commit_msg>@mut fix<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use core::prelude::*;

use ast;
use ast::{token_tree, tt_delim, tt_tok, tt_seq, tt_nonterminal,ident};
use ast_util;
use codemap::{span, dummy_sp};
use diagnostic::span_handler;
use ext::tt::macro_parser::{named_match, matched_seq, matched_nonterminal};
use parse::token::{EOF, INTERPOLATED, IDENT, Token, nt_ident, ident_interner};
use parse::lexer::TokenAndSpan;

use core::option;
use core::vec;
use std;
use std::oldmap::HashMap;

/* FIXME #2811: figure out how to have a uniquely linked stack, and change to
   `~` */
///an unzipping of `token_tree`s
struct TtFrame {
    readme: ~[ast::token_tree],
    idx: uint,
    dotdotdoted: bool,
    sep: Option<Token>,
    up: Option<@mut TtFrame>,
}

pub struct TtReader {
    sp_diag: span_handler,
    interner: @ident_interner,
    cur: @mut TtFrame,
    /* for MBE-style macro transcription */
    interpolations: std::oldmap::HashMap<ident, @named_match>,
    repeat_idx: ~[uint],
    repeat_len: ~[uint],
    /* cached: */
    cur_tok: Token,
    cur_span: span
}

/** This can do Macro-By-Example transcription. On the other hand, if
 *  `src` contains no `tt_seq`s and `tt_nonterminal`s, `interp` can (and
 *  should) be none. */
pub fn new_tt_reader(sp_diag: span_handler,
                     itr: @ident_interner,
                     interp: Option<std::oldmap::HashMap<ident,@named_match>>,
                     src: ~[ast::token_tree])
                  -> @mut TtReader {
    let r = @mut TtReader {
        sp_diag: sp_diag,
        interner: itr,
        mut cur: @mut TtFrame {
            readme: src,
            idx: 0u,
            dotdotdoted: false,
            sep: None,
            up: option::None
        },
        interpolations: match interp { /* just a convienience */
            None => std::oldmap::HashMap(),
            Some(x) => x
        },
        repeat_idx: ~[],
        repeat_len: ~[],
        /* dummy values, never read: */
        cur_tok: EOF,
        cur_span: dummy_sp()
    };
    tt_next_token(r); /* get cur_tok and cur_span set up */
    return r;
}

pure fn dup_tt_frame(f: @mut TtFrame) -> @mut TtFrame {
    @mut TtFrame {
        readme: f.readme,
        idx: f.idx,
        dotdotdoted: f.dotdotdoted,
        sep: f.sep,
        up: match f.up {
            Some(up_frame) => Some(dup_tt_frame(up_frame)),
            None => None
        }
    }
}

pub pure fn dup_tt_reader(r: @mut TtReader) -> @mut TtReader {
    @mut TtReader {
        sp_diag: r.sp_diag,
        interner: r.interner,
        cur: dup_tt_frame(r.cur),
        interpolations: r.interpolations,
        repeat_idx: copy r.repeat_idx,
        repeat_len: copy r.repeat_len,
        cur_tok: r.cur_tok,
        cur_span: r.cur_span
    }
}

pure fn lookup_cur_matched_by_matched(r: @mut TtReader,
                                      start: @named_match) -> @named_match {
    pure fn red(+ad: @named_match, idx: &uint) -> @named_match {
        match *ad {
          matched_nonterminal(_) => {
            // end of the line; duplicate henceforth
            ad
          }
          matched_seq(ads, _) => ads[*idx]
        }
    }
    vec::foldl(start, r.repeat_idx, red)
}

fn lookup_cur_matched(r: @mut TtReader, name: ident) -> @named_match {
    lookup_cur_matched_by_matched(r, r.interpolations.get(&name))
}
enum lis {
    lis_unconstrained, lis_constraint(uint, ident), lis_contradiction(~str)
}

fn lockstep_iter_size(t: token_tree, r: @mut TtReader) -> lis {
    fn lis_merge(lhs: lis, rhs: lis, r: @mut TtReader) -> lis {
        match lhs {
          lis_unconstrained => rhs,
          lis_contradiction(_) => lhs,
          lis_constraint(l_len, l_id) => match rhs {
            lis_unconstrained => lhs,
            lis_contradiction(_) => rhs,
            lis_constraint(r_len, _) if l_len == r_len => lhs,
            lis_constraint(r_len, r_id) => {
                let l_n = *r.interner.get(l_id);
                let r_n = *r.interner.get(r_id);
                lis_contradiction(fmt!("Inconsistent lockstep iteration: \
                                       '%s' has %u items, but '%s' has %u",
                                        l_n, l_len, r_n, r_len))
            }
          }
        }
    }
    match t {
      tt_delim(ref tts) | tt_seq(_, ref tts, _, _) => {
        vec::foldl(lis_unconstrained, (*tts), |lis, tt|
            lis_merge(lis, lockstep_iter_size(*tt, r), r))
      }
      tt_tok(*) => lis_unconstrained,
      tt_nonterminal(_, name) => match *lookup_cur_matched(r, name) {
        matched_nonterminal(_) => lis_unconstrained,
        matched_seq(ads, _) => lis_constraint(ads.len(), name)
      }
    }
}

pub fn tt_next_token(r: @mut TtReader) -> TokenAndSpan {
    let ret_val = TokenAndSpan { tok: r.cur_tok, sp: r.cur_span };
    while r.cur.idx >= r.cur.readme.len() {
        /* done with this set; pop or repeat? */
        if ! r.cur.dotdotdoted
            || r.repeat_idx.last() == r.repeat_len.last() - 1 {

            match r.cur.up {
              None => {
                r.cur_tok = EOF;
                return ret_val;
              }
              Some(tt_f) => {
                if r.cur.dotdotdoted {
                    r.repeat_idx.pop();
                    r.repeat_len.pop();
                }

                r.cur = tt_f;
                r.cur.idx += 1u;
              }
            }

        } else { /* repeat */
            r.cur.idx = 0u;
            r.repeat_idx[r.repeat_idx.len() - 1u] += 1u;
            match r.cur.sep {
              Some(tk) => {
                r.cur_tok = tk; /* repeat same span, I guess */
                return ret_val;
              }
              None => ()
            }
        }
    }
    loop { /* because it's easiest, this handles `tt_delim` not starting
    with a `tt_tok`, even though it won't happen */
        match r.cur.readme[r.cur.idx] {
          tt_delim(copy tts) => {
            r.cur = @mut TtFrame {
                readme: tts,
                idx: 0u,
                dotdotdoted: false,
                sep: None,
                up: option::Some(r.cur)
            };
            // if this could be 0-length, we'd need to potentially recur here
          }
          tt_tok(sp, copy tok) => {
            r.cur_span = sp; r.cur_tok = tok;
            r.cur.idx += 1u;
            return ret_val;
          }
          tt_seq(sp, copy tts, copy sep, zerok) => {
            match lockstep_iter_size(tt_seq(sp, tts, sep, zerok), r) {
              lis_unconstrained => {
                r.sp_diag.span_fatal(
                    sp, /* blame macro writer */
                      ~"attempted to repeat an expression \
                        containing no syntax \
                        variables matched as repeating at this depth");
                  }
                  lis_contradiction(ref msg) => {
                      /* FIXME #2887 blame macro invoker instead*/
                      r.sp_diag.span_fatal(sp, (*msg));
                  }
                  lis_constraint(len, _) => {
                    if len == 0 {
                      if !zerok {
                        r.sp_diag.span_fatal(sp, /* FIXME #2887 blame invoker
                        */
                                             ~"this must repeat at least \
                                               once");
                          }

                    r.cur.idx += 1u;
                    return tt_next_token(r);
                } else {
                    r.repeat_len.push(len);
                    r.repeat_idx.push(0u);
                    r.cur = @mut TtFrame {
                        readme: tts,
                        idx: 0u,
                        dotdotdoted: true,
                        sep: sep,
                        up: option::Some(r.cur)
                    };
                }
              }
            }
          }
          // FIXME #2887: think about span stuff here
          tt_nonterminal(sp, ident) => {
            match *lookup_cur_matched(r, ident) {
              /* sidestep the interpolation tricks for ident because
              (a) idents can be in lots of places, so it'd be a pain
              (b) we actually can, since it's a token. */
              matched_nonterminal(nt_ident(sn,b)) => {
                r.cur_span = sp; r.cur_tok = IDENT(sn,b);
                r.cur.idx += 1u;
                return ret_val;
              }
              matched_nonterminal(ref other_whole_nt) => {
                r.cur_span = sp; r.cur_tok = INTERPOLATED((*other_whole_nt));
                r.cur.idx += 1u;
                return ret_val;
              }
              matched_seq(*) => {
                r.sp_diag.span_fatal(
                    copy r.cur_span, /* blame the macro writer */
                    fmt!("variable '%s' is still repeating at this depth",
                         *r.interner.get(ident)));
              }
            }
          }
        }
    }

}
<|endoftext|>


<commit_before>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use spec::{LinkerFlavor, Target, TargetOptions, TargetResult, PanicStrategy};

pub fn target() -> TargetResult {
    let mut base = super::windows_msvc_base::opts();

    base.pre_link_args.get_mut(&LinkerFlavor::Msvc).unwrap().push(
        "/LIBPATH:C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Enterprise\\VC\\Tools\\MSVC\\14.11.25503\\lib\\arm".to_string());

    base.pre_link_args.get_mut(&LinkerFlavor::Msvc).unwrap().push(
        "/LIBPATH:C:\\Program Files (x86)\\Windows Kits\\10\\lib\\10.0.17134.0\\ucrt\\arm".to_string());

    base.pre_link_args.get_mut(&LinkerFlavor::Msvc).unwrap().push(
        "/LIBPATH:C:\\Program Files (x86)\\Windows Kits\\10\\lib\\10.0.17134.0\\um\\arm".to_string());

    base.pre_link_args.get_mut(&LinkerFlavor::Msvc).unwrap().push(
        "/MACHINE:ARM".to_string());

    base.pre_link_args.get_mut(&LinkerFlavor::Msvc).unwrap().push(
        "/INCREMENTAL:NO".to_string());

    // Prevent error LNK2013: BRANCH24(T) fixup overflow
    base.pre_link_args.get_mut(&LinkerFlavor::Msvc).unwrap().push(
        "/OPT:NOLBR".to_string());

    base.panic_strategy = PanicStrategy::Abort;

    Ok(Target {
        llvm_target: "thumbv7a-pc-windows-msvc".to_string(),
        target_endian: "little".to_string(),
        target_pointer_width: "32".to_string(),
        target_c_int_width: "32".to_string(),
        data_layout: "e-m:w-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
        arch: "arm".to_string(),
        target_os: "windows".to_string(),
        target_env: "msvc".to_string(),
        target_vendor: "pc".to_string(),
        linker_flavor: LinkerFlavor::Msvc,

        options: TargetOptions {
            features: "+v7,+thumb-mode,+vfp3,+d16,+thumb2,+neon".to_string(),
            cpu: "generic".to_string(),
            max_atomic_width: Some(64),
            abi_blacklist: super::arm_base::abi_blacklist(),
            .. base
        }
    })
}
<commit_msg>Removed hardcoded paths and unnecessary LLVM features<commit_after>// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use spec::{LinkerFlavor, Target, TargetOptions, TargetResult, PanicStrategy};

pub fn target() -> TargetResult {
    let mut base = super::windows_msvc_base::opts();

    // Prevent error LNK2013: BRANCH24(T) fixup overflow
    base.pre_link_args.get_mut(&LinkerFlavor::Msvc).unwrap().push(
        "/OPT:NOLBR".to_string());

    base.panic_strategy = PanicStrategy::Abort;

    Ok(Target {
        llvm_target: "thumbv7a-pc-windows-msvc".to_string(),
        target_endian: "little".to_string(),
        target_pointer_width: "32".to_string(),
        target_c_int_width: "32".to_string(),
        data_layout: "e-m:w-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
        arch: "arm".to_string(),
        target_os: "windows".to_string(),
        target_env: "msvc".to_string(),
        target_vendor: "pc".to_string(),
        linker_flavor: LinkerFlavor::Msvc,

        options: TargetOptions {
            features: "+vfp3,+neon".to_string(),
            cpu: "generic".to_string(),
            max_atomic_width: Some(64),
            abi_blacklist: super::arm_base::abi_blacklist(),
            .. base
        }
    })
}
<|endoftext|>


<commit_before><commit_msg>Problem 49<commit_after>fn gray(n: uint) -> ~[~str] {
    match n {
        0 => ~[],
        1 => ~[~"0", ~"1"],
        _ => {
            let prev = gray(n-1);
            let zero = prev.iter().map(|s| (~"0").append(*s));
            let one = prev.rev_iter().map(|s| (~"1").append(*s));
            zero.chain(one).collect()
        }
    }
}

fn main() {
    assert!(gray(1) == ~[~"0", ~"1"]);
    assert!(gray(2) == ~[~"00", ~"01", ~"11", ~"10"]);
    assert!(gray(3) == ~[~"000", ~"001", ~"011", ~"010", ~"110", ~"111", ~"101", ~"100"]);
}
<|endoftext|>


<commit_before><commit_msg>Handle cases where two consecutive stations have the same time.<commit_after><|endoftext|>


<commit_before><commit_msg>xfail-pretty reexport-star<commit_after><|endoftext|>


<commit_before><commit_msg>Loads of changes to model code<commit_after><|endoftext|>


<commit_before><commit_msg>fixes the bitrig d_namlen compile error<commit_after><|endoftext|>


<commit_before>iface to_str { fn to_str() -> str; }

impl of to_str for int {
    fn to_str() -> str { int::str(self) }
}
impl of to_str for uint {
    fn to_str() -> str { uint::str(self) }
}
impl of to_str for u8 {
    fn to_str() -> str { uint::str(self as uint) }
}
impl of to_str for float {
    fn to_str() -> str { float::to_str(self, 4u) }
}
impl of to_str for bool {
    fn to_str() -> str { bool::to_str(self) }
}
impl of to_str for () {
    fn to_str() -> str { "()" }
}
impl of to_str for str {
    fn to_str() -> str { self }
}

impl <A: to_str copy, B: to_str copy> of to_str for (A, B) {
    fn to_str() -> str {
        let (a, b) = self;
        "(" + a.to_str() + ", " + b.to_str() + ")"
    }
}
impl <A: to_str copy, B: to_str copy, C: to_str copy> of to_str for (A, B, C){
    fn to_str() -> str {
        let (a, b, c) = self;
        "(" + a.to_str() + ", " + b.to_str() + ", " + c.to_str() + ")"
    }
}

impl <A: to_str> of to_str for [A] {
    fn to_str() -> str {
        let mut acc = "[", first = true;
        for vec::each(self) {|elt|
            if first { first = false; }
            else { acc += ", "; }
            acc += elt.to_str();
        }
        acc += "]";
        acc
    }
}

impl <A: to_str> of to_str for @A {
    fn to_str() -> str { "@" + (*self).to_str() }
}
impl <A: to_str> of to_str for ~A {
    fn to_str() -> str { "~" + (*self).to_str() }
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_simple_types() {
        assert 1.to_str() == "1";
        assert (-1).to_str() == "-1";
        assert 200u.to_str() == "200";
        assert 2u8.to_str() == "2";
        assert true.to_str() == "true";
        assert false.to_str() == "false";
        assert ().to_str() == "()";
        assert "hi".to_str() == "hi";
    }

    #[test]
    fn test_tuple_types() {
        assert (1, 2).to_str() == "(1, 2)";
        assert ("a", "b", false).to_str() == "(a, b, false)";
        assert ((), ((), 100)).to_str() == "((), ((), 100))";
    }

    fn test_vectors() {
        let x: [int] = [];
        assert x.to_str() == "[]";
        assert [1].to_str() == "[1]";
        assert [1, 2, 3].to_str() == "[1, 2, 3]";
        assert [[], [1], [1, 1]].to_str() == "[[], [1], [1, 1]]";
    }

    fn test_pointer_types() {
        assert (@1).to_str() == "@1";
        assert (~(true, false)).to_str() == "~(true, false)";
    }
}
<commit_msg>core: Add to_str impls for remaining int types<commit_after>iface to_str { fn to_str() -> str; }

impl of to_str for i8 {
    fn to_str() -> str { i8::str(self) }
}
impl of to_str for i16 {
    fn to_str() -> str { i16::str(self) }
}
impl of to_str for i32 {
    fn to_str() -> str { i32::str(self) }
}
impl of to_str for i64 {
    fn to_str() -> str { i64::str(self) }
}
impl of to_str for u8 {
    fn to_str() -> str { u8::str(self) }
}
impl of to_str for u16 {
    fn to_str() -> str { u16::str(self) }
}
impl of to_str for u32 {
    fn to_str() -> str { u32::str(self) }
}
impl of to_str for u64 {
    fn to_str() -> str { u64::str(self) }
}
impl of to_str for float {
    fn to_str() -> str { float::to_str(self, 4u) }
}
impl of to_str for bool {
    fn to_str() -> str { bool::to_str(self) }
}
impl of to_str for () {
    fn to_str() -> str { "()" }
}
impl of to_str for str {
    fn to_str() -> str { self }
}

impl <A: to_str copy, B: to_str copy> of to_str for (A, B) {
    fn to_str() -> str {
        let (a, b) = self;
        "(" + a.to_str() + ", " + b.to_str() + ")"
    }
}
impl <A: to_str copy, B: to_str copy, C: to_str copy> of to_str for (A, B, C){
    fn to_str() -> str {
        let (a, b, c) = self;
        "(" + a.to_str() + ", " + b.to_str() + ", " + c.to_str() + ")"
    }
}

impl <A: to_str> of to_str for [A] {
    fn to_str() -> str {
        let mut acc = "[", first = true;
        for vec::each(self) {|elt|
            if first { first = false; }
            else { acc += ", "; }
            acc += elt.to_str();
        }
        acc += "]";
        acc
    }
}

impl <A: to_str> of to_str for @A {
    fn to_str() -> str { "@" + (*self).to_str() }
}
impl <A: to_str> of to_str for ~A {
    fn to_str() -> str { "~" + (*self).to_str() }
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_simple_types() {
        assert 1.to_str() == "1";
        assert (-1).to_str() == "-1";
        assert 200u.to_str() == "200";
        assert 2u8.to_str() == "2";
        assert true.to_str() == "true";
        assert false.to_str() == "false";
        assert ().to_str() == "()";
        assert "hi".to_str() == "hi";
    }

    #[test]
    fn test_tuple_types() {
        assert (1, 2).to_str() == "(1, 2)";
        assert ("a", "b", false).to_str() == "(a, b, false)";
        assert ((), ((), 100)).to_str() == "((), ((), 100))";
    }

    fn test_vectors() {
        let x: [int] = [];
        assert x.to_str() == "[]";
        assert [1].to_str() == "[1]";
        assert [1, 2, 3].to_str() == "[1, 2, 3]";
        assert [[], [1], [1, 1]].to_str() == "[[], [1], [1, 1]]";
    }

    fn test_pointer_types() {
        assert (@1).to_str() == "@1";
        assert (~(true, false)).to_str() == "~(true, false)";
    }
}
<|endoftext|>