<commit_before>//! Interprets the terminal events we care about:
//!
//!   - Resize events.
//!   - Keyboard input.
//!
//! Resize events are handled by registering a signal handler for SIGWINCH.
//!
//! Keyboard events are read from stdin. We look for byte strings of key combinations that we care
//! about. E.g. Alt-arrow keys, C-w etc.

#![feature(const_fn)]

extern crate libc;
extern crate nix;

use nix::sys::signal::{sigaction, Signal, SigAction, SigHandler, SigSet};
use nix::sys::signal;

use std::char;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering;

////////////////////////////////////////////////////////////////////////////////////////////////////
// Public types
////////////////////////////////////////////////////////////////////////////////////////////////////

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Key {
    AltArrow(Arrow),
    Arrow(Arrow),
    Ctrl(char),
    Char(char),
    Esc,
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Arrow { Left, Right, Up, Down }

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Event {
    /// A single key input.
    Key(Key),

    /// Usually a paste.
    String(String),

    /// SIGWINCH happened.
    Resize,

    /// An unknown sequence of bytes (probably for a key combination that we don't care about).
    Unknown(Vec<u8>),
}

pub struct Input {
    /// Used when reading from stdin.
    buf: Vec<u8>,
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// SIGWINCH handler
////////////////////////////////////////////////////////////////////////////////////////////////////

static GOT_SIGWINCH : AtomicBool = AtomicBool::new(false);

extern fn sigwinch_handler(_: libc::c_int) {
    GOT_SIGWINCH.store(true, Ordering::Relaxed);
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Byte sequences of key pressed we want to capture
// (TODO: We only support xterm for now)
////////////////////////////////////////////////////////////////////////////////////////////////////

static XTERM_ALT_ARROW_LEFT  : [u8; 6] = [27, 91, 49, 59, 51, 68];
static XTERM_ALT_ARROW_RIGHT : [u8; 6] = [27, 91, 49, 59, 51, 67];
static XTERM_ALT_ARROW_UP    : [u8; 6] = [27, 91, 49, 59, 51, 65];
static XTERM_ALT_ARROW_DOWN  : [u8; 6] = [27, 91, 49, 59, 51, 66];
static XTERM_ARROW_LEFT      : [u8; 3] = [27, 91, 68];
static XTERM_ARROW_RIGHT     : [u8; 3] = [27, 91, 67];
static XTERM_ARROW_UP        : [u8; 3] = [27, 91, 65];
static XTERM_ARROW_DOWN      : [u8; 3] = [27, 91, 66];

static XTERM_KEY_SEQS : [(&[u8], Event); 8] =
    [ (&XTERM_ALT_ARROW_LEFT,  Event::Key(Key::AltArrow(Arrow::Left))),
      (&XTERM_ALT_ARROW_RIGHT, Event::Key(Key::AltArrow(Arrow::Right))),
      (&XTERM_ALT_ARROW_UP,    Event::Key(Key::AltArrow(Arrow::Up))),
      (&XTERM_ALT_ARROW_DOWN,  Event::Key(Key::AltArrow(Arrow::Down))),
      (&XTERM_ARROW_LEFT,      Event::Key(Key::Arrow(Arrow::Left))),
      (&XTERM_ARROW_RIGHT,     Event::Key(Key::Arrow(Arrow::Right))),
      (&XTERM_ARROW_UP,        Event::Key(Key::Arrow(Arrow::Up))),
      (&XTERM_ARROW_DOWN,      Event::Key(Key::Arrow(Arrow::Down))),
    ];

// Make sure not to use 27 (ESC) because it's used as a prefix in many combinations.
static XTERM_SINGLE_BYTES : [(u8, Event); 5] =
    [ (1,  Event::Key(Key::Ctrl('a'))),
      (5,  Event::Key(Key::Ctrl('e'))),
      (23, Event::Key(Key::Ctrl('w'))),
      (11, Event::Key(Key::Ctrl('k'))),
      (4,  Event::Key(Key::Ctrl('d'))),
    ];

////////////////////////////////////////////////////////////////////////////////////////////////////

impl Input {
    pub fn new() -> Input {
        unsafe {
            // ignore the existing handler
            sigaction(Signal::SIGWINCH, &SigAction::new(SigHandler::Handler(sigwinch_handler),
                                                        signal::SA_RESTART,
                                                        SigSet::empty())).unwrap();
        }

        Input {
            buf: Vec::with_capacity(100),
        }
    }

    pub fn read_input_events(&mut self, evs: &mut Vec<Event>) {
        evs.clear();

        if GOT_SIGWINCH.swap(false, Ordering::Relaxed) {
            evs.push(Event::Resize);
        }

        if read_stdin(&mut self.buf) {

            let mut buf_slice : &[u8] = &self.buf;

            // read_stdin() returned true, there should be at least one character in the buffer
            debug_assert!(!buf_slice.is_empty());

            while !buf_slice.is_empty() {
                let read_fn = if buf_slice[0] <= 27 {
                    println!("key comb");
                    read_key_comb
                } else {
                    read_chars
                };

                match read_fn(buf_slice, evs) {
                    Some(buf_slice_) => {
                        buf_slice = buf_slice_;
                    },
                    None => {
                        evs.push(Event::Unknown(buf_slice.to_owned()));
                        break;
                    }
                }
            }
        }
    }
}

fn read_chars<'a>(mut buf_slice: &'a [u8], evs: &mut Vec<Event>) -> Option<&'a [u8]> {
    debug_assert!(!buf_slice.is_empty());

    // Use a fast path for the common case: Single utf-8 character.
    // (TODO: What about other encodings?)

    utf8_char_len(buf_slice[0]).map(|char_len| {
        if char_len as usize == buf_slice.len() {
            // fast path: single character
            evs.push(Event::Key(Key::Char(get_utf8_char(buf_slice, char_len))));
            &buf_slice[char_len as usize ..]
        } else {
            // probably a paste: allocate a string and collect chars
            let mut string = String::with_capacity(10);
            loop {
                if buf_slice.is_empty() { break; }
                match utf8_char_len(buf_slice[0]) {
                    Some(char_len) => {
                        string.push(get_utf8_char(buf_slice, char_len));
                        buf_slice = &buf_slice[char_len as usize ..];
                    },
                    None => { break; }
                }
            }
            evs.push(Event::String(string));
            return buf_slice;
        }
    })
}

fn read_key_comb<'a>(buf_slice: &'a [u8], evs: &mut Vec<Event>) -> Option<&'a [u8]> {
    debug_assert!(!buf_slice.is_empty());

    // TODO: This is not working, see https://github.com/rust-lang/rust/issues/36401
    for &(byte, ref ev) in XTERM_SINGLE_BYTES.iter() {
        if byte == buf_slice[0] {
            evs.push(ev.clone());
            return Some(&buf_slice[1 ..]);
        }
    }

    for &(byte_seq, ref ev) in XTERM_KEY_SEQS.iter() {
        if buf_slice.starts_with(byte_seq) {
            evs.push(ev.clone());
            return Some(&buf_slice[byte_seq.len() ..]);
        }
    }

    // as a special case, 27 (ESC) not followed by anything is an actual ESC
    if buf_slice == &[27] {
        evs.push(Event::Key(Key::Esc));
        return Some(&buf_slice[1 ..]);
    }

    None
}

fn utf8_char_len(byte: u8) -> Option<u8> {
    if      byte >> 7 == 0b0     { Some(1) }
    else if byte >> 5 == 0b110   { Some(2) }
    else if byte >> 4 == 0b1110  { Some(3) }
    else if byte >> 3 == 0b11110 { Some(4) }
    else                         { None    }
}

fn get_utf8_char(buf: &[u8], len: u8) -> char {
    let codepoint : u32 = {
        if len == 1 {
            (buf[0] & 0b0111_1111) as u32
        } else if len == 2 {
            (((buf[0] & 0b0001_1111) as u32) << 6) +
             ((buf[1] & 0b0011_1111) as u32)
        } else if len == 3 {
            (((buf[0] & 0b0000_1111) as u32) << 12) +
            (((buf[1] & 0b0011_1111) as u32) <<  6) +
             ((buf[2] & 0b0011_1111) as u32)
        } else {
            debug_assert!(len == 4);
            (((buf[0] & 0b0000_0111) as u32) << 18) +
            (((buf[1] & 0b0011_1111) as u32) << 12) +
            (((buf[2] & 0b0011_1111) as u32) <<  6) +
             ((buf[3] & 0b0011_1111) as u32)
        }
    };

    char::from_u32(codepoint).unwrap()
}

/// Read stdin contents if it's ready for reading. Returns true when it was able to read. Buffer is
/// not modified when return value is 0.
pub fn read_stdin(buf : &mut Vec<u8>) -> bool {
    let mut bytes_available : i32 = 0; // this really needs to be a 32-bit value
    let ioctl_ret = unsafe { libc::ioctl(libc::STDIN_FILENO, libc::FIONREAD, &mut bytes_available) };
    // println!("ioctl_ret: {}", ioctl_ret);
    // println!("bytes_available: {}", bytes_available);
    if ioctl_ret < 0 || bytes_available == 0 {
        false
    } else {
        buf.clear();
        buf.reserve(bytes_available as usize);

        let buf_ptr : *mut libc::c_void = buf.as_ptr() as *mut libc::c_void;
        let bytes_read = unsafe { libc::read(libc::STDIN_FILENO, buf_ptr, bytes_available as usize) };
        debug_assert!(bytes_read == bytes_available as isize);

        unsafe { buf.set_len(bytes_read as usize); }
        true
    }
}
<commit_msg>Revert to an older Rust nightly that can compile this<commit_after>//! Interprets the terminal events we care about:
//!
//!   - Resize events.
//!   - Keyboard input.
//!
//! Resize events are handled by registering a signal handler for SIGWINCH.
//!
//! Keyboard events are read from stdin. We look for byte strings of key combinations that we care
//! about. E.g. Alt-arrow keys, C-w etc.

#![feature(const_fn)]

extern crate libc;
extern crate nix;

use nix::sys::signal::{sigaction, Signal, SigAction, SigHandler, SigSet};
use nix::sys::signal;

use std::char;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering;

////////////////////////////////////////////////////////////////////////////////////////////////////
// Public types
////////////////////////////////////////////////////////////////////////////////////////////////////

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Key {
    AltArrow(Arrow),
    Arrow(Arrow),
    Ctrl(char),
    Char(char),
    Esc,
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Arrow { Left, Right, Up, Down }

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Event {
    /// A single key input.
    Key(Key),

    /// Usually a paste.
    String(String),

    /// SIGWINCH happened.
    Resize,

    /// An unknown sequence of bytes (probably for a key combination that we don't care about).
    Unknown(Vec<u8>),
}

pub struct Input {
    /// Used when reading from stdin.
    buf: Vec<u8>,
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// SIGWINCH handler
////////////////////////////////////////////////////////////////////////////////////////////////////

static GOT_SIGWINCH : AtomicBool = AtomicBool::new(false);

extern fn sigwinch_handler(_: libc::c_int) {
    GOT_SIGWINCH.store(true, Ordering::Relaxed);
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Byte sequences of key pressed we want to capture
// (TODO: We only support xterm for now)
////////////////////////////////////////////////////////////////////////////////////////////////////

static XTERM_ALT_ARROW_LEFT  : [u8; 6] = [27, 91, 49, 59, 51, 68];
static XTERM_ALT_ARROW_RIGHT : [u8; 6] = [27, 91, 49, 59, 51, 67];
static XTERM_ALT_ARROW_UP    : [u8; 6] = [27, 91, 49, 59, 51, 65];
static XTERM_ALT_ARROW_DOWN  : [u8; 6] = [27, 91, 49, 59, 51, 66];
static XTERM_ARROW_LEFT      : [u8; 3] = [27, 91, 68];
static XTERM_ARROW_RIGHT     : [u8; 3] = [27, 91, 67];
static XTERM_ARROW_UP        : [u8; 3] = [27, 91, 65];
static XTERM_ARROW_DOWN      : [u8; 3] = [27, 91, 66];

static XTERM_KEY_SEQS : [(&'static [u8], Event); 8] =
    [ (&XTERM_ALT_ARROW_LEFT,  Event::Key(Key::AltArrow(Arrow::Left))),
      (&XTERM_ALT_ARROW_RIGHT, Event::Key(Key::AltArrow(Arrow::Right))),
      (&XTERM_ALT_ARROW_UP,    Event::Key(Key::AltArrow(Arrow::Up))),
      (&XTERM_ALT_ARROW_DOWN,  Event::Key(Key::AltArrow(Arrow::Down))),
      (&XTERM_ARROW_LEFT,      Event::Key(Key::Arrow(Arrow::Left))),
      (&XTERM_ARROW_RIGHT,     Event::Key(Key::Arrow(Arrow::Right))),
      (&XTERM_ARROW_UP,        Event::Key(Key::Arrow(Arrow::Up))),
      (&XTERM_ARROW_DOWN,      Event::Key(Key::Arrow(Arrow::Down))),
    ];

// Make sure not to use 27 (ESC) because it's used as a prefix in many combinations.
static XTERM_SINGLE_BYTES : [(u8, Event); 5] =
    [ (1,  Event::Key(Key::Ctrl('a'))),
      (5,  Event::Key(Key::Ctrl('e'))),
      (23, Event::Key(Key::Ctrl('w'))),
      (11, Event::Key(Key::Ctrl('k'))),
      (4,  Event::Key(Key::Ctrl('d'))),
    ];

////////////////////////////////////////////////////////////////////////////////////////////////////

impl Input {
    pub fn new() -> Input {
        unsafe {
            // ignore the existing handler
            sigaction(Signal::SIGWINCH, &SigAction::new(SigHandler::Handler(sigwinch_handler),
                                                        signal::SA_RESTART,
                                                        SigSet::empty())).unwrap();
        }

        Input {
            buf: Vec::with_capacity(100),
        }
    }

    pub fn read_input_events(&mut self, evs: &mut Vec<Event>) {
        evs.clear();

        if GOT_SIGWINCH.swap(false, Ordering::Relaxed) {
            evs.push(Event::Resize);
        }

        if read_stdin(&mut self.buf) {

            let mut buf_slice : &[u8] = &self.buf;

            // read_stdin() returned true, there should be at least one character in the buffer
            debug_assert!(!buf_slice.is_empty());

            while !buf_slice.is_empty() {
                let read_fn = if buf_slice[0] <= 27 {
                    read_key_comb
                } else {
                    read_chars
                };

                match read_fn(buf_slice, evs) {
                    Some(buf_slice_) => {
                        buf_slice = buf_slice_;
                    },
                    None => {
                        evs.push(Event::Unknown(buf_slice.to_owned()));
                        break;
                    }
                }
            }
        }
    }
}

fn read_chars<'a>(mut buf_slice: &'a [u8], evs: &mut Vec<Event>) -> Option<&'a [u8]> {
    debug_assert!(!buf_slice.is_empty());

    // Use a fast path for the common case: Single utf-8 character.
    // (TODO: What about other encodings?)

    utf8_char_len(buf_slice[0]).map(|char_len| {
        if char_len as usize == buf_slice.len() {
            // fast path: single character
            evs.push(Event::Key(Key::Char(get_utf8_char(buf_slice, char_len))));
            &buf_slice[char_len as usize ..]
        } else {
            // probably a paste: allocate a string and collect chars
            let mut string = String::with_capacity(10);
            loop {
                if buf_slice.is_empty() { break; }
                match utf8_char_len(buf_slice[0]) {
                    Some(char_len) => {
                        string.push(get_utf8_char(buf_slice, char_len));
                        buf_slice = &buf_slice[char_len as usize ..];
                    },
                    None => { break; }
                }
            }
            evs.push(Event::String(string));
            return buf_slice;
        }
    })
}

fn read_key_comb<'a>(buf_slice: &'a [u8], evs: &mut Vec<Event>) -> Option<&'a [u8]> {
    debug_assert!(!buf_slice.is_empty());

    // TODO: This is not working, see https://github.com/rust-lang/rust/issues/36401
    for &(byte, ref ev) in XTERM_SINGLE_BYTES.iter() {
        if byte == buf_slice[0] {
            evs.push(ev.clone());
            return Some(&buf_slice[1 ..]);
        }
    }

    for &(byte_seq, ref ev) in XTERM_KEY_SEQS.iter() {
        if buf_slice.starts_with(byte_seq) {
            evs.push(ev.clone());
            return Some(&buf_slice[byte_seq.len() ..]);
        }
    }

    // as a special case, 27 (ESC) not followed by anything is an actual ESC
    if buf_slice == &[27] {
        evs.push(Event::Key(Key::Esc));
        return Some(&buf_slice[1 ..]);
    }

    None
}

fn utf8_char_len(byte: u8) -> Option<u8> {
    if      byte >> 7 == 0b0     { Some(1) }
    else if byte >> 5 == 0b110   { Some(2) }
    else if byte >> 4 == 0b1110  { Some(3) }
    else if byte >> 3 == 0b11110 { Some(4) }
    else                         { None    }
}

fn get_utf8_char(buf: &[u8], len: u8) -> char {
    let codepoint : u32 = {
        if len == 1 {
            (buf[0] & 0b0111_1111) as u32
        } else if len == 2 {
            (((buf[0] & 0b0001_1111) as u32) << 6) +
             ((buf[1] & 0b0011_1111) as u32)
        } else if len == 3 {
            (((buf[0] & 0b0000_1111) as u32) << 12) +
            (((buf[1] & 0b0011_1111) as u32) <<  6) +
             ((buf[2] & 0b0011_1111) as u32)
        } else {
            debug_assert!(len == 4);
            (((buf[0] & 0b0000_0111) as u32) << 18) +
            (((buf[1] & 0b0011_1111) as u32) << 12) +
            (((buf[2] & 0b0011_1111) as u32) <<  6) +
             ((buf[3] & 0b0011_1111) as u32)
        }
    };

    char::from_u32(codepoint).unwrap()
}

/// Read stdin contents if it's ready for reading. Returns true when it was able to read. Buffer is
/// not modified when return value is 0.
pub fn read_stdin(buf : &mut Vec<u8>) -> bool {
    let mut bytes_available : i32 = 0; // this really needs to be a 32-bit value
    let ioctl_ret = unsafe { libc::ioctl(libc::STDIN_FILENO, libc::FIONREAD, &mut bytes_available) };
    // println!("ioctl_ret: {}", ioctl_ret);
    // println!("bytes_available: {}", bytes_available);
    if ioctl_ret < 0 || bytes_available == 0 {
        false
    } else {
        buf.clear();
        buf.reserve(bytes_available as usize);

        let buf_ptr : *mut libc::c_void = buf.as_ptr() as *mut libc::c_void;
        let bytes_read = unsafe { libc::read(libc::STDIN_FILENO, buf_ptr, bytes_available as usize) };
        debug_assert!(bytes_read == bytes_available as isize);

        unsafe { buf.set_len(bytes_read as usize); }
        true
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate lazy_static;
extern crate quickcheck;
extern crate fail;
extern crate rand;
extern crate sled;
extern crate pagecache;
extern crate tests;

use std::collections::{BTreeMap, HashSet};
use std::sync::Mutex;

use quickcheck::{Arbitrary, Gen, QuickCheck, StdGen};

use sled::*;

#[derive(Debug, Clone)]
enum Op {
    Set,
    Del(u8),
    Restart,
    FailPoint(&'static str),
}

use Op::*;

impl Arbitrary for Op {
    fn arbitrary<G: Gen>(g: &mut G) -> Op {
        let fail_points = vec![
            "initial allocation",
            "initial allocation post",
            "zero segment",
            "zero segment post",
            "zero garbage segment",
            "zero garbage segment post",
            "buffer write",
            "buffer write post",
            "write_config bytes",
            "write_config crc",
            "write_config post",
            "trailer write",
            "trailer write post",
            "snap write",
            "snap write len",
            "snap write crc",
            "snap write post",
            "snap write mv",
            "snap write mv post",
            "snap write rm old",
        ];

        if g.gen_weighted_bool(30) {
            return FailPoint(*g.choose(&fail_points).unwrap());
        }

        if g.gen_weighted_bool(10) {
            return Restart;
        }

        let choice = g.gen_range(0, 2);

        match choice {
            0 => Set,
            1 => Del(g.gen::<u8>()),
            _ => panic!("impossible choice"),
        }
    }

    fn shrink(&self) -> Box<Iterator<Item = Op>> {
        match *self {
            Op::Del(ref lid) if *lid > 0 => Box::new(
                vec![Op::Del(*lid - 1)].into_iter(),
            ),
            _ => Box::new(vec![].into_iter()),
        }
    }
}

fn v(b: &Vec<u8>) -> u16 {
    assert_eq!(b.len(), 2);
    ((b[0] as u16) << 8) + b[1] as u16
}

fn prop_tree_crashes_nicely(ops: Vec<Op>, flusher: bool) -> bool {
    lazy_static! {
        // forces quickcheck to run one thread at a time
        static ref M: Mutex<()> = Mutex::new(());
    }

    let _lock = M.lock().expect("our test lock should not be poisoned");

    // clear all failpoints that may be left over from the last run
    fail::teardown();

    let res = std::panic::catch_unwind(
        || run_tree_crashes_nicely(ops.clone(), flusher),
    );

    fail::teardown();

    match res {
        Err(e) => {
            println!(
                "failed with {:?} on ops {:?} flusher {}",
                e,
                ops,
                flusher
            );
            false
        }
        Ok(res) => {
            if !res {
                println!("failed with ops {:?} flusher: {}", ops, flusher);
            }
            res
        }
    }
}

fn run_tree_crashes_nicely(ops: Vec<Op>, flusher: bool) -> bool {
    let config = ConfigBuilder::new()
        .temporary(true)
        .snapshot_after_ops(1)
        .flush_every_ms(if flusher { Some(1) } else {None})
        .io_buf_size(300)
        .min_items_per_segment(1)
        .blink_fanout(2) // smol pages for smol buffers
        .cache_capacity(40)
        .cache_bits(2)
        .build();

    let mut tree = sled::Tree::start(config.clone()).unwrap();
    let mut reference = BTreeMap::new();
    let mut fail_points = HashSet::new();

    macro_rules! restart {
        () => {
            drop(tree);
            let tree_res = sled::Tree::start(config.clone());
            if let Err(ref e) = tree_res {
                if e == &Error::FailPoint {
                    return true;
                }

                println!("could not start database: {}", e);
                return false;
            }

            tree = tree_res.unwrap();

            let tree_iter = tree.iter().map(|res| {
                let (ref tk, _) = res.unwrap();
                v(tk)
            });
            let mut ref_iter = reference.iter().map(|(ref rk, ref rv)| (**rk, **rv));
            for t in tree_iter {
                // make sure the tree value is in there
                while let Some((r, (_rv, certainty))) = ref_iter.next() {
                    if certainty {
                        // tree MUST match reference if we have a certain reference
                        if t != r {
                            println!("expected to iterate over {:?} but got {:?} instead", r, t);
                            return false;
                        }
                        break;
                    } else {
                        // we have an uncertain reference, so we iterate through
                        // it and guarantee the reference is never higher than
                        // the tree value.
                        if t == r {
                            // we can move on to the next tree item
                            break;
                        }

                        if r > t {
                            // we have a bug, the reference iterator should always be <= tree
                            println!("tree verification failed: expected {:?} got {:?}", r, t);
                            return false;
                        }

                        // we are iterating through the reference until we have a certain
                        // item or an item that matches the tree's real item anyway
                    }
                }
            }
        }
    }

    macro_rules! fp_crash {
        ($e:expr) => {
            match $e {
                Ok(thing) => thing,
                Err(Error::FailPoint) => {
                    fail::teardown();
                    restart!();
                    continue;
                }
                other => {
                    println!("got non-failpoint err: {:?}", other);
                    return false;
                },
            }
        }
    }

    // we always increase set_counter because
    let mut set_counter = 0u16;

    for op in ops.into_iter() {
        match op {
            Set => {
                let hi = (set_counter >> 8) as u8;
                let lo = set_counter as u8;

                // insert false certainty until it fully completes
                reference.insert(set_counter, (set_counter, false));

                fp_crash!(tree.set(vec![hi, lo], vec![hi, lo]));

                // make sure we keep the disk and reference in-sync
                // maybe in the future put pending things in their own
                // reference and have a Flush op that syncs them.
                // just because the set above didn't hit a failpoint,
                // it doesn't mean this flush won't hit one, so we
                // also use the fp_crash macro here for handling it.
                fp_crash!(tree.flush());

                // now we should be certain the thing is in there, set certainty to true
                reference.insert(set_counter, (set_counter, true));

                set_counter += 1;
            }
            Del(k) => {
                // insert false certainty before completes
                reference.insert(k as u16, (k as u16, false));

                fp_crash!(tree.del(&*vec![0, k]));
                tree.flush().unwrap();

                reference.remove(&(k as u16));
            }
            Restart => {
                restart!();
            }
            FailPoint(fp) => {
                fail_points.insert(fp.clone());
                fail::cfg(&*fp, "return").unwrap();
            }
        }
    }

    true
}

#[test]
fn quickcheck_tree_with_failpoints() {
    // use fewer tests for travis OSX builds that stall out all the time
    #[cfg(target_os = "macos")]
    let n_tests = 50;

    #[cfg(not(target_os = "macos"))]
    let n_tests = 100;

    QuickCheck::new()
        .gen(StdGen::new(rand::thread_rng(), 100))
        .tests(n_tests)
        .max_tests(10000)
        .quickcheck(prop_tree_crashes_nicely as fn(Vec<Op>, bool) -> bool);
}

#[test]
fn failpoints_bug_1() {
    // postmortem 1: model did not account for proper reasons to fail to start
    assert!(prop_tree_crashes_nicely(
        vec![FailPoint("snap write"), Restart],
        false,
    ));
}

#[test]
fn failpoints_bug_2() {
    // postmortem 1: the system was assuming the happy path across failpoints
    assert!(prop_tree_crashes_nicely(
        vec![FailPoint("buffer write post"), Set, Set, Restart],
        false,
    ))
}

#[test]
fn failpoints_bug_3() {
    // postmortem 1: this was a regression that happened because we
    // chose to eat errors about advancing snapshots, which trigger
    // log flushes. We should not trigger flushes from snapshots,
    // but first we need to make sure we are better about detecting
    // tears, by not also using 0 as a failed flush signifier.
    assert!(prop_tree_crashes_nicely(
        vec![
            Set,
            Set,
            Set,
            Set,
            FailPoint("trailer write"),
            Set,
            Set,
            Set,
            Set,
            Restart,
        ],
        false,
    ))
}

#[test]
fn failpoints_bug_4() {
    // postmortem 1: the test model was not properly accounting for
    // writes that may-or-may-not be present due to an error.
    assert!(prop_tree_crashes_nicely(
        vec![Set, FailPoint("snap write"), Del(0), Set, Restart],
        false,
    ))
}

#[test]
fn failpoints_bug_5() {
    // postmortem 1:
    assert!(prop_tree_crashes_nicely(
        vec![
            Set,
            FailPoint("snap write mv post"),
            Set,
            FailPoint("snap write"),
            Set,
            Set,
            Set,
            Restart,
            FailPoint("zero segment"),
            Set,
            Set,
            Set,
            Restart,
        ],
        false,
    ))
}

#[test]
fn failpoints_bug_6() {
    // postmortem 1:
    assert!(prop_tree_crashes_nicely(
        vec![
            Set,
            Del(0),
            Set,
            Set,
            Set,
            Restart,
            FailPoint("zero segment post"),
            Set,
            Set,
            Set,
            Restart,
        ],
        false,
    ))
}

#[test]
fn failpoints_bug_7() {
    // postmortem 1: We were crashing because a Segment was
    // in the SegmentAccountant's to_clean Vec, but it had
    // no present pages. This can legitimately happen when
    // a Segment only contains failed log flushes.
    assert!(prop_tree_crashes_nicely(
        vec![
            Set,
            Set,
            Set,
            Set,
            Set,
            Set,
            Set,
            Set,
            Set,
            Set,
            Set,
            Set,
            Set,
            Set,
            Set,
            Set,
            Set,
            Del(17),
            Del(29),
            Del(246),
            Del(248),
            Set,
        ],
        false,
    ))
}
<commit_msg>fix bad expectation with deletion in failpoints where del's did not fail if the underlying item was not actually present<commit_after>#[macro_use]
extern crate lazy_static;
extern crate quickcheck;
extern crate fail;
extern crate rand;
extern crate sled;
extern crate pagecache;
extern crate tests;

use std::collections::{BTreeMap, HashSet};
use std::sync::Mutex;

use quickcheck::{Arbitrary, Gen, QuickCheck, StdGen};

use sled::*;

#[derive(Debug, Clone)]
enum Op {
    Set,
    Del(u8),
    Restart,
    FailPoint(&'static str),
}

use Op::*;

impl Arbitrary for Op {
    fn arbitrary<G: Gen>(g: &mut G) -> Op {
        let fail_points = vec![
            "initial allocation",
            "initial allocation post",
            "zero segment",
            "zero segment post",
            "zero garbage segment",
            "zero garbage segment post",
            "buffer write",
            "buffer write post",
            "write_config bytes",
            "write_config crc",
            "write_config post",
            "trailer write",
            "trailer write post",
            "snap write",
            "snap write len",
            "snap write crc",
            "snap write post",
            "snap write mv",
            "snap write mv post",
            "snap write rm old",
        ];

        if g.gen_weighted_bool(30) {
            return FailPoint(*g.choose(&fail_points).unwrap());
        }

        if g.gen_weighted_bool(10) {
            return Restart;
        }

        let choice = g.gen_range(0, 2);

        match choice {
            0 => Set,
            1 => Del(g.gen::<u8>()),
            _ => panic!("impossible choice"),
        }
    }

    fn shrink(&self) -> Box<Iterator<Item = Op>> {
        match *self {
            Op::Del(ref lid) if *lid > 0 => Box::new(
                vec![Op::Del(*lid - 1)].into_iter(),
            ),
            _ => Box::new(vec![].into_iter()),
        }
    }
}

fn v(b: &Vec<u8>) -> u16 {
    assert_eq!(b.len(), 2);
    ((b[0] as u16) << 8) + b[1] as u16
}

fn prop_tree_crashes_nicely(ops: Vec<Op>, flusher: bool) -> bool {
    lazy_static! {
        // forces quickcheck to run one thread at a time
        static ref M: Mutex<()> = Mutex::new(());
    }

    let _lock = M.lock().expect("our test lock should not be poisoned");

    // clear all failpoints that may be left over from the last run
    fail::teardown();

    let res = std::panic::catch_unwind(
        || run_tree_crashes_nicely(ops.clone(), flusher),
    );

    fail::teardown();

    match res {
        Err(e) => {
            println!(
                "failed with {:?} on ops {:?} flusher {}",
                e,
                ops,
                flusher
            );
            false
        }
        Ok(res) => {
            if !res {
                println!("failed with ops {:?} flusher: {}", ops, flusher);
            }
            res
        }
    }
}

fn run_tree_crashes_nicely(ops: Vec<Op>, flusher: bool) -> bool {
    let config = ConfigBuilder::new()
        .temporary(true)
        .snapshot_after_ops(1)
        .flush_every_ms(if flusher { Some(1) } else {None})
        .io_buf_size(300)
        .min_items_per_segment(1)
        .blink_fanout(2) // smol pages for smol buffers
        .cache_capacity(40)
        .cache_bits(2)
        .build();

    let mut tree =
        sled::Tree::start(config.clone()).expect("tree should start");
    let mut reference = BTreeMap::new();
    let mut fail_points = HashSet::new();

    macro_rules! restart {
        () => {
            drop(tree);
            let tree_res = sled::Tree::start(config.clone());
            if let Err(ref e) = tree_res {
                if e == &Error::FailPoint {
                    return true;
                }

                println!("could not start database: {}", e);
                return false;
            }

            tree = tree_res.expect("tree should restart");

            let tree_iter = tree.iter().map(|res| {
                let (ref tk, _) = res.expect("should be able to iterate over items in tree");
                v(tk)
            });
            let mut ref_iter = reference.iter().map(|(ref rk, ref rv)| (**rk, **rv));
            for t in tree_iter {
                // make sure the tree value is in there
                while let Some((r, (_rv, certainty))) = ref_iter.next() {
                    if certainty {
                        // tree MUST match reference if we have a certain reference
                        if t != r {
                            println!("expected to iterate over {:?} but got {:?} instead", r, t);
                            return false;
                        }
                        break;
                    } else {
                        // we have an uncertain reference, so we iterate through
                        // it and guarantee the reference is never higher than
                        // the tree value.
                        if t == r {
                            // we can move on to the next tree item
                            break;
                        }

                        if r > t {
                            // we have a bug, the reference iterator should always be <= tree
                            println!("tree verification failed: expected {:?} got {:?}", r, t);
                            return false;
                        }

                        // we are iterating through the reference until we have a certain
                        // item or an item that matches the tree's real item anyway
                    }
                }
            }
        }
    }

    macro_rules! fp_crash {
        ($e:expr) => {
            match $e {
                Ok(thing) => thing,
                Err(Error::FailPoint) => {
                    fail::teardown();
                    restart!();
                    continue;
                }
                other => {
                    println!("got non-failpoint err: {:?}", other);
                    return false;
                },
            }
        }
    }

    // we always increase set_counter because
    let mut set_counter = 0u16;

    for op in ops.into_iter() {
        match op {
            Set => {
                let hi = (set_counter >> 8) as u8;
                let lo = set_counter as u8;

                // insert false certainty until it fully completes
                reference.insert(set_counter, (set_counter, false));

                fp_crash!(tree.set(vec![hi, lo], vec![hi, lo]));

                // make sure we keep the disk and reference in-sync
                // maybe in the future put pending things in their own
                // reference and have a Flush op that syncs them.
                // just because the set above didn't hit a failpoint,
                // it doesn't mean this flush won't hit one, so we
                // also use the fp_crash macro here for handling it.
                fp_crash!(tree.flush());

                // now we should be certain the thing is in there, set certainty to true
                reference.insert(set_counter, (set_counter, true));

                set_counter += 1;
            }
            Del(k) => {
                // insert false certainty before completes
                reference.insert(k as u16, (k as u16, false));

                let res = fp_crash!(tree.del(&*vec![0, k]));
                match res {
                    Some(_) => {
                        // we definitely caused a file write
                        tree.flush().expect("should be able to flush after del")
                    }
                    None => {
                        // we might not have actually written anything
                        // because the key wasn't there.
                        let _ = tree.flush();
                    }
                }

                reference.remove(&(k as u16));
            }
            Restart => {
                restart!();
            }
            FailPoint(fp) => {
                fail_points.insert(fp.clone());
                fail::cfg(&*fp, "return").expect(
                    "should be able to configure failpoint",
                );
            }
        }
    }

    true
}

#[test]
fn quickcheck_tree_with_failpoints() {
    // use fewer tests for travis OSX builds that stall out all the time
    #[cfg(target_os = "macos")]
    let n_tests = 50;

    #[cfg(not(target_os = "macos"))]
    let n_tests = 100;

    QuickCheck::new()
        .gen(StdGen::new(rand::thread_rng(), 100))
        .tests(n_tests)
        .max_tests(10000)
        .quickcheck(prop_tree_crashes_nicely as fn(Vec<Op>, bool) -> bool);
}

#[test]
fn failpoints_bug_1() {
    // postmortem 1: model did not account for proper reasons to fail to start
    assert!(prop_tree_crashes_nicely(
        vec![FailPoint("snap write"), Restart],
        false,
    ));
}

#[test]
fn failpoints_bug_2() {
    // postmortem 1: the system was assuming the happy path across failpoints
    assert!(prop_tree_crashes_nicely(
        vec![FailPoint("buffer write post"), Set, Set, Restart],
        false,
    ))
}

#[test]
fn failpoints_bug_3() {
    // postmortem 1: this was a regression that happened because we
    // chose to eat errors about advancing snapshots, which trigger
    // log flushes. We should not trigger flushes from snapshots,
    // but first we need to make sure we are better about detecting
    // tears, by not also using 0 as a failed flush signifier.
    assert!(prop_tree_crashes_nicely(
        vec![
            Set,
            Set,
            Set,
            Set,
            FailPoint("trailer write"),
            Set,
            Set,
            Set,
            Set,
            Restart,
        ],
        false,
    ))
}

#[test]
fn failpoints_bug_4() {
    // postmortem 1: the test model was not properly accounting for
    // writes that may-or-may-not be present due to an error.
    assert!(prop_tree_crashes_nicely(
        vec![Set, FailPoint("snap write"), Del(0), Set, Restart],
        false,
    ))
}

#[test]
fn failpoints_bug_5() {
    // postmortem 1:
    assert!(prop_tree_crashes_nicely(
        vec![
            Set,
            FailPoint("snap write mv post"),
            Set,
            FailPoint("snap write"),
            Set,
            Set,
            Set,
            Restart,
            FailPoint("zero segment"),
            Set,
            Set,
            Set,
            Restart,
        ],
        false,
    ))
}

#[test]
fn failpoints_bug_6() {
    // postmortem 1:
    assert!(prop_tree_crashes_nicely(
        vec![
            Set,
            Del(0),
            Set,
            Set,
            Set,
            Restart,
            FailPoint("zero segment post"),
            Set,
            Set,
            Set,
            Restart,
        ],
        false,
    ))
}

#[test]
fn failpoints_bug_7() {
    // postmortem 1: We were crashing because a Segment was
    // in the SegmentAccountant's to_clean Vec, but it had
    // no present pages. This can legitimately happen when
    // a Segment only contains failed log flushes.
    assert!(prop_tree_crashes_nicely(
        vec![
            Set,
            Set,
            Set,
            Set,
            Set,
            Set,
            Set,
            Set,
            Set,
            Set,
            Set,
            Set,
            Set,
            Set,
            Set,
            Set,
            Set,
            Del(17),
            Del(29),
            Del(246),
            Del(248),
            Set,
        ],
        false,
    ))
}

#[test]
fn failpoints_bug_8() {
    // postmortem 1: we were assuming that deletes would fail if buffer writes
    // are disabled, but that's not true, because deletes might not cause any
    // writes if the value was not present.
    assert!(prop_tree_crashes_nicely(
        vec![
            Set,
            Set,
            Set,
            Set,
            Set,
            Set,
            Set,
            Set,
            Set,
            Set,
            Set,
            Set,
            Set,
            Set,
            Set,
            Set,
            Set,
            Del(0),
            FailPoint("buffer write post"),
            Del(179),
        ],
        false,
    ))
}
<|endoftext|>


<commit_before>//! Fast, minimal float-parsing algorithm.

// FEATURES

// Require intrinsics in a no_std context.
#![cfg_attr(not(feature = "std"), no_std)]

#[cfg(all(not(no_alloc), not(feature = "std")))]
extern crate alloc;

/// Facade around the core features for name mangling.
pub(crate) mod lib {
#[cfg(feature = "std")]
pub(crate) use std::*;

#[cfg(not(feature = "std"))]
pub(crate) use core::*;

#[cfg(all(not(no_alloc), feature = "std"))]
pub(crate) use std::vec::Vec;

#[cfg(all(not(no_alloc), not(feature = "std")))]
pub(crate) use ::alloc::vec::Vec;
}

// MODULES
mod algorithm;
mod bhcomp;
mod bignum;
mod cached;
mod cached_float80;
mod digit;
mod errors;
mod exponent;
mod float;
mod large_powers;
mod math;
mod num;
mod parse;
mod rounding;
mod shift;
mod slice;
mod small_powers;

#[cfg(limb_width_32)]
mod large_powers32;

#[cfg(limb_width_64)]
mod large_powers64;

// API
pub use self::parse::parse_float;
pub use self::num::Float;

<commit_msg>Add explanation to lexical lib<commit_after>// The code in this module is derived from the `lexical` crate by @Alexhuszagh
// which the author condensed into this minimal subset for use in serde_json.
// For the serde_json use case we care more about reliably round tripping all
// possible floating point values than about parsing any arbitrarily long string
// of digits with perfect accuracy, as the latter would take a high cost in
// compile time and performance.
//
// Dual licensed as MIT and Apache 2.0 just like the rest of serde_json, but
// copyright Alexander Huszagh.

//! Fast, minimal float-parsing algorithm.

// FEATURES

// Require intrinsics in a no_std context.
#![cfg_attr(not(feature = "std"), no_std)]

#[cfg(all(not(no_alloc), not(feature = "std")))]
extern crate alloc;

/// Facade around the core features for name mangling.
pub(crate) mod lib {
#[cfg(feature = "std")]
pub(crate) use std::*;

#[cfg(not(feature = "std"))]
pub(crate) use core::*;

#[cfg(all(not(no_alloc), feature = "std"))]
pub(crate) use std::vec::Vec;

#[cfg(all(not(no_alloc), not(feature = "std")))]
pub(crate) use ::alloc::vec::Vec;
}

// MODULES
mod algorithm;
mod bhcomp;
mod bignum;
mod cached;
mod cached_float80;
mod digit;
mod errors;
mod exponent;
mod float;
mod large_powers;
mod math;
mod num;
mod parse;
mod rounding;
mod shift;
mod slice;
mod small_powers;

#[cfg(limb_width_32)]
mod large_powers32;

#[cfg(limb_width_64)]
mod large_powers64;

// API
pub use self::parse::parse_float;
pub use self::num::Float;

<|endoftext|>


<commit_before>// Copyright 2013-2014 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.

//! Terminal formatting library.
//!
//! This crate provides the `Terminal` trait, which abstracts over an [ANSI
//! Terminal][ansi] to provide color printing, among other things. There are two implementations,
//! the `TerminfoTerminal`, which uses control characters from a
//! [terminfo][ti] database, and `WinConsole`, which uses the [Win32 Console
//! API][win].
//!
//! # Examples
//!
//! ```no_run
//! extern crate term;
//!
//! fn main() {
//!     let mut t = term::stdout().unwrap();
//!
//!     t.fg(term::color::GREEN).unwrap();
//!     (write!(t, "hello, ")).unwrap();
//!
//!     t.fg(term::color::RED).unwrap();
//!     (writeln!(t, "world!")).unwrap();
//!
//!     t.reset().unwrap();
//! }
//! ```
//!
//! [ansi]: https://en.wikipedia.org/wiki/ANSI_escape_code
//! [win]: http://msdn.microsoft.com/en-us/library/windows/desktop/ms682010%28v=vs.85%29.aspx
//! [ti]: https://en.wikipedia.org/wiki/Terminfo

#![crate_name = "term"]
#![experimental]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "http://www.rust-lang.org/favicon.ico",
       html_root_url = "http://doc.rust-lang.org/nightly/",
       html_playground_url = "http://play.rust-lang.org/")]

#![allow(unknown_features)]
#![feature(macro_rules, phase, slicing_syntax, globs)]

#![deny(missing_docs)]

#[phase(plugin, link)] extern crate log;

pub use terminfo::TerminfoTerminal;
#[cfg(windows)]
pub use win::WinConsole;

use std::io::IoResult;

pub mod terminfo;

#[cfg(windows)]
mod win;

/// A hack to work around the fact that `Box<Writer + Send>` does not
/// currently implement `Writer`.
pub struct WriterWrapper {
    wrapped: Box<Writer + Send>,
}

impl Writer for WriterWrapper {
    #[inline]
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        self.wrapped.write(buf)
    }

    #[inline]
    fn flush(&mut self) -> IoResult<()> {
        self.wrapped.flush()
    }
}

#[cfg(not(windows))]
/// Return a Terminal wrapping stdout, or None if a terminal couldn't be
/// opened.
pub fn stdout() -> Option<Box<Terminal<WriterWrapper> + Send>> {
    TerminfoTerminal::new(WriterWrapper {
        wrapped: box std::io::stdout() as Box<Writer + Send>,
    })
}

#[cfg(windows)]
/// Return a Terminal wrapping stdout, or None if a terminal couldn't be
/// opened.
pub fn stdout() -> Option<Box<Terminal<WriterWrapper> + Send>> {
    let ti = TerminfoTerminal::new(WriterWrapper {
        wrapped: box std::io::stdout() as Box<Writer + Send>,
    });

    match ti {
        Some(t) => Some(t),
        None => {
            WinConsole::new(WriterWrapper {
                wrapped: box std::io::stdout() as Box<Writer + Send>,
            })
        }
    }
}

#[cfg(not(windows))]
/// Return a Terminal wrapping stderr, or None if a terminal couldn't be
/// opened.
pub fn stderr() -> Option<Box<Terminal<WriterWrapper> + Send>> {
    TerminfoTerminal::new(WriterWrapper {
        wrapped: box std::io::stderr() as Box<Writer + Send>,
    })
}

#[cfg(windows)]
/// Return a Terminal wrapping stderr, or None if a terminal couldn't be
/// opened.
pub fn stderr() -> Option<Box<Terminal<WriterWrapper> + Send>> {
    let ti = TerminfoTerminal::new(WriterWrapper {
        wrapped: box std::io::stderr() as Box<Writer + Send>,
    });

    match ti {
        Some(t) => Some(t),
        None => {
            WinConsole::new(WriterWrapper {
                wrapped: box std::io::stderr() as Box<Writer + Send>,
            })
        }
    }
}

/// Terminal color definitions
pub mod color {
    /// Number for a terminal color
    pub type Color = u16;

    pub const BLACK:   Color = 0u16;
    pub const RED:     Color = 1u16;
    pub const GREEN:   Color = 2u16;
    pub const YELLOW:  Color = 3u16;
    pub const BLUE:    Color = 4u16;
    pub const MAGENTA: Color = 5u16;
    pub const CYAN:    Color = 6u16;
    pub const WHITE:   Color = 7u16;

    pub const BRIGHT_BLACK:   Color = 8u16;
    pub const BRIGHT_RED:     Color = 9u16;
    pub const BRIGHT_GREEN:   Color = 10u16;
    pub const BRIGHT_YELLOW:  Color = 11u16;
    pub const BRIGHT_BLUE:    Color = 12u16;
    pub const BRIGHT_MAGENTA: Color = 13u16;
    pub const BRIGHT_CYAN:    Color = 14u16;
    pub const BRIGHT_WHITE:   Color = 15u16;
}

/// Terminal attributes
pub mod attr {
    pub use self::Attr::*;

    /// Terminal attributes for use with term.attr().
    ///
    /// Most attributes can only be turned on and must be turned off with term.reset().
    /// The ones that can be turned off explicitly take a boolean value.
    /// Color is also represented as an attribute for convenience.
    #[deriving(Copy)]
    pub enum Attr {
        /// Bold (or possibly bright) mode
        Bold,
        /// Dim mode, also called faint or half-bright. Often not supported
        Dim,
        /// Italics mode. Often not supported
        Italic(bool),
        /// Underline mode
        Underline(bool),
        /// Blink mode
        Blink,
        /// Standout mode. Often implemented as Reverse, sometimes coupled with Bold
        Standout(bool),
        /// Reverse mode, inverts the foreground and background colors
        Reverse,
        /// Secure mode, also called invis mode. Hides the printed text
        Secure,
        /// Convenience attribute to set the foreground color
        ForegroundColor(super::color::Color),
        /// Convenience attribute to set the background color
        BackgroundColor(super::color::Color)
    }
}

/// A terminal with similar capabilities to an ANSI Terminal
/// (foreground/background colors etc).
pub trait Terminal<T: Writer>: Writer {
    /// Sets the foreground color to the given color.
    ///
    /// If the color is a bright color, but the terminal only supports 8 colors,
    /// the corresponding normal color will be used instead.
    ///
    /// Returns `Ok(true)` if the color was set, `Ok(false)` otherwise, and `Err(e)`
    /// if there was an I/O error.
    fn fg(&mut self, color: color::Color) -> IoResult<bool>;

    /// Sets the background color to the given color.
    ///
    /// If the color is a bright color, but the terminal only supports 8 colors,
    /// the corresponding normal color will be used instead.
    ///
    /// Returns `Ok(true)` if the color was set, `Ok(false)` otherwise, and `Err(e)`
    /// if there was an I/O error.
    fn bg(&mut self, color: color::Color) -> IoResult<bool>;

    /// Sets the given terminal attribute, if supported.  Returns `Ok(true)`
    /// if the attribute was supported, `Ok(false)` otherwise, and `Err(e)` if
    /// there was an I/O error.
    fn attr(&mut self, attr: attr::Attr) -> IoResult<bool>;

    /// Returns whether the given terminal attribute is supported.
    fn supports_attr(&self, attr: attr::Attr) -> bool;

    /// Resets all terminal attributes and color to the default.
    /// Returns `Ok()`.
    fn reset(&mut self) -> IoResult<()>;

    /// Gets an immutable reference to the stream inside
    fn get_ref<'a>(&'a self) -> &'a T;

    /// Gets a mutable reference to the stream inside
    fn get_mut<'a>(&'a mut self) -> &'a mut T;
}

/// A terminal which can be unwrapped.
pub trait UnwrappableTerminal<T: Writer>: Terminal<T> {
    /// Returns the contained stream, destroying the `Terminal`
    fn unwrap(self) -> T;
}
<commit_msg>rollup merge of #20276: alexcrichton/deprecate-term<commit_after>// Copyright 2013-2014 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.

//! Terminal formatting library.
//!
//! This crate provides the `Terminal` trait, which abstracts over an [ANSI
//! Terminal][ansi] to provide color printing, among other things. There are two implementations,
//! the `TerminfoTerminal`, which uses control characters from a
//! [terminfo][ti] database, and `WinConsole`, which uses the [Win32 Console
//! API][win].
//!
//! # Examples
//!
//! ```no_run
//! extern crate term;
//!
//! fn main() {
//!     let mut t = term::stdout().unwrap();
//!
//!     t.fg(term::color::GREEN).unwrap();
//!     (write!(t, "hello, ")).unwrap();
//!
//!     t.fg(term::color::RED).unwrap();
//!     (writeln!(t, "world!")).unwrap();
//!
//!     t.reset().unwrap();
//! }
//! ```
//!
//! [ansi]: https://en.wikipedia.org/wiki/ANSI_escape_code
//! [win]: http://msdn.microsoft.com/en-us/library/windows/desktop/ms682010%28v=vs.85%29.aspx
//! [ti]: https://en.wikipedia.org/wiki/Terminfo

#![crate_name = "term"]
#![experimental = "use the crates.io `term` library instead"]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "http://www.rust-lang.org/favicon.ico",
       html_root_url = "http://doc.rust-lang.org/nightly/",
       html_playground_url = "http://play.rust-lang.org/")]

#![allow(unknown_features)]
#![feature(macro_rules, phase, slicing_syntax, globs)]

#![deny(missing_docs)]

#[phase(plugin, link)] extern crate log;

pub use terminfo::TerminfoTerminal;
#[cfg(windows)]
pub use win::WinConsole;

use std::io::IoResult;

pub mod terminfo;

#[cfg(windows)]
mod win;

/// A hack to work around the fact that `Box<Writer + Send>` does not
/// currently implement `Writer`.
pub struct WriterWrapper {
    wrapped: Box<Writer + Send>,
}

impl Writer for WriterWrapper {
    #[inline]
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        self.wrapped.write(buf)
    }

    #[inline]
    fn flush(&mut self) -> IoResult<()> {
        self.wrapped.flush()
    }
}

#[cfg(not(windows))]
/// Return a Terminal wrapping stdout, or None if a terminal couldn't be
/// opened.
pub fn stdout() -> Option<Box<Terminal<WriterWrapper> + Send>> {
    TerminfoTerminal::new(WriterWrapper {
        wrapped: box std::io::stdout() as Box<Writer + Send>,
    })
}

#[cfg(windows)]
/// Return a Terminal wrapping stdout, or None if a terminal couldn't be
/// opened.
pub fn stdout() -> Option<Box<Terminal<WriterWrapper> + Send>> {
    let ti = TerminfoTerminal::new(WriterWrapper {
        wrapped: box std::io::stdout() as Box<Writer + Send>,
    });

    match ti {
        Some(t) => Some(t),
        None => {
            WinConsole::new(WriterWrapper {
                wrapped: box std::io::stdout() as Box<Writer + Send>,
            })
        }
    }
}

#[cfg(not(windows))]
/// Return a Terminal wrapping stderr, or None if a terminal couldn't be
/// opened.
pub fn stderr() -> Option<Box<Terminal<WriterWrapper> + Send>> {
    TerminfoTerminal::new(WriterWrapper {
        wrapped: box std::io::stderr() as Box<Writer + Send>,
    })
}

#[cfg(windows)]
/// Return a Terminal wrapping stderr, or None if a terminal couldn't be
/// opened.
pub fn stderr() -> Option<Box<Terminal<WriterWrapper> + Send>> {
    let ti = TerminfoTerminal::new(WriterWrapper {
        wrapped: box std::io::stderr() as Box<Writer + Send>,
    });

    match ti {
        Some(t) => Some(t),
        None => {
            WinConsole::new(WriterWrapper {
                wrapped: box std::io::stderr() as Box<Writer + Send>,
            })
        }
    }
}

/// Terminal color definitions
pub mod color {
    /// Number for a terminal color
    pub type Color = u16;

    pub const BLACK:   Color = 0u16;
    pub const RED:     Color = 1u16;
    pub const GREEN:   Color = 2u16;
    pub const YELLOW:  Color = 3u16;
    pub const BLUE:    Color = 4u16;
    pub const MAGENTA: Color = 5u16;
    pub const CYAN:    Color = 6u16;
    pub const WHITE:   Color = 7u16;

    pub const BRIGHT_BLACK:   Color = 8u16;
    pub const BRIGHT_RED:     Color = 9u16;
    pub const BRIGHT_GREEN:   Color = 10u16;
    pub const BRIGHT_YELLOW:  Color = 11u16;
    pub const BRIGHT_BLUE:    Color = 12u16;
    pub const BRIGHT_MAGENTA: Color = 13u16;
    pub const BRIGHT_CYAN:    Color = 14u16;
    pub const BRIGHT_WHITE:   Color = 15u16;
}

/// Terminal attributes
pub mod attr {
    pub use self::Attr::*;

    /// Terminal attributes for use with term.attr().
    ///
    /// Most attributes can only be turned on and must be turned off with term.reset().
    /// The ones that can be turned off explicitly take a boolean value.
    /// Color is also represented as an attribute for convenience.
    #[deriving(Copy)]
    pub enum Attr {
        /// Bold (or possibly bright) mode
        Bold,
        /// Dim mode, also called faint or half-bright. Often not supported
        Dim,
        /// Italics mode. Often not supported
        Italic(bool),
        /// Underline mode
        Underline(bool),
        /// Blink mode
        Blink,
        /// Standout mode. Often implemented as Reverse, sometimes coupled with Bold
        Standout(bool),
        /// Reverse mode, inverts the foreground and background colors
        Reverse,
        /// Secure mode, also called invis mode. Hides the printed text
        Secure,
        /// Convenience attribute to set the foreground color
        ForegroundColor(super::color::Color),
        /// Convenience attribute to set the background color
        BackgroundColor(super::color::Color)
    }
}

/// A terminal with similar capabilities to an ANSI Terminal
/// (foreground/background colors etc).
pub trait Terminal<T: Writer>: Writer {
    /// Sets the foreground color to the given color.
    ///
    /// If the color is a bright color, but the terminal only supports 8 colors,
    /// the corresponding normal color will be used instead.
    ///
    /// Returns `Ok(true)` if the color was set, `Ok(false)` otherwise, and `Err(e)`
    /// if there was an I/O error.
    fn fg(&mut self, color: color::Color) -> IoResult<bool>;

    /// Sets the background color to the given color.
    ///
    /// If the color is a bright color, but the terminal only supports 8 colors,
    /// the corresponding normal color will be used instead.
    ///
    /// Returns `Ok(true)` if the color was set, `Ok(false)` otherwise, and `Err(e)`
    /// if there was an I/O error.
    fn bg(&mut self, color: color::Color) -> IoResult<bool>;

    /// Sets the given terminal attribute, if supported.  Returns `Ok(true)`
    /// if the attribute was supported, `Ok(false)` otherwise, and `Err(e)` if
    /// there was an I/O error.
    fn attr(&mut self, attr: attr::Attr) -> IoResult<bool>;

    /// Returns whether the given terminal attribute is supported.
    fn supports_attr(&self, attr: attr::Attr) -> bool;

    /// Resets all terminal attributes and color to the default.
    /// Returns `Ok()`.
    fn reset(&mut self) -> IoResult<()>;

    /// Gets an immutable reference to the stream inside
    fn get_ref<'a>(&'a self) -> &'a T;

    /// Gets a mutable reference to the stream inside
    fn get_mut<'a>(&'a mut self) -> &'a mut T;
}

/// A terminal which can be unwrapped.
pub trait UnwrappableTerminal<T: Writer>: Terminal<T> {
    /// Returns the contained stream, destroying the `Terminal`
    fn unwrap(self) -> T;
}
<|endoftext|>


<commit_before>// Copyright 2016 Pierre Talbot (IRCAM)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use ast::*;
use partial::*;

pub fn generate_chococubes(ast: Program) -> Partial<String> {
  let mut gen = CodeGenerator::new();
  gen.push_block(ast.header);
  gen.push_line(&format!("public class {}", ast.class_name));
  gen.open_block();
  generate_items(&mut gen, ast.items);
  gen.close_block();

  Partial::Value(gen.code)
}

fn generate_items(gen: &mut CodeGenerator, items: Vec<Item>) {
  for item in items {
    match item {
      Item::Statement(stmt) => generate_statement(gen, stmt),
      Item::Proc(process) => generate_process(gen, process),
      Item::JavaStaticMethod(_, method) => gen.push_java_method(method)
    }
  }
}

fn generate_statement(gen: &mut CodeGenerator, stmt: Stmt) {
}

fn generate_process(gen: &mut CodeGenerator, process: Process) {

}

struct CodeGenerator {
  indent: usize,
  pub code: String
}

impl CodeGenerator {
  pub fn new() -> CodeGenerator {
    CodeGenerator {
      indent: 0,
      code: String::new()
    }
  }

  pub fn open_block(&mut self) {
    self.push_line("{");
    self.indent += 2;
  }

  pub fn close_block(&mut self) {
    self.indent -= 2;
    self.push_line("}");
  }

  pub fn push_line(&mut self, code_line: &str) {
    self.code += &self.indent_spaces();
    self.push_unindented_line(code_line);
  }

  pub fn push_unindented_line(&mut self, code_line: &str) {
    self.code += code_line;
    self.newline();
  }

  pub fn push_java_method(&mut self, code_block: String) {
    let mut lines_iter = code_block.lines();
    self.push_line(lines_iter.next().unwrap());
    for line in lines_iter {
      self.push_unindented_line(line);
    }
    self.newline();
  }

  pub fn push_block(&mut self, code_block: String) {
    for line in code_block.lines() {
      self.push_line(line);
    }
  }

  fn newline(&mut self) {
    self.code += "\n";
  }

  fn indent_spaces(&self) -> String {
    let mut res = String::new();
    for _ in 0..self.indent {
      res.push(' ');
    }
    res
  }
}
<commit_msg>[Bonsai][Code generation] Generate the execute method, running the synchronous machine.<commit_after>// Copyright 2016 Pierre Talbot (IRCAM)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use ast::*;
use partial::*;

pub fn generate_chococubes(ast: Program) -> Partial<String> {
  let mut gen = CodeGenerator::new();
  gen.push_block(ast.header);
  gen.push_line(&format!("public class {}", ast.class_name));
  gen.open_block();
  generate_execute_process(&mut gen);
  generate_items(&mut gen, ast.items);
  gen.close_block();
  Partial::Value(gen.code)
}

fn generate_items(gen: &mut CodeGenerator, items: Vec<Item>) {
  for item in items {
    match item {
      Item::Statement(stmt) => unreachable!("Should have been moved into the init process."),
      Item::Proc(process) => generate_process(gen, process),
      Item::JavaStaticMethod(_, method) => gen.push_java_method(method)
    }
  }
}

fn generate_execute_process(gen: &mut CodeGenerator) {
  gen.push_line("public void execute()");
  gen.open_block();
  gen.push_block(String::from("\
    Program program = init();\n\
    SpaceMachine machine = SpaceMachine.create(p);\n\
    machine.execute();"));
  gen.close_block();
}

fn generate_process(gen: &mut CodeGenerator, process: Process) {

}

struct CodeGenerator {
  indent: usize,
  pub code: String
}

impl CodeGenerator {
  pub fn new() -> CodeGenerator {
    CodeGenerator {
      indent: 0,
      code: String::new()
    }
  }

  pub fn indent(&mut self) {
    self.indent += 2;
  }

  pub fn unindent(&mut self) {
    self.indent -= 2;
  }

  pub fn open_block(&mut self) {
    self.push_line("{");
    self.indent();
  }

  pub fn close_block(&mut self) {
    self.unindent();
    self.push_line("}");
  }

  pub fn push_line(&mut self, code_line: &str) {
    self.code += &self.indent_spaces();
    self.raw_push_line(code_line);
  }

  pub fn raw_push_line(&mut self, code_line: &str) {
    self.code += code_line;
    self.newline();
  }

  pub fn push_java_method(&mut self, code_block: String) {
    let mut lines_iter = code_block.lines();
    self.push_line(lines_iter.next().unwrap());
    for line in lines_iter {
      self.raw_push_line(line);
    }
    self.newline();
  }

  pub fn push_block(&mut self, code_block: String) {
    for line in code_block.lines() {
      self.push_line(line);
    }
  }

  fn newline(&mut self) {
    self.code += "\n";
  }

  fn indent_spaces(&self) -> String {
    let mut res = String::new();
    for _ in 0..self.indent {
      res.push(' ');
    }
    res
  }
}
<|endoftext|>


<commit_before>#![cfg_attr(feature = "nightly", feature(test))]
#![feature(nll, try_trait)]

#[macro_use]
extern crate log;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate bitflags;

extern crate syntax;
#[macro_use]
extern crate derive_more;
extern crate rls_span;

#[macro_use]
mod testutils;
#[macro_use]
mod util;
mod ast;
mod ast_types;
mod codecleaner;
mod codeiter;
mod core;
mod fileres;
mod matchers;
#[cfg(feature = "metadata")]
mod metadata;
mod nameres;
mod primitive;
mod project_model;
mod scopes;
mod snippets;
mod typeinf;

pub use ast_types::PathSearch;
pub use core::{
    complete_from_file, complete_fully_qualified_name, find_definition, is_use_stmt, to_coords,
    to_point,
};
pub use core::{
    BytePos, ByteRange, Coordinate, FileCache, FileLoader, Location, Match, MatchType, Session,
};
pub use primitive::PrimKind;
pub use project_model::ProjectModelProvider;
pub use snippets::snippet_for_match;
pub use util::expand_ident;

pub use util::{get_rust_src_path, RustSrcPathError};

#[cfg(all(feature = "nightly", test))]
mod benches;
<commit_msg>Re-export Edition<commit_after>#![cfg_attr(feature = "nightly", feature(test))]
#![feature(nll, try_trait)]

#[macro_use]
extern crate log;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate bitflags;

extern crate syntax;
#[macro_use]
extern crate derive_more;
extern crate rls_span;

#[macro_use]
mod testutils;
#[macro_use]
mod util;
mod ast;
mod ast_types;
mod codecleaner;
mod codeiter;
mod core;
mod fileres;
mod matchers;
#[cfg(feature = "metadata")]
mod metadata;
mod nameres;
mod primitive;
mod project_model;
mod scopes;
mod snippets;
mod typeinf;

pub use ast_types::PathSearch;
pub use core::{
    complete_from_file, complete_fully_qualified_name, find_definition, is_use_stmt, to_coords,
    to_point,
};
pub use core::{
    BytePos, ByteRange, Coordinate, FileCache, FileLoader, Location, Match, MatchType, Session,
};
pub use primitive::PrimKind;
pub use project_model::{Edition, ProjectModelProvider};
pub use snippets::snippet_for_match;
pub use util::expand_ident;

pub use util::{get_rust_src_path, RustSrcPathError};

#[cfg(all(feature = "nightly", test))]
mod benches;
<|endoftext|>


<commit_before>// Copyright 2016 Amanieu d'Antras
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://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 crate::{deadlock, util};
#[cfg(has_sized_atomics)]
use core::sync::atomic::AtomicU8;
#[cfg(not(has_sized_atomics))]
use core::sync::atomic::AtomicUsize as AtomicU8;
use core::{sync::atomic::Ordering, time::Duration};
use lock_api::{GuardNoSend, RawMutex as RawMutex_};
use parking_lot_core::{self, ParkResult, SpinWait, UnparkResult, UnparkToken, DEFAULT_PARK_TOKEN};
use std::time::Instant;

#[cfg(has_sized_atomics)]
type U8 = u8;
#[cfg(not(has_sized_atomics))]
type U8 = usize;

// UnparkToken used to indicate that that the target thread should attempt to
// lock the mutex again as soon as it is unparked.
pub(crate) const TOKEN_NORMAL: UnparkToken = UnparkToken(0);

// UnparkToken used to indicate that the mutex is being handed off to the target
// thread directly without unlocking it.
pub(crate) const TOKEN_HANDOFF: UnparkToken = UnparkToken(1);

const LOCKED_BIT: U8 = 1;
const PARKED_BIT: U8 = 2;

/// Raw mutex type backed by the parking lot.
pub struct RawMutex {
    state: AtomicU8,
}

unsafe impl lock_api::RawMutex for RawMutex {
    const INIT: RawMutex = RawMutex {
        state: AtomicU8::new(0),
    };

    type GuardMarker = GuardNoSend;

    #[inline]
    fn lock(&self) {
        if self
            .state
            .compare_exchange_weak(0, LOCKED_BIT, Ordering::Acquire, Ordering::Relaxed)
            .is_err()
        {
            self.lock_slow(None);
        }
        unsafe { deadlock::acquire_resource(self as *const _ as usize) };
    }

    #[inline]
    fn try_lock(&self) -> bool {
        let mut state = self.state.load(Ordering::Relaxed);
        loop {
            if state & LOCKED_BIT != 0 {
                return false;
            }
            match self.state.compare_exchange_weak(
                state,
                state | LOCKED_BIT,
                Ordering::Acquire,
                Ordering::Relaxed,
            ) {
                Ok(_) => {
                    unsafe { deadlock::acquire_resource(self as *const _ as usize) };
                    return true;
                }
                Err(x) => state = x,
            }
        }
    }

    #[inline]
    fn unlock(&self) {
        unsafe { deadlock::release_resource(self as *const _ as usize) };
        if self
            .state
            .compare_exchange(LOCKED_BIT, 0, Ordering::Release, Ordering::Relaxed)
            .is_ok()
        {
            return;
        }
        self.unlock_slow(false);
    }
}

unsafe impl lock_api::RawMutexFair for RawMutex {
    #[inline]
    fn unlock_fair(&self) {
        unsafe { deadlock::release_resource(self as *const _ as usize) };
        if self
            .state
            .compare_exchange(LOCKED_BIT, 0, Ordering::Release, Ordering::Relaxed)
            .is_ok()
        {
            return;
        }
        self.unlock_slow(true);
    }

    #[inline]
    fn bump(&self) {
        if self.state.load(Ordering::Relaxed) & PARKED_BIT != 0 {
            self.bump_slow();
        }
    }
}

unsafe impl lock_api::RawMutexTimed for RawMutex {
    type Duration = Duration;
    type Instant = Instant;

    #[inline]
    fn try_lock_until(&self, timeout: Instant) -> bool {
        let result = if self
            .state
            .compare_exchange_weak(0, LOCKED_BIT, Ordering::Acquire, Ordering::Relaxed)
            .is_ok()
        {
            true
        } else {
            self.lock_slow(Some(timeout))
        };
        if result {
            unsafe { deadlock::acquire_resource(self as *const _ as usize) };
        }
        result
    }

    #[inline]
    fn try_lock_for(&self, timeout: Duration) -> bool {
        let result = if self
            .state
            .compare_exchange_weak(0, LOCKED_BIT, Ordering::Acquire, Ordering::Relaxed)
            .is_ok()
        {
            true
        } else {
            self.lock_slow(util::to_deadline(timeout))
        };
        if result {
            unsafe { deadlock::acquire_resource(self as *const _ as usize) };
        }
        result
    }
}

impl RawMutex {
    // Used by Condvar when requeuing threads to us, must be called while
    // holding the queue lock.
    #[inline]
    pub(crate) fn mark_parked_if_locked(&self) -> bool {
        let mut state = self.state.load(Ordering::Relaxed);
        loop {
            if state & LOCKED_BIT == 0 {
                return false;
            }
            match self.state.compare_exchange_weak(
                state,
                state | PARKED_BIT,
                Ordering::Relaxed,
                Ordering::Relaxed,
            ) {
                Ok(_) => return true,
                Err(x) => state = x,
            }
        }
    }

    // Used by Condvar when requeuing threads to us, must be called while
    // holding the queue lock.
    #[inline]
    pub(crate) fn mark_parked(&self) {
        self.state.fetch_or(PARKED_BIT, Ordering::Relaxed);
    }

    #[cold]
    fn lock_slow(&self, timeout: Option<Instant>) -> bool {
        let mut spinwait = SpinWait::new();
        let mut state = self.state.load(Ordering::Relaxed);
        loop {
            // Grab the lock if it isn't locked, even if there is a queue on it
            if state & LOCKED_BIT == 0 {
                match self.state.compare_exchange_weak(
                    state,
                    state | LOCKED_BIT,
                    Ordering::Acquire,
                    Ordering::Relaxed,
                ) {
                    Ok(_) => return true,
                    Err(x) => state = x,
                }
                continue;
            }

            // If there is no queue, try spinning a few times
            if state & PARKED_BIT == 0 && spinwait.spin() {
                state = self.state.load(Ordering::Relaxed);
                continue;
            }

            // Set the parked bit
            if state & PARKED_BIT == 0 {
                if let Err(x) = self.state.compare_exchange_weak(
                    state,
                    state | PARKED_BIT,
                    Ordering::Relaxed,
                    Ordering::Relaxed,
                ) {
                    state = x;
                    continue;
                }
            }

            // Park our thread until we are woken up by an unlock
            unsafe {
                let addr = self as *const _ as usize;
                let validate = || self.state.load(Ordering::Relaxed) == LOCKED_BIT | PARKED_BIT;
                let before_sleep = || {};
                let timed_out = |_, was_last_thread| {
                    // Clear the parked bit if we were the last parked thread
                    if was_last_thread {
                        self.state.fetch_and(!PARKED_BIT, Ordering::Relaxed);
                    }
                };
                match parking_lot_core::park(
                    addr,
                    validate,
                    before_sleep,
                    timed_out,
                    DEFAULT_PARK_TOKEN,
                    timeout,
                ) {
                    // The thread that unparked us passed the lock on to us
                    // directly without unlocking it.
                    ParkResult::Unparked(TOKEN_HANDOFF) => return true,

                    // We were unparked normally, try acquiring the lock again
                    ParkResult::Unparked(_) => (),

                    // The validation function failed, try locking again
                    ParkResult::Invalid => (),

                    // Timeout expired
                    ParkResult::TimedOut => return false,
                }
            }

            // Loop back and try locking again
            spinwait.reset();
            state = self.state.load(Ordering::Relaxed);
        }
    }

    #[cold]
    fn unlock_slow(&self, force_fair: bool) {
        // Unpark one thread and leave the parked bit set if there might
        // still be parked threads on this address.
        unsafe {
            let addr = self as *const _ as usize;
            let callback = |result: UnparkResult| {
                // If we are using a fair unlock then we should keep the
                // mutex locked and hand it off to the unparked thread.
                if result.unparked_threads != 0 && (force_fair || result.be_fair) {
                    // Clear the parked bit if there are no more parked
                    // threads.
                    if !result.have_more_threads {
                        self.state.store(LOCKED_BIT, Ordering::Relaxed);
                    }
                    return TOKEN_HANDOFF;
                }

                // Clear the locked bit, and the parked bit as well if there
                // are no more parked threads.
                if result.have_more_threads {
                    self.state.store(PARKED_BIT, Ordering::Release);
                } else {
                    self.state.store(0, Ordering::Release);
                }
                TOKEN_NORMAL
            };
            parking_lot_core::unpark_one(addr, callback);
        }
    }

    #[cold]
    fn bump_slow(&self) {
        unsafe { deadlock::release_resource(self as *const _ as usize) };
        self.unlock_slow(true);
        self.lock();
    }
}
<commit_msg>Reduce scope of unsafe block and add SAFETY doc<commit_after>// Copyright 2016 Amanieu d'Antras
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://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 crate::{deadlock, util};
#[cfg(has_sized_atomics)]
use core::sync::atomic::AtomicU8;
#[cfg(not(has_sized_atomics))]
use core::sync::atomic::AtomicUsize as AtomicU8;
use core::{sync::atomic::Ordering, time::Duration};
use lock_api::{GuardNoSend, RawMutex as RawMutex_};
use parking_lot_core::{self, ParkResult, SpinWait, UnparkResult, UnparkToken, DEFAULT_PARK_TOKEN};
use std::time::Instant;

#[cfg(has_sized_atomics)]
type U8 = u8;
#[cfg(not(has_sized_atomics))]
type U8 = usize;

// UnparkToken used to indicate that that the target thread should attempt to
// lock the mutex again as soon as it is unparked.
pub(crate) const TOKEN_NORMAL: UnparkToken = UnparkToken(0);

// UnparkToken used to indicate that the mutex is being handed off to the target
// thread directly without unlocking it.
pub(crate) const TOKEN_HANDOFF: UnparkToken = UnparkToken(1);

const LOCKED_BIT: U8 = 1;
const PARKED_BIT: U8 = 2;

/// Raw mutex type backed by the parking lot.
pub struct RawMutex {
    state: AtomicU8,
}

unsafe impl lock_api::RawMutex for RawMutex {
    const INIT: RawMutex = RawMutex {
        state: AtomicU8::new(0),
    };

    type GuardMarker = GuardNoSend;

    #[inline]
    fn lock(&self) {
        if self
            .state
            .compare_exchange_weak(0, LOCKED_BIT, Ordering::Acquire, Ordering::Relaxed)
            .is_err()
        {
            self.lock_slow(None);
        }
        unsafe { deadlock::acquire_resource(self as *const _ as usize) };
    }

    #[inline]
    fn try_lock(&self) -> bool {
        let mut state = self.state.load(Ordering::Relaxed);
        loop {
            if state & LOCKED_BIT != 0 {
                return false;
            }
            match self.state.compare_exchange_weak(
                state,
                state | LOCKED_BIT,
                Ordering::Acquire,
                Ordering::Relaxed,
            ) {
                Ok(_) => {
                    unsafe { deadlock::acquire_resource(self as *const _ as usize) };
                    return true;
                }
                Err(x) => state = x,
            }
        }
    }

    #[inline]
    fn unlock(&self) {
        unsafe { deadlock::release_resource(self as *const _ as usize) };
        if self
            .state
            .compare_exchange(LOCKED_BIT, 0, Ordering::Release, Ordering::Relaxed)
            .is_ok()
        {
            return;
        }
        self.unlock_slow(false);
    }
}

unsafe impl lock_api::RawMutexFair for RawMutex {
    #[inline]
    fn unlock_fair(&self) {
        unsafe { deadlock::release_resource(self as *const _ as usize) };
        if self
            .state
            .compare_exchange(LOCKED_BIT, 0, Ordering::Release, Ordering::Relaxed)
            .is_ok()
        {
            return;
        }
        self.unlock_slow(true);
    }

    #[inline]
    fn bump(&self) {
        if self.state.load(Ordering::Relaxed) & PARKED_BIT != 0 {
            self.bump_slow();
        }
    }
}

unsafe impl lock_api::RawMutexTimed for RawMutex {
    type Duration = Duration;
    type Instant = Instant;

    #[inline]
    fn try_lock_until(&self, timeout: Instant) -> bool {
        let result = if self
            .state
            .compare_exchange_weak(0, LOCKED_BIT, Ordering::Acquire, Ordering::Relaxed)
            .is_ok()
        {
            true
        } else {
            self.lock_slow(Some(timeout))
        };
        if result {
            unsafe { deadlock::acquire_resource(self as *const _ as usize) };
        }
        result
    }

    #[inline]
    fn try_lock_for(&self, timeout: Duration) -> bool {
        let result = if self
            .state
            .compare_exchange_weak(0, LOCKED_BIT, Ordering::Acquire, Ordering::Relaxed)
            .is_ok()
        {
            true
        } else {
            self.lock_slow(util::to_deadline(timeout))
        };
        if result {
            unsafe { deadlock::acquire_resource(self as *const _ as usize) };
        }
        result
    }
}

impl RawMutex {
    // Used by Condvar when requeuing threads to us, must be called while
    // holding the queue lock.
    #[inline]
    pub(crate) fn mark_parked_if_locked(&self) -> bool {
        let mut state = self.state.load(Ordering::Relaxed);
        loop {
            if state & LOCKED_BIT == 0 {
                return false;
            }
            match self.state.compare_exchange_weak(
                state,
                state | PARKED_BIT,
                Ordering::Relaxed,
                Ordering::Relaxed,
            ) {
                Ok(_) => return true,
                Err(x) => state = x,
            }
        }
    }

    // Used by Condvar when requeuing threads to us, must be called while
    // holding the queue lock.
    #[inline]
    pub(crate) fn mark_parked(&self) {
        self.state.fetch_or(PARKED_BIT, Ordering::Relaxed);
    }

    #[cold]
    fn lock_slow(&self, timeout: Option<Instant>) -> bool {
        let mut spinwait = SpinWait::new();
        let mut state = self.state.load(Ordering::Relaxed);
        loop {
            // Grab the lock if it isn't locked, even if there is a queue on it
            if state & LOCKED_BIT == 0 {
                match self.state.compare_exchange_weak(
                    state,
                    state | LOCKED_BIT,
                    Ordering::Acquire,
                    Ordering::Relaxed,
                ) {
                    Ok(_) => return true,
                    Err(x) => state = x,
                }
                continue;
            }

            // If there is no queue, try spinning a few times
            if state & PARKED_BIT == 0 && spinwait.spin() {
                state = self.state.load(Ordering::Relaxed);
                continue;
            }

            // Set the parked bit
            if state & PARKED_BIT == 0 {
                if let Err(x) = self.state.compare_exchange_weak(
                    state,
                    state | PARKED_BIT,
                    Ordering::Relaxed,
                    Ordering::Relaxed,
                ) {
                    state = x;
                    continue;
                }
            }

            // Park our thread until we are woken up by an unlock
            let addr = self as *const _ as usize;
            let validate = || self.state.load(Ordering::Relaxed) == LOCKED_BIT | PARKED_BIT;
            let before_sleep = || {};
            let timed_out = |_, was_last_thread| {
                // Clear the parked bit if we were the last parked thread
                if was_last_thread {
                    self.state.fetch_and(!PARKED_BIT, Ordering::Relaxed);
                }
            };
            // SAFETY:
            //   * `addr` is an address we control.
            //   * `validate`/`timed_out` does not panic or call into any function of `parking_lot`.
            //   * `before_sleep` does not call `park`, nor does it panic.
            match unsafe {
                parking_lot_core::park(
                    addr,
                    validate,
                    before_sleep,
                    timed_out,
                    DEFAULT_PARK_TOKEN,
                    timeout,
                )
            } {
                // The thread that unparked us passed the lock on to us
                // directly without unlocking it.
                ParkResult::Unparked(TOKEN_HANDOFF) => return true,

                // We were unparked normally, try acquiring the lock again
                ParkResult::Unparked(_) => (),

                // The validation function failed, try locking again
                ParkResult::Invalid => (),

                // Timeout expired
                ParkResult::TimedOut => return false,
            }

            // Loop back and try locking again
            spinwait.reset();
            state = self.state.load(Ordering::Relaxed);
        }
    }

    #[cold]
    fn unlock_slow(&self, force_fair: bool) {
        // Unpark one thread and leave the parked bit set if there might
        // still be parked threads on this address.
        let addr = self as *const _ as usize;
        let callback = |result: UnparkResult| {
            // If we are using a fair unlock then we should keep the
            // mutex locked and hand it off to the unparked thread.
            if result.unparked_threads != 0 && (force_fair || result.be_fair) {
                // Clear the parked bit if there are no more parked
                // threads.
                if !result.have_more_threads {
                    self.state.store(LOCKED_BIT, Ordering::Relaxed);
                }
                return TOKEN_HANDOFF;
            }

            // Clear the locked bit, and the parked bit as well if there
            // are no more parked threads.
            if result.have_more_threads {
                self.state.store(PARKED_BIT, Ordering::Release);
            } else {
                self.state.store(0, Ordering::Release);
            }
            TOKEN_NORMAL
        };
        // SAFETY:
        //   * `addr` is an address we control.
        //   * `callback` does not panic or call into any function of `parking_lot`.
        unsafe {
            parking_lot_core::unpark_one(addr, callback);
        }
    }

    #[cold]
    fn bump_slow(&self) {
        unsafe { deadlock::release_resource(self as *const _ as usize) };
        self.unlock_slow(true);
        self.lock();
    }
}
<|endoftext|>