<commit_before>use std::iter::FromIterator;
use std::collections::HashSet;

use {TextRange, NodeType, File};
use regex::Regex;

pub struct Rule {
    pub ty: NodeType,
    pub re: &'static str
}

#[derive(Clone, Copy)]
pub struct Token {
    pub ty: NodeType,
    pub range: TextRange,
}

pub struct TreeBuilder {
    text: String,
    skip: HashSet<NodeType>,
    tokens: Vec<Token>,
    pending: Vec<Frame>,
    current_token: usize,
}

#[derive(Debug)]
pub struct PreNode {
    pub ty: NodeType,
    pub range: TextRange,
    pub children: Vec<PreNode>,
}

#[derive(Debug)]
struct Frame {
    ty: NodeType,
    children: Vec<PreNode>,
    start_token: usize,
}

impl TreeBuilder {
    pub fn start(&mut self, ty: NodeType) {
        self.pending.push(Frame { ty: ty, children: vec![], start_token: self.current_token })
    }

    pub fn finish(&mut self, ty: NodeType) {
        assert!(self.top().ty == ty, "Expected {:?}, got {:?}", self.top().ty, ty);
        let mut top = self.pending.pop().unwrap();

        while let Some(ty) = top.children.last().map(|n| n.ty) {
            if !self.is_skip(ty) {
                break
            }
            top.children.pop();
            self.current_token -= 1;
        }

        let first_token = self.tokens[top.start_token];
        let last_token = self.tokens[self.current_token - 1];
        assert!(!self.is_skip(first_token.ty) && !self.is_skip(last_token.ty));

        let range = TextRange {
            start: first_token.range.start,
            end: last_token.range.end,
        };
        let node = PreNode { ty: top.ty, range: range, children: top.children };
        self.top().children.push(node);
    }

    pub fn rollback(&mut self, ty: NodeType) {
        assert!(self.top().ty == ty, "Expected {:?}, got {:?}", self.top().ty, ty);
        let top = self.pending.pop().unwrap();
        self.current_token = top.start_token;
    }

    pub fn try_eat(&mut self, ty: NodeType) -> bool {
        let t = match self.current() {
            None => return false,
            Some(t) => t
        };

        if t.ty == ty {
            self.bump();
            self.do_skip();
            true
        } else {
            false
        }
    }

    pub fn skip_until(&mut self, _tys: &[NodeType]) {}

    pub fn parse_many(&mut self, f: &Fn(&mut TreeBuilder) -> bool) {
        loop {
            if !f(self) {
                break
            }
        }
    }

    pub fn next_is(&mut self, ty: NodeType) -> bool {
        self.do_skip();
        if let Some(t) = self.current() {
            t.ty == ty
        } else {
            false
        }
    }

    pub fn error(&mut self) {}

    fn new(text: String, file_type: NodeType, tokens: Vec<Token>) -> TreeBuilder {
        let skip = &[::WHITESPACE];
        let mut result = TreeBuilder {
            text: text,
            skip: skip.iter().cloned().collect(),
            tokens: tokens,
            pending: vec![Frame { ty: file_type, children: vec![], start_token: 0 }],
            current_token: 0,
        };
        result.do_skip();
        result
    }

    fn top(&mut self) -> &mut Frame {
        self.pending.last_mut().unwrap()
    }

    fn bump(&mut self) {
        let t = self.current().unwrap();
        self.current_token += 1;
        self.top().children.push(PreNode {
            ty: t.ty,
            range: t.range,
            children: vec![],
        })
    }

    fn do_skip(&mut self) {
        while let Some(t) = self.current() {
            if !self.is_skip(t.ty) {
                break;
            }
            self.bump();
        }
    }

    fn current(&self) -> Option<Token> {
        self.tokens.get(self.current_token).cloned()
    }

    fn into_file(mut self) -> File {
        while self.current().is_some() {
            self.bump();
        }
        let top = self.pending.pop().unwrap();
        assert!(self.pending.is_empty());
        ::imp::build_file(self.text, top.ty, top.children)
    }

    fn is_skip(&self, ty: NodeType) -> bool {
        self.skip.contains(&ty)
    }
}

pub fn parse(
    text: String,
    file_type: NodeType,
    tokenizer: &[Rule],
    parser: &Fn(&mut TreeBuilder)
) -> File {
    let tokens = tokenize(&text, tokenizer);
    let mut builder = TreeBuilder::new(text, file_type, tokens);
    parser(&mut builder);
    builder.into_file()
}

fn tokenize(text: &str, tokenizer: &[Rule]) -> Vec<Token> {
    let mut result = vec![];

    let rules = Vec::from_iter(
        tokenizer.iter().map(|r| (r.ty, Regex::new(&format!("^{}", r.re)).unwrap()))
    );

    let mut offset = 0;
    let mut rest = text;

    'l: while rest.len() > 0 {
        for &(ty, ref re) in rules.iter() {
            if let Some(m) = re.find(rest) {
                assert!(m.start() == 0);
                assert!(m.end() > 0);
                result.push(Token {
                    ty: ty,
                    range: TextRange { start: offset as u32, end: (offset + m.end()) as u32 },
                });
                offset += m.end();
                rest = &rest[m.end()..];
                continue 'l;
            }
        }
        let bad_char_len = rest.chars().next().unwrap().len_utf8();
        result.push(Token {
            ty: ::ERROR,
            range: TextRange { start: offset as u32, end: (offset + bad_char_len) as u32 }
        });
        offset += bad_char_len;
    }

    result
}
<commit_msg>Fix lexer nontermination<commit_after>use std::iter::FromIterator;
use std::collections::HashSet;

use {TextRange, NodeType, File};
use regex::Regex;

pub struct Rule {
    pub ty: NodeType,
    pub re: &'static str
}

#[derive(Debug, Clone, Copy)]
pub struct Token {
    pub ty: NodeType,
    pub range: TextRange,
}

pub struct TreeBuilder {
    text: String,
    skip: HashSet<NodeType>,
    tokens: Vec<Token>,
    pending: Vec<Frame>,
    current_token: usize,
}

#[derive(Debug)]
pub struct PreNode {
    pub ty: NodeType,
    pub range: TextRange,
    pub children: Vec<PreNode>,
}

#[derive(Debug)]
struct Frame {
    ty: NodeType,
    children: Vec<PreNode>,
    start_token: usize,
}

impl TreeBuilder {
    pub fn start(&mut self, ty: NodeType) {
        self.pending.push(Frame { ty: ty, children: vec![], start_token: self.current_token })
    }

    pub fn finish(&mut self, ty: NodeType) {
        assert!(self.top().ty == ty, "Expected {:?}, got {:?}", self.top().ty, ty);
        let mut top = self.pending.pop().unwrap();

        while let Some(ty) = top.children.last().map(|n| n.ty) {
            if !self.is_skip(ty) {
                break
            }
            top.children.pop();
            self.current_token -= 1;
        }

        let first_token = self.tokens[top.start_token];
        let last_token = self.tokens[self.current_token - 1];
        assert!(!self.is_skip(first_token.ty) && !self.is_skip(last_token.ty));

        let range = TextRange {
            start: first_token.range.start,
            end: last_token.range.end,
        };
        let node = PreNode { ty: top.ty, range: range, children: top.children };
        self.top().children.push(node);
    }

    pub fn rollback(&mut self, ty: NodeType) {
        assert!(self.top().ty == ty, "Expected {:?}, got {:?}", self.top().ty, ty);
        let top = self.pending.pop().unwrap();
        self.current_token = top.start_token;
    }

    pub fn try_eat(&mut self, ty: NodeType) -> bool {
        let t = match self.current() {
            None => return false,
            Some(t) => t
        };

        if t.ty == ty {
            self.bump();
            self.do_skip();
            true
        } else {
            false
        }
    }

    pub fn skip_until(&mut self, _tys: &[NodeType]) {}

    pub fn parse_many(&mut self, f: &Fn(&mut TreeBuilder) -> bool) {
        loop {
            if !f(self) {
                break
            }
        }
    }

    pub fn next_is(&mut self, ty: NodeType) -> bool {
        self.do_skip();
        if let Some(t) = self.current() {
            t.ty == ty
        } else {
            false
        }
    }

    pub fn error(&mut self) {}

    fn new(text: String, file_type: NodeType, tokens: Vec<Token>) -> TreeBuilder {
        let skip = &[::WHITESPACE];
        let mut result = TreeBuilder {
            text: text,
            skip: skip.iter().cloned().collect(),
            tokens: tokens,
            pending: vec![Frame { ty: file_type, children: vec![], start_token: 0 }],
            current_token: 0,
        };
        result.do_skip();
        result
    }

    fn top(&mut self) -> &mut Frame {
        self.pending.last_mut().unwrap()
    }

    fn bump(&mut self) {
        let t = self.current().unwrap();
        self.current_token += 1;
        self.top().children.push(PreNode {
            ty: t.ty,
            range: t.range,
            children: vec![],
        })
    }

    fn do_skip(&mut self) {
        while let Some(t) = self.current() {
            if !self.is_skip(t.ty) {
                break;
            }
            self.bump();
        }
    }

    fn current(&self) -> Option<Token> {
        self.tokens.get(self.current_token).cloned()
    }

    fn into_file(mut self) -> File {
        while self.current().is_some() {
            self.bump();
        }
        let top = self.pending.pop().unwrap();
        assert!(self.pending.is_empty());
        ::imp::build_file(self.text, top.ty, top.children)
    }

    fn is_skip(&self, ty: NodeType) -> bool {
        self.skip.contains(&ty)
    }
}

pub fn parse(
    text: String,
    file_type: NodeType,
    tokenizer: &[Rule],
    parser: &Fn(&mut TreeBuilder)
) -> File {
    let tokens = tokenize(&text, tokenizer);
    let mut builder = TreeBuilder::new(text, file_type, tokens);
    parser(&mut builder);
    builder.into_file()
}

fn tokenize(text: &str, tokenizer: &[Rule]) -> Vec<Token> {
    let mut result = vec![];

    let rules = Vec::from_iter(
        tokenizer.iter().map(|r| (r.ty, Regex::new(&format!("^{}", r.re)).unwrap()))
    );

    let mut offset = 0;
    let mut rest = text;

    'l: while rest.len() > 0 {
        for &(ty, ref re) in rules.iter() {
            if let Some(m) = re.find(rest) {
                assert!(m.start() == 0);
                assert!(m.end() > 0);
                result.push(Token {
                    ty: ty,
                    range: TextRange { start: offset as u32, end: (offset + m.end()) as u32 },
                });
                offset += m.end();
                rest = &rest[m.end()..];
                continue 'l;
            }
        }
        let bad_char_len = rest.chars().next().unwrap().len_utf8();
        result.push(Token {
            ty: ::ERROR,
            range: TextRange { start: offset as u32, end: (offset + bad_char_len) as u32 }
        });
        offset += bad_char_len;
        rest = &rest[bad_char_len..];
    }

    result
}
<|endoftext|>


<commit_before>// xfail-test

// A port of task-killjoin to use a resource to manage
// the join.

use std;
import task;

fn joinable(f: fn()) -> (task::task, comm::port<bool>) {
    resource notify(data: (comm::chan<bool>,
                           @mutable bool)) {
        let (c, v) = data;
        comm::send(c, *v);
    }
    fn wrapper(pair: (comm::chan<bool>, fn())) {
        let (c, f) = pair;
        let b = @mutable false;
        let _r = notify((c, b));
        f();
        *b = true;
    }
    let p = comm::port();
    let c = comm::chan(p);
    let t = task::spawn((c, f), wrapper);
    ret (t, p);
}

fn join(pair: (task::task, comm::port<bool>)) -> bool {
    let (_, port) = pair;
    comm::recv(port)
}

fn supervised() {
    // Yield to make sure the supervisor joins before we
    // fail. This is currently not needed because the supervisor
    // runs first, but I can imagine that changing.
    task::yield();
    fail;
}

fn supervisor() {
    // Unsupervise this task so the process doesn't return a failure status as
    // a result of the main task being killed.
    task::unsupervise();
    let f = supervised;
    join(joinable(supervised));
}

fn main() {
    join(joinable(supervisor));
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<commit_msg>remove trailing whitespace<commit_after>// xfail-test

// A port of task-killjoin to use a resource to manage
// the join.

use std;
import task;

fn joinable(f: fn()) -> (task::task, comm::port<bool>) {
    resource notify(data: (comm::chan<bool>,
                           @mutable bool)) {
        let (c, v) = data;
        comm::send(c, *v);
    }
    fn wrapper(pair: (comm::chan<bool>, fn())) {
        let (c, f) = pair;
        let b = @mutable false;
        let _r = notify((c, b));
        f();
        *b = true;
    }
    let p = comm::port();
    let c = comm::chan(p);
    let t = task::spawn((c, f), wrapper);
    ret (t, p);
}

fn join(pair: (task::task, comm::port<bool>)) -> bool {
    let (_, port) = pair;
    comm::recv(port)
}

fn supervised() {
    // Yield to make sure the supervisor joins before we
    // fail. This is currently not needed because the supervisor
    // runs first, but I can imagine that changing.
    task::yield();
    fail;
}

fn supervisor() {
    // Unsupervise this task so the process doesn't return a failure status as
    // a result of the main task being killed.
    task::unsupervise();
    let f = supervised;
    join(joinable(supervised));
}

fn main() {
    join(joinable(supervisor));
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<|endoftext|>


<commit_before>#![crate_name = "uu_cat"]

// This file is part of the uutils coreutils package.
//
// (c) Jordi Boggiano <j.boggiano@seld.be>
// (c) Evgeniy Klyuchikov <evgeniy.klyuchikov@gmail.com>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
//
#[macro_use]
extern crate uucore;

// last synced with: cat (GNU coreutils) 8.13
use std::fs::File;
use std::io::{stdout, stdin, stderr, Write, Read, BufWriter};
use uucore::fs::is_stdin_interactive;

static SYNTAX: &'static str = "[OPTION]... [FILE]...";
static SUMMARY: &'static str = "Concatenate FILE(s), or standard input, to standard output
 With no FILE, or when FILE is -, read standard input.";
static LONG_HELP: &'static str = "";

pub fn uumain(args: Vec<String>) -> i32 {
    let matches = new_coreopts!(SYNTAX, SUMMARY, LONG_HELP)
        .optflag("A", "show-all", "equivalent to -vET")
        .optflag("b",
                 "number-nonblank",
                 "number nonempty output lines, overrides -n")
        .optflag("e", "", "equivalent to -vE")
        .optflag("E", "show-ends", "display $ at end of each line")
        .optflag("n", "number", "number all output lines")
        .optflag("s", "squeeze-blank", "suppress repeated empty output lines")
        .optflag("t", "", "equivalent to -vT")
        .optflag("T", "show-tabs", "display TAB characters as ^I")
        .optflag("v",
                 "show-nonprinting",
                 "use ^ and M- notation, except for LF (\\n) and TAB (\\t)")
        .parse(args);

    let number_mode = if matches.opt_present("b") {
        NumberingMode::NumberNonEmpty
    } else if matches.opt_present("n") {
        NumberingMode::NumberAll
    } else {
        NumberingMode::NumberNone
    };
    let show_nonprint =
        matches.opts_present(&["A".to_owned(), "e".to_owned(), "t".to_owned(), "v".to_owned()]);
    let show_ends = matches.opts_present(&["E".to_owned(), "A".to_owned(), "e".to_owned()]);
    let show_tabs = matches.opts_present(&["A".to_owned(), "T".to_owned(), "t".to_owned()]);
    let squeeze_blank = matches.opt_present("s");
    let mut files = matches.free;
    if files.is_empty() {
        files.push("-".to_owned());
    }

    if show_tabs || show_nonprint || show_ends || squeeze_blank ||
       number_mode != NumberingMode::NumberNone {
        write_lines(files,
                    number_mode,
                    squeeze_blank,
                    show_ends,
                    show_tabs,
                    show_nonprint);
    } else {
        write_fast(files);
    }
    pipe_flush!();

    0
}

#[derive(PartialEq)]
enum NumberingMode {
    NumberNone,
    NumberNonEmpty,
    NumberAll,
}

fn open(path: &str) -> Option<(Box<Read>, bool)> {
    if path == "-" {
        let stdin = stdin();
        return Some((Box::new(stdin) as Box<Read>, is_stdin_interactive()));
    }

    match File::open(path) {
        Ok(f) => Some((Box::new(f) as Box<Read>, false)),
        Err(e) => {
            (writeln!(&mut stderr(), "cat: {0}: {1}", path, e.to_string())).unwrap();
            None
        }
    }
}

fn write_fast(files: Vec<String>) {
    let mut writer = stdout();
    let mut in_buf = [0; 1024 * 64];

    for (mut reader, _) in files.iter().filter_map(|p| open(&p[..])) {
        while let Ok(n) = reader.read(&mut in_buf) {
            if n == 0 {
                break;
            }
            writer.write_all(&in_buf[..n]).unwrap();
        }
    }
}

fn write_lines(files: Vec<String>,
               number: NumberingMode,
               squeeze_blank: bool,
               show_ends: bool,
               show_tabs: bool,
               show_nonprint: bool) {
    // initialize end of line
    let end_of_line = if show_ends {
        "$\n".as_bytes()
    } else {
        "\n".as_bytes()
    };
    // initialize tab simbol
    let tab = if show_tabs {
        "^I".as_bytes()
    } else {
        "\t".as_bytes()
    };
    let mut line_counter: usize = 1;

    for (mut reader, interactive) in files.iter().filter_map(|p| open(&p[..])) {
        let mut in_buf = [0; 1024 * 31];
        let mut writer = BufWriter::with_capacity(1024 * 64, stdout());
        let mut at_line_start = true;
        let mut one_blank_kept = false;
        while let Ok(n) = reader.read(&mut in_buf) {
            if n == 0 {
                break;
            }
            let in_buf = &in_buf[..n];
            let mut pos = 0;
            while pos < n {
                // skip empty lines enumerating them if needed
                if in_buf[pos] == '\n' as u8 {
                    if !at_line_start || !squeeze_blank || !one_blank_kept {
                        one_blank_kept = true;
                        if at_line_start && number == NumberingMode::NumberAll {
                            (write!(&mut writer, "{0:6}\t", line_counter)).unwrap();
                            line_counter += 1;
                        }
                        writer.write_all(end_of_line).unwrap();
                        if interactive {
                            writer.flush().unwrap();
                        }
                    }
                    at_line_start = true;
                    pos += 1;
                    continue;
                }
                one_blank_kept = false;
                if at_line_start && number != NumberingMode::NumberNone {
                    (write!(&mut writer, "{0:6}\t", line_counter)).unwrap();
                    line_counter += 1;
                }

                // print to end of line or end of buffer
                let offset = if show_nonprint {
                    write_nonprint_to_end(&in_buf[pos..], &mut writer, tab)
                } else if show_tabs {
                    write_tab_to_end(&in_buf[pos..], &mut writer)
                } else {
                    write_to_end(&in_buf[pos..], &mut writer)
                };
                // end of buffer?
                if offset == 0 {
                    at_line_start = false;
                    break;
                }
                // print suitable end of line
                writer.write_all(end_of_line).unwrap();
                if interactive {
                    writer.flush().unwrap();
                }
                at_line_start = true;
                pos += offset;
            }
        }
    }
}

// write***_to_end methods
// Write all simbols till end of line or end of buffer
// Return the number of written bytes - 1 or 0 if the end of buffer is reached
fn write_to_end<W: Write>(in_buf: &[u8], writer: &mut W) -> usize {
    match in_buf.iter().position(|c| *c == '\n' as u8) {
        Some(p) => {
            writer.write_all(&in_buf[..p]).unwrap();
            p + 1
        }
        None => {
            writer.write_all(in_buf).unwrap();
            0
        }
    }
}

fn write_tab_to_end<W: Write>(in_buf: &[u8], writer: &mut W) -> usize {
    match in_buf.iter().position(|c| *c == '\n' as u8 || *c == '\t' as u8) {
        Some(p) => {
            writer.write_all(&in_buf[..p]).unwrap();
            if in_buf[p] == '\n' as u8 {
                p + 1
            } else {
                writer.write_all("^I".as_bytes()).unwrap();
                write_tab_to_end(&in_buf[p + 1..], writer)
            }
        }
        None => {
            writer.write_all(in_buf).unwrap();
            0
        }
    }
}

fn write_nonprint_to_end<W: Write>(in_buf: &[u8], writer: &mut W, tab: &[u8]) -> usize {
    let mut count = 0;

    for byte in in_buf.iter().map(|c| *c) {
        if byte == '\n' as u8 {
            break;
        }
        match byte {
                9 => writer.write_all(tab),
                0...8 | 10...31 => writer.write_all(&['^' as u8, byte + 64]),
                32...126 => writer.write_all(&[byte]),
                127 => writer.write_all(&['^' as u8, byte - 64]),
                128...159 => writer.write_all(&['M' as u8, '-' as u8, '^' as u8, byte - 64]),
                160...254 => writer.write_all(&['M' as u8, '-' as u8, byte - 128]),
                _ => writer.write_all(&['M' as u8, '-' as u8, '^' as u8, 63]),
            }
            .unwrap();
        count += 1;
    }
    if count != in_buf.len() { count + 1 } else { 0 }
}<commit_msg>cat: remove recursion<commit_after>#![crate_name = "uu_cat"]

// This file is part of the uutils coreutils package.
//
// (c) Jordi Boggiano <j.boggiano@seld.be>
// (c) Evgeniy Klyuchikov <evgeniy.klyuchikov@gmail.com>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
//
#[macro_use]
extern crate uucore;

// last synced with: cat (GNU coreutils) 8.13
use std::fs::File;
use std::io::{stdout, stdin, stderr, Write, Read, BufWriter};
use uucore::fs::is_stdin_interactive;

static SYNTAX: &'static str = "[OPTION]... [FILE]...";
static SUMMARY: &'static str = "Concatenate FILE(s), or standard input, to standard output
 With no FILE, or when FILE is -, read standard input.";
static LONG_HELP: &'static str = "";

pub fn uumain(args: Vec<String>) -> i32 {
    let matches = new_coreopts!(SYNTAX, SUMMARY, LONG_HELP)
        .optflag("A", "show-all", "equivalent to -vET")
        .optflag("b",
                 "number-nonblank",
                 "number nonempty output lines, overrides -n")
        .optflag("e", "", "equivalent to -vE")
        .optflag("E", "show-ends", "display $ at end of each line")
        .optflag("n", "number", "number all output lines")
        .optflag("s", "squeeze-blank", "suppress repeated empty output lines")
        .optflag("t", "", "equivalent to -vT")
        .optflag("T", "show-tabs", "display TAB characters as ^I")
        .optflag("v",
                 "show-nonprinting",
                 "use ^ and M- notation, except for LF (\\n) and TAB (\\t)")
        .parse(args);

    let number_mode = if matches.opt_present("b") {
        NumberingMode::NumberNonEmpty
    } else if matches.opt_present("n") {
        NumberingMode::NumberAll
    } else {
        NumberingMode::NumberNone
    };
    let show_nonprint =
        matches.opts_present(&["A".to_owned(), "e".to_owned(), "t".to_owned(), "v".to_owned()]);
    let show_ends = matches.opts_present(&["E".to_owned(), "A".to_owned(), "e".to_owned()]);
    let show_tabs = matches.opts_present(&["A".to_owned(), "T".to_owned(), "t".to_owned()]);
    let squeeze_blank = matches.opt_present("s");
    let mut files = matches.free;
    if files.is_empty() {
        files.push("-".to_owned());
    }

    if show_tabs || show_nonprint || show_ends || squeeze_blank ||
       number_mode != NumberingMode::NumberNone {
        write_lines(files,
                    number_mode,
                    squeeze_blank,
                    show_ends,
                    show_tabs,
                    show_nonprint);
    } else {
        write_fast(files);
    }
    pipe_flush!();

    0
}

#[derive(PartialEq)]
enum NumberingMode {
    NumberNone,
    NumberNonEmpty,
    NumberAll,
}

fn open(path: &str) -> Option<(Box<Read>, bool)> {
    if path == "-" {
        let stdin = stdin();
        return Some((Box::new(stdin) as Box<Read>, is_stdin_interactive()));
    }

    match File::open(path) {
        Ok(f) => Some((Box::new(f) as Box<Read>, false)),
        Err(e) => {
            (writeln!(&mut stderr(), "cat: {0}: {1}", path, e.to_string())).unwrap();
            None
        }
    }
}

fn write_fast(files: Vec<String>) {
    let mut writer = stdout();
    let mut in_buf = [0; 1024 * 64];

    for (mut reader, _) in files.iter().filter_map(|p| open(&p[..])) {
        while let Ok(n) = reader.read(&mut in_buf) {
            if n == 0 {
                break;
            }
            writer.write_all(&in_buf[..n]).unwrap();
        }
    }
}

fn write_lines(files: Vec<String>,
               number: NumberingMode,
               squeeze_blank: bool,
               show_ends: bool,
               show_tabs: bool,
               show_nonprint: bool) {
    // initialize end of line
    let end_of_line = if show_ends {
        "$\n".as_bytes()
    } else {
        "\n".as_bytes()
    };
    // initialize tab simbol
    let tab = if show_tabs {
        "^I".as_bytes()
    } else {
        "\t".as_bytes()
    };
    let mut line_counter: usize = 1;

    for (mut reader, interactive) in files.iter().filter_map(|p| open(&p[..])) {
        let mut in_buf = [0; 1024 * 31];
        let mut writer = BufWriter::with_capacity(1024 * 64, stdout());
        let mut at_line_start = true;
        let mut one_blank_kept = false;
        while let Ok(n) = reader.read(&mut in_buf) {
            if n == 0 {
                break;
            }
            let in_buf = &in_buf[..n];
            let mut pos = 0;
            while pos < n {
                // skip empty lines enumerating them if needed
                if in_buf[pos] == '\n' as u8 {
                    if !at_line_start || !squeeze_blank || !one_blank_kept {
                        one_blank_kept = true;
                        if at_line_start && number == NumberingMode::NumberAll {
                            (write!(&mut writer, "{0:6}\t", line_counter)).unwrap();
                            line_counter += 1;
                        }
                        writer.write_all(end_of_line).unwrap();
                        if interactive {
                            writer.flush().unwrap();
                        }
                    }
                    at_line_start = true;
                    pos += 1;
                    continue;
                }
                one_blank_kept = false;
                if at_line_start && number != NumberingMode::NumberNone {
                    (write!(&mut writer, "{0:6}\t", line_counter)).unwrap();
                    line_counter += 1;
                }

                // print to end of line or end of buffer
                let offset = if show_nonprint {
                    write_nonprint_to_end(&in_buf[pos..], &mut writer, tab)
                } else if show_tabs {
                    write_tab_to_end(&in_buf[pos..], &mut writer)
                } else {
                    write_to_end(&in_buf[pos..], &mut writer)
                };
                // end of buffer?
                if offset == 0 {
                    at_line_start = false;
                    break;
                }
                // print suitable end of line
                writer.write_all(end_of_line).unwrap();
                if interactive {
                    writer.flush().unwrap();
                }
                at_line_start = true;
                pos += offset;
            }
        }
    }
}

// write***_to_end methods
// Write all symbols till end of line or end of buffer is reached
// Return the (number of written symbols + 1) or 0 if the end of buffer is reached
fn write_to_end<W: Write>(in_buf: &[u8], writer: &mut W) -> usize {
    match in_buf.iter().position(|c| *c == '\n' as u8) {
        Some(p) => {
            writer.write_all(&in_buf[..p]).unwrap();
            p + 1
        }
        None => {
            writer.write_all(in_buf).unwrap();
            0
        }
    }
}

fn write_tab_to_end<W: Write>(mut in_buf: &[u8], writer: &mut W) -> usize {
    loop {
        match in_buf.iter().position(|c| *c == '\n' as u8 || *c == '\t' as u8) {
            Some(p) => {
                writer.write_all(&in_buf[..p]).unwrap();
                if in_buf[p] == '\n' as u8 {
                    return p + 1;
                } else {
                    writer.write_all("^I".as_bytes()).unwrap();
                    in_buf = &in_buf[p + 1..];
                }
            }
            None => {
                writer.write_all(in_buf).unwrap();
                return 0;
            }
        };
    }
}

fn write_nonprint_to_end<W: Write>(in_buf: &[u8], writer: &mut W, tab: &[u8]) -> usize {
    let mut count = 0;

    for byte in in_buf.iter().map(|c| *c) {
        if byte == '\n' as u8 {
            break;
        }
        match byte {
                9 => writer.write_all(tab),
                0...8 | 10...31 => writer.write_all(&['^' as u8, byte + 64]),
                32...126 => writer.write_all(&[byte]),
                127 => writer.write_all(&['^' as u8, byte - 64]),
                128...159 => writer.write_all(&['M' as u8, '-' as u8, '^' as u8, byte - 64]),
                160...254 => writer.write_all(&['M' as u8, '-' as u8, byte - 128]),
                _ => writer.write_all(&['M' as u8, '-' as u8, '^' as u8, 63]),
            }
            .unwrap();
        count += 1;
    }
    if count != in_buf.len() { count + 1 } else { 0 }
}
<|endoftext|>


<commit_before>// This issue reproduces an ICE on compile
// Fails on 2020-02-08 nightly
// regressed commit: https://github.com/rust-lang/rust/commit/f8fd4624474a68bd26694eff3536b9f3a127b2d3
//
// check-pass

#![feature(generator_trait)]
#![feature(generators)]

use std::ops::Generator;

fn gen() -> impl Generator<usize> {
    |_: usize| {
        println!("-> {}", yield);
    }
}
<commit_msg>add main function to issue-69017 test<commit_after>// This issue reproduces an ICE on compile
// Fails on 2020-02-08 nightly
// regressed commit: https://github.com/rust-lang/rust/commit/f8fd4624474a68bd26694eff3536b9f3a127b2d3
//
// check-pass

#![feature(generator_trait)]
#![feature(generators)]

use std::ops::Generator;

fn gen() -> impl Generator<usize> {
    |_: usize| {
        println!("-> {}", yield);
    }
}

fn main() {}
<|endoftext|>


<commit_before>// check-pass

#![allow(unused)]

use std::borrow::Borrow;
use std::ops::Deref;

struct Foo<T>(T);

#[derive(Clone)]
struct Bar<T>(T);

struct DerefExample<T>(T);

impl<T> Deref for DerefExample<T> {
    type Target = T;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

fn main() {
    let foo = &Foo(1u32);
    let foo_clone: &Foo<u32> = foo.clone();
    //~^ WARNING call to `.clone()` on a reference in this situation does nothing [noop_method_call]

    let bar = &Bar(1u32);
    let bar_clone: Bar<u32> = bar.clone();

    let deref = &&DerefExample(12u32);
    let derefed: &DerefExample<u32> = deref.deref();
    //~^ WARNING call to `.deref()` on a reference in this situation does nothing [noop_method_call]

    let deref = &DerefExample(12u32);
    let derefed: &u32 = deref.deref();

    let a = &&Foo(1u32);
    let borrowed: &Foo<u32> = a.borrow();
    //~^ WARNING call to `.borrow()` on a reference in this situation does nothing [noop_method_call]
}

fn generic<T>(foo: &Foo<T>) {
    foo.clone();
}

fn non_generic(foo: &Foo<u32>) {
    foo.clone();
    //~^ WARNING call to `.clone()` on a reference in this situation does nothing [noop_method_call]
}
<commit_msg>Fix tidy error<commit_after>// check-pass

#![allow(unused)]

use std::borrow::Borrow;
use std::ops::Deref;

struct Foo<T>(T);

#[derive(Clone)]
struct Bar<T>(T);

struct DerefExample<T>(T);

impl<T> Deref for DerefExample<T> {
    type Target = T;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

fn main() {
    let foo = &Foo(1u32);
    let foo_clone: &Foo<u32> = foo.clone();
    //~^ WARNING call to `.clone()` on a reference in this situation does nothing

    let bar = &Bar(1u32);
    let bar_clone: Bar<u32> = bar.clone();

    let deref = &&DerefExample(12u32);
    let derefed: &DerefExample<u32> = deref.deref();
    //~^ WARNING call to `.deref()` on a reference in this situation does nothing

    let deref = &DerefExample(12u32);
    let derefed: &u32 = deref.deref();

    let a = &&Foo(1u32);
    let borrowed: &Foo<u32> = a.borrow();
    //~^ WARNING call to `.borrow()` on a reference in this situation does nothing
}

fn generic<T>(foo: &Foo<T>) {
    foo.clone();
}

fn non_generic(foo: &Foo<u32>) {
    foo.clone();
    //~^ WARNING call to `.clone()` on a reference in this situation does nothing
}
<|endoftext|>


<commit_before>use std::io::Cursor;

use byteorder::BigEndian;

pub fn encode<'a, I>(iter: I) -> Encode<I>
where
    I: Iterator<Item = &'a [u8]>,
{
    Encode {
        iter: iter,
        cur: Cursor::new(vec!()),
    }
}

pub fn decode<R>(buf: R) -> Decode<R>
where
    R: std::io::Read,
{
    Decode {
        buf: buf,
    }
}

pub struct Encode<I> {
    iter: I,
    cur: Cursor<Vec<u8>>,
}

impl<'a, I> Encode<I>
where
    I: Iterator<Item = &'a [u8]>,
{
    fn is_empty(&self) -> bool {
        self.cur.position() == self.cur.get_ref().len() as u64
    }

    fn pull(&mut self) -> std::io::Result<()> {
        use std::io::Write as _;
        use byteorder::WriteBytesExt as _;

        let data = match self.iter.next() {
            Some(data) => data,
            None => return Ok(()),
        };

        self.cur.get_mut().clear();
        self.cur.set_position(0);

        self.cur.write_u64::<BigEndian>(data.len() as u64)?;
        self.cur.write_all(data)?;

        Ok(())
    }
}

impl<'a, I> std::io::Read for Encode<I>
where
    I: Iterator<Item = &'a [u8]>,
{
    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
        if self.is_empty() {
            self.pull()?;
        }

        self.cur.read(buf)
    }
}

pub struct Decode<R> {
    buf: R,
}

impl<R: std::io::Read> Decode<R> {

    fn read_len(&mut self) -> std::io::Result<Option<usize>> {
        use byteorder::ReadBytesExt as _;

        let mut buf = [0; 8];
        match self.buf.read(&mut buf[..])? {
            8 => (),
            0 => return Ok(None),
            _ => return Err(SizeTagError.into()),
        }

        let len = (&buf[..]).read_u64::<BigEndian>()? as usize;
        Ok(Some(len))
    }
}

impl<R: std::io::Read> Iterator for Decode<R> {

    type Item = std::io::Result<Vec<u8>>;

    fn next(&mut self) -> Option<std::io::Result<Vec<u8>>> {
        let len = match self.read_len() {
            Ok(Some(len)) => len,
            Ok(None) => return None,
            Err(error) => return Some(Err(error)),
        };

        let mut buf = vec!(0; len);
        match self.buf.read_exact(&mut buf[..]) {
            Ok(()) => (),
            Err(error) => return Some(Err(error)),
        }

        Some(Ok(buf))
    }
}

#[derive(Debug)]
struct SizeTagError;

impl std::fmt::Display for SizeTagError {

    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(fmt, "incorrect length of the size tag")
    }
}

impl std::error::Error for SizeTagError {
}

impl From<SizeTagError> for std::io::Error {

    fn from(error: SizeTagError) -> std::io::Error {
        std::io::Error::new(std::io::ErrorKind::InvalidData, error)
    }
}
<commit_msg>Fix a bug with cursor position not being reset.<commit_after>use std::io::Cursor;

use byteorder::BigEndian;

pub fn encode<'a, I>(iter: I) -> Encode<I>
where
    I: Iterator<Item = &'a [u8]>,
{
    Encode {
        iter: iter,
        cur: Cursor::new(vec!()),
    }
}

pub fn decode<R>(buf: R) -> Decode<R>
where
    R: std::io::Read,
{
    Decode {
        buf: buf,
    }
}

pub struct Encode<I> {
    iter: I,
    cur: Cursor<Vec<u8>>,
}

impl<'a, I> Encode<I>
where
    I: Iterator<Item = &'a [u8]>,
{
    fn is_empty(&self) -> bool {
        self.cur.position() == self.cur.get_ref().len() as u64
    }

    fn pull(&mut self) -> std::io::Result<()> {
        use std::io::Write as _;
        use byteorder::WriteBytesExt as _;

        let data = match self.iter.next() {
            Some(data) => data,
            None => return Ok(()),
        };

        self.cur.get_mut().clear();
        self.cur.set_position(0);

        self.cur.write_u64::<BigEndian>(data.len() as u64)?;
        self.cur.write_all(data)?;
        self.cur.set_position(0);

        Ok(())
    }
}

impl<'a, I> std::io::Read for Encode<I>
where
    I: Iterator<Item = &'a [u8]>,
{
    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
        if self.is_empty() {
            self.pull()?;
        }

        self.cur.read(buf)
    }
}

pub struct Decode<R> {
    buf: R,
}

impl<R: std::io::Read> Decode<R> {

    fn read_len(&mut self) -> std::io::Result<Option<usize>> {
        use byteorder::ReadBytesExt as _;

        let mut buf = [0; 8];
        match self.buf.read(&mut buf[..])? {
            8 => (),
            0 => return Ok(None),
            _ => return Err(SizeTagError.into()),
        }

        let len = (&buf[..]).read_u64::<BigEndian>()? as usize;
        Ok(Some(len))
    }
}

impl<R: std::io::Read> Iterator for Decode<R> {

    type Item = std::io::Result<Vec<u8>>;

    fn next(&mut self) -> Option<std::io::Result<Vec<u8>>> {
        let len = match self.read_len() {
            Ok(Some(len)) => len,
            Ok(None) => return None,
            Err(error) => return Some(Err(error)),
        };

        let mut buf = vec!(0; len);
        match self.buf.read_exact(&mut buf[..]) {
            Ok(()) => (),
            Err(error) => return Some(Err(error)),
        }

        Some(Ok(buf))
    }
}

#[derive(Debug)]
struct SizeTagError;

impl std::fmt::Display for SizeTagError {

    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(fmt, "incorrect length of the size tag")
    }
}

impl std::error::Error for SizeTagError {
}

impl From<SizeTagError> for std::io::Error {

    fn from(error: SizeTagError) -> std::io::Error {
        std::io::Error::new(std::io::ErrorKind::InvalidData, error)
    }
}
<|endoftext|>


<commit_before>use ForthResult;
use error::Error::{UnknownWord, SyntaxError};
use stack::Stack;
use std::result::Result::{Ok, Err};
use word::Word;
use word::WordKind::{Builtin, Words};

#[deriving(Default)]
pub struct Context {
    stack: Stack,
    dict: Vec<Word>,
    compiling_word: Option<Word>,
}

impl Context {
    pub fn new() -> Context {
        Context {
            stack: Stack::new(),
            dict: Vec::new(),
            compiling_word: None,
        }
    }

    pub fn add_word(&mut self, word: Word) {
        self.dict.push(word);
    }

    fn real_run_word(dict: &Vec<Word>, stack: &mut Stack,
                     command: &str) -> ForthResult {
        for word in dict.iter() {
            if command == word.command {
                match word.kind {
                    Builtin(ref f) => try!((**f).call((stack,))),
                    Words(ref ws) => for w in ws.iter() {
                        try!(Context::real_run_word(dict, stack, w.as_slice()));
                    },
                }
                return Ok(());
            }
        }
        let i = try!(command.parse().ok_or(UnknownWord));
        stack.push(i);
        Ok(())
    }

    pub fn run_word(&mut self, command: &str) -> ForthResult {
        Context::real_run_word(&self.dict, &mut self.stack, command)
    }

    pub fn parse_line(&mut self, line: &str) -> ForthResult {
        let mut tokens = line.trim_right_chars('\n').split(' ');
        loop {
            let token = match tokens.next() {
                Some(t) => t,
                None => break,
            };
            match token {
                ":" => {
                    match self.compiling_word {
                        None => {
                            let command = try!(tokens.next().ok_or(SyntaxError));
                            self.compiling_word = Some(Word {
                                command: String::from_str(command),
                                kind: Words(Vec::new())
                            });
                        }
                        Some(..) => return Err(SyntaxError),
                    }
                },
                ";" => {
                    match self.compiling_word.take() {
                        Some(word) => {
                            self.dict.push(word);
                        },
                        None => return Err(SyntaxError),
                    }
                },
                word => {
                    match self.compiling_word {
                        Some(ref mut partial_word) => {
                            match partial_word.kind {
                                Words(ref mut ws) => ws.push(String::from_str(word)),
                                _ => panic!("compiling_word not Words kind"),
                            }
                        },
                        None => try!(self.run_word(word)),
                    }
                },
            }
        }
        debug!("stack={}", self.stack);
        Ok(())
    }
}
<commit_msg>Use find() rather than a loop on dict.iter()<commit_after>use ForthResult;
use error::Error::{UnknownWord, SyntaxError};
use stack::Stack;
use std::result::Result::{Ok, Err};
use word::Word;
use word::WordKind::{Builtin, Words};

#[deriving(Default)]
pub struct Context {
    stack: Stack,
    dict: Vec<Word>,
    compiling_word: Option<Word>,
}

impl Context {
    pub fn new() -> Context {
        Context {
            stack: Stack::new(),
            dict: Vec::new(),
            compiling_word: None,
        }
    }

    pub fn add_word(&mut self, word: Word) {
        self.dict.push(word);
    }

    fn real_run_word(dict: &Vec<Word>, stack: &mut Stack,
                     command: &str) -> ForthResult {
        match dict.iter().find(|word| word.command == command) {
            Some(word) => match word.kind {
                    Builtin(ref f) => try!((**f).call((stack,))),
                    Words(ref ws) => for w in ws.iter() {
                        try!(Context::real_run_word(dict, stack, w.as_slice()));
                    },
            },
            None => {
                let i = try!(command.parse().ok_or(UnknownWord));
                stack.push(i);
            },
        }
        Ok(())
    }

    pub fn run_word(&mut self, command: &str) -> ForthResult {
        Context::real_run_word(&self.dict, &mut self.stack, command)
    }

    pub fn parse_line(&mut self, line: &str) -> ForthResult {
        let mut tokens = line.trim_right_chars('\n').split(' ');
        loop {
            let token = match tokens.next() {
                Some(t) => t,
                None => break,
            };
            match token {
                ":" => {
                    match self.compiling_word {
                        None => {
                            let command = try!(tokens.next().ok_or(SyntaxError));
                            self.compiling_word = Some(Word {
                                command: String::from_str(command),
                                kind: Words(Vec::new())
                            });
                        }
                        Some(..) => return Err(SyntaxError),
                    }
                },
                ";" => {
                    match self.compiling_word.take() {
                        Some(word) => {
                            self.dict.push(word);
                        },
                        None => return Err(SyntaxError),
                    }
                },
                word => {
                    match self.compiling_word {
                        Some(ref mut partial_word) => {
                            match partial_word.kind {
                                Words(ref mut ws) => ws.push(String::from_str(word)),
                                _ => panic!("compiling_word not Words kind"),
                            }
                        },
                        None => try!(self.run_word(word)),
                    }
                },
            }
        }
        debug!("stack={}", self.stack);
        Ok(())
    }
}
<|endoftext|>


<commit_before>//! A couple of functions to enable and disable coloring.

use std::default::Default;
use std::env;
use std::sync::atomic::{AtomicBool, Ordering};

/// Sets a flag to the console to use a virtual terminal environment.
/// This is primarily used for Windows 10 environments which will not correctly colorize the outputs based on ansi escape codes.
///
/// # Notes
/// > Only available to `Windows` build targets.
///
/// # Example
/// ```rust
/// use colored::*;
/// control::set_virtual_terminal(false);
/// println!("{}", "bright cyan".bright_cyan());	// will print 'bright cyan' on windows 10
///
/// control::set_virtual_terminal(true);
/// println!("{}", "bright cyan".bright_cyan());	// will print correctly
/// ```
#[cfg(windows)]
pub fn set_virtual_terminal(use_virtual: bool) {
    use winapi::{
        shared::minwindef::DWORD,
        um::{
            consoleapi::{GetConsoleMode, SetConsoleMode},
            processenv::GetStdHandle,
            winbase::STD_OUTPUT_HANDLE,
            wincon::ENABLE_VIRTUAL_TERMINAL_PROCESSING,
        }
    };

    unsafe {
        let handle = GetStdHandle(STD_OUTPUT_HANDLE);
        let mut original_mode: DWORD = 0;
        GetConsoleMode(handle, &mut original_mode);

        let enabled = original_mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING == ENABLE_VIRTUAL_TERMINAL_PROCESSING;

        match (use_virtual, enabled) {
            // not enabled, should be enabled
            (true, false) => SetConsoleMode(handle, ENABLE_VIRTUAL_TERMINAL_PROCESSING | original_mode),
            // already enabled, should be disabled
            (false, true) => SetConsoleMode(handle, ENABLE_VIRTUAL_TERMINAL_PROCESSING ^ original_mode),
            _ => 0,
        };
    }
}

pub struct ShouldColorize {
    clicolor: Option<bool>,
    clicolor_force: Option<bool>,
    // XXX we can't use Option<Atomic> because we can't use &mut references to ShouldColorize
    has_manual_override: AtomicBool,
    manual_override: AtomicBool,
}

/// Use this to force colored to ignore the environment and always/never colorize
/// See example/control.rs
pub fn set_override(override_colorize: bool) {
    SHOULD_COLORIZE.set_override(override_colorize)
}

/// Remove the manual override and let the environment decide if it's ok to colorize
/// See example/control.rs
pub fn unset_override() {
    SHOULD_COLORIZE.unset_override()
}

lazy_static! {
    pub static ref SHOULD_COLORIZE: ShouldColorize = ShouldColorize::from_env();
}

impl Default for ShouldColorize {
    fn default() -> ShouldColorize {
        ShouldColorize {
            clicolor: None,
            clicolor_force: None,
            has_manual_override: AtomicBool::new(false),
            manual_override: AtomicBool::new(false),
        }
    }
}

impl ShouldColorize {
    /// Reads environment variables to determine whether colorization should
    /// be used or not. `CLICOLOR_FORCE` takes highest priority, followed by
    /// `NO_COLOR`, followed by `CLICOLOR`. In the absence of manual overrides,
    /// which take precedence over all environment variables, the priority
    /// of these variables can be expressed as follows.
    ///
    /// `NO_COLOR`  | `CLICOLOR`          | `CLICOLOR_FORCE`   | colorize?
    /// :---------  | :---------          | :---------------   | :--------
    /// unset       | unset               | unset              | true (default)
    /// unset       | `!= 0`              | unset              | true
    /// unset       | `== 0`              | unset              | false
    /// set         | unset/`== 0`/`!= 0` | unset              | false
    /// set/unset   | unset/`== 0`/`!= 0` | `== 0`             | false
    /// set/unset   | unset/`== 0`/`!= 0` | `!= 0`             | true
    pub fn from_env() -> Self {
        use std::io;

        ShouldColorize {
            clicolor: ShouldColorize::normalize_env(env::var("CLICOLOR")),
            clicolor_force: ShouldColorize::resolve_clicolor_force(
                env::var("NO_COLOR"),
                env::var("CLICOLOR_FORCE"),
            ),
            ..ShouldColorize::default()
        }
    }

    pub fn should_colorize(&self) -> bool {
        if self.has_manual_override.load(Ordering::Relaxed) {
            return self.manual_override.load(Ordering::Relaxed);
        }

        if let Some(forced_value) = self.clicolor_force {
            return forced_value;
        }

        if let Some(value) = self.clicolor {
            return value;
        }

        true
    }

    pub fn set_override(&self, override_colorize: bool) {
        self.has_manual_override.store(true, Ordering::Relaxed);
        self.manual_override
            .store(override_colorize, Ordering::Relaxed);
    }

    pub fn unset_override(&self) {
        self.has_manual_override.store(false, Ordering::Relaxed);
    }

    /* private */

    fn normalize_env(env_res: Result<String, env::VarError>) -> Option<bool> {
        match env_res {
            Ok(string) => Some(string != "0"),
            Err(_) => None,
        }
    }

    fn resolve_clicolor_force(
        no_color: Result<String, env::VarError>,
        clicolor_force: Result<String, env::VarError>,
    ) -> Option<bool> {
        match (
            ShouldColorize::normalize_env(no_color),
            ShouldColorize::normalize_env(clicolor_force),
        ) {
            (_, Some(b)) => Some(b),
            (Some(_), None) => Some(false),
            (None, None) => None,
        }
    }
}

#[cfg(test)]
mod specs {
    use super::*;
    use rspec;
    use rspec::context::*;
    use std::env;

    #[test]
    fn clicolor_behavior() {
        use std::io;

        let stdout = &mut io::stdout();
        let mut formatter = rspec::formatter::Simple::new(stdout);
        let mut runner = describe("ShouldColorize", |ctx| {
            ctx.describe("::normalize_env", |ctx| {
                ctx.it("should return None if error", || {
                    assert_eq!(
                        None,
                        ShouldColorize::normalize_env(Err(env::VarError::NotPresent))
                    );
                    assert_eq!(
                        None,
                        ShouldColorize::normalize_env(Err(env::VarError::NotUnicode("".into())))
                    )
                });

                ctx.it("should return Some(true) if != 0", || {
                    Some(true) == ShouldColorize::normalize_env(Ok(String::from("1")))
                });

                ctx.it("should return Some(false) if == 0", || {
                    Some(false) == ShouldColorize::normalize_env(Ok(String::from("0")))
                });
            });

            ctx.describe("::resolve_clicolor_force", |ctx| {
                ctx.it(
                    "should return None if neither NO_COLOR nor CLICOLOR_FORCE are set",
                    || {
                        assert_eq!(
                            None,
                            ShouldColorize::resolve_clicolor_force(
                                Err(env::VarError::NotPresent),
                                Err(env::VarError::NotPresent)
                            )
                        );
                    },
                );

                ctx.it(
                    "should return Some(false) if NO_COLOR is set and CLICOLOR_FORCE is unset",
                    || {
                        assert_eq!(
                            Some(false),
                            ShouldColorize::resolve_clicolor_force(
                                Ok(String::from("0")),
                                Err(env::VarError::NotPresent)
                            )
                        );
                        assert_eq!(
                            Some(false),
                            ShouldColorize::resolve_clicolor_force(
                                Ok(String::from("1")),
                                Err(env::VarError::NotPresent)
                            )
                        );
                    },
                );

                ctx.it(
                    "should ignore NO_COLOR and return Some(forced_value) if CLICOLOR_FORCE is set to forced_value",
                    || {
                        assert_eq!(
                            Some(true),
                            ShouldColorize::resolve_clicolor_force(
                                Ok(String::from("1")),
                                Ok(String::from("1")),
                            )
                        );
                        assert_eq!(
                            Some(false),
                            ShouldColorize::resolve_clicolor_force(
                                Ok(String::from("1")),
                                Ok(String::from("0")),
                            )
                        );
                        assert_eq!(
                            Some(false),
                            ShouldColorize::resolve_clicolor_force(
                                Err(env::VarError::NotPresent),
                                Ok(String::from("0")),
                            )
                        );
                        assert_eq!(
                            Some(true),
                            ShouldColorize::resolve_clicolor_force(
                                Err(env::VarError::NotPresent),
                                Ok(String::from("1")),
                            )
                        );
                    },
                );
            });

            ctx.describe("constructors", |ctx| {
                ctx.it("should have a default constructor", || {
                    ShouldColorize::default();
                });

                ctx.it("should have an environment constructor", || {
                    ShouldColorize::from_env();
                });
            });

            ctx.describe("when only changing clicolors", |ctx| {
                ctx.it("clicolor == false means no colors", || {
                    let colorize_control = ShouldColorize {
                        clicolor: Some(false),
                        ..ShouldColorize::default()
                    };
                    false == colorize_control.should_colorize()
                });

                ctx.it("clicolor == true means colors !", || {
                    let colorize_control = ShouldColorize {
                        clicolor: Some(true),
                        ..ShouldColorize::default()
                    };
                    true == colorize_control.should_colorize()
                });

                ctx.it("unset clicolors implies true", || {
                    true == ShouldColorize::default().should_colorize()
                });
            });

            ctx.describe("when using clicolor_force", |ctx| {
                ctx.it(
                    "clicolor_force should force to true no matter clicolor",
                    || {
                        let colorize_control = ShouldColorize {
                            clicolor: Some(false),
                            clicolor_force: Some(true),
                            ..ShouldColorize::default()
                        };

                        true == colorize_control.should_colorize()
                    },
                );

                ctx.it(
                    "clicolor_force should force to false no matter clicolor",
                    || {
                        let colorize_control = ShouldColorize {
                            clicolor: Some(true),
                            clicolor_force: Some(false),
                            ..ShouldColorize::default()
                        };

                        false == colorize_control.should_colorize()
                    },
                );
            });

            ctx.describe("using a manual override", |ctx| {
                ctx.it("shoud colorize if manual_override is true, but clicolor is false and clicolor_force also false", || {
                    let colorize_control = ShouldColorize {
                        clicolor: Some(false),
                        clicolor_force: None,
                        has_manual_override: AtomicBool::new(true),
                        manual_override: AtomicBool::new(true),
                        .. ShouldColorize::default()
                    };

                    true == colorize_control.should_colorize()
                });

                ctx.it("should not colorize if manual_override is false, but clicolor is true or clicolor_force is true", || {
                    let colorize_control = ShouldColorize {
                        clicolor: Some(true),
                        clicolor_force: Some(true),
                        has_manual_override: AtomicBool::new(true),
                        manual_override: AtomicBool::new(false),
                        .. ShouldColorize::default()
                    };

                    false == colorize_control.should_colorize()
                })
            });

            ctx.describe("::set_override", |ctx| {
                ctx.it("should exists", || {
                    let colorize_control = ShouldColorize::default();
                    colorize_control.set_override(true);
                });

                ctx.it("set the manual_override property", || {
                    let colorize_control = ShouldColorize::default();
                    colorize_control.set_override(true);
                    {
                        assert_eq!(
                            true,
                            colorize_control.has_manual_override.load(Ordering::Relaxed)
                        );
                        let val = colorize_control.manual_override.load(Ordering::Relaxed);
                        assert_eq!(true, val);
                    }
                    colorize_control.set_override(false);
                    {
                        assert_eq!(
                            true,
                            colorize_control.has_manual_override.load(Ordering::Relaxed)
                        );
                        let val = colorize_control.manual_override.load(Ordering::Relaxed);
                        assert_eq!(false, val);
                    }
                });
            });

            ctx.describe("::unset_override", |ctx| {
                ctx.it("should exists", || {
                    let colorize_control = ShouldColorize::default();
                    colorize_control.unset_override();
                });

                ctx.it("unset the manual_override property", || {
                    let colorize_control = ShouldColorize::default();
                    colorize_control.set_override(true);
                    colorize_control.unset_override();
                    assert_eq!(
                        false,
                        colorize_control.has_manual_override.load(Ordering::Relaxed)
                    );
                });
            });
        });
        runner.add_event_handler(&mut formatter);
        runner.run().unwrap();
    }
}
<commit_msg>set_virtual_terminal to return dummy Result to ensure backwards compatibility<commit_after>//! A couple of functions to enable and disable coloring.

use std::default::Default;
use std::env;
use std::sync::atomic::{AtomicBool, Ordering};

/// Sets a flag to the console to use a virtual terminal environment.
///
/// This is primarily used for Windows 10 environments which will not correctly colorize
/// the outputs based on ANSI escape codes.
///
/// The returned `Result` is _always_ `Ok(())`, the return type was kept to ensure backwards
/// compatibility.
///
/// # Notes
/// > Only available to `Windows` build targets.
///
/// # Example
/// ```rust
/// use colored::*;
/// control::set_virtual_terminal(false).unwrap();
/// println!("{}", "bright cyan".bright_cyan());	// will print 'bright cyan' on windows 10
///
/// control::set_virtual_terminal(true).unwrap();
/// println!("{}", "bright cyan".bright_cyan());	// will print correctly
/// ```
#[cfg(windows)]
pub fn set_virtual_terminal(use_virtual: bool) -> Result<(), ()> {
    use winapi::{
        shared::minwindef::DWORD,
        um::{
            consoleapi::{GetConsoleMode, SetConsoleMode},
            processenv::GetStdHandle,
            winbase::STD_OUTPUT_HANDLE,
            wincon::ENABLE_VIRTUAL_TERMINAL_PROCESSING,
        }
    };

    unsafe {
        let handle = GetStdHandle(STD_OUTPUT_HANDLE);
        let mut original_mode: DWORD = 0;
        GetConsoleMode(handle, &mut original_mode);

        let enabled = original_mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING == ENABLE_VIRTUAL_TERMINAL_PROCESSING;

        match (use_virtual, enabled) {
            // not enabled, should be enabled
            (true, false) => SetConsoleMode(handle, ENABLE_VIRTUAL_TERMINAL_PROCESSING | original_mode),
            // already enabled, should be disabled
            (false, true) => SetConsoleMode(handle, ENABLE_VIRTUAL_TERMINAL_PROCESSING ^ original_mode),
            _ => 0,
        };
    }

    Ok(())
}

pub struct ShouldColorize {
    clicolor: Option<bool>,
    clicolor_force: Option<bool>,
    // XXX we can't use Option<Atomic> because we can't use &mut references to ShouldColorize
    has_manual_override: AtomicBool,
    manual_override: AtomicBool,
}

/// Use this to force colored to ignore the environment and always/never colorize
/// See example/control.rs
pub fn set_override(override_colorize: bool) {
    SHOULD_COLORIZE.set_override(override_colorize)
}

/// Remove the manual override and let the environment decide if it's ok to colorize
/// See example/control.rs
pub fn unset_override() {
    SHOULD_COLORIZE.unset_override()
}

lazy_static! {
    pub static ref SHOULD_COLORIZE: ShouldColorize = ShouldColorize::from_env();
}

impl Default for ShouldColorize {
    fn default() -> ShouldColorize {
        ShouldColorize {
            clicolor: None,
            clicolor_force: None,
            has_manual_override: AtomicBool::new(false),
            manual_override: AtomicBool::new(false),
        }
    }
}

impl ShouldColorize {
    /// Reads environment variables to determine whether colorization should
    /// be used or not. `CLICOLOR_FORCE` takes highest priority, followed by
    /// `NO_COLOR`, followed by `CLICOLOR`. In the absence of manual overrides,
    /// which take precedence over all environment variables, the priority
    /// of these variables can be expressed as follows.
    ///
    /// `NO_COLOR`  | `CLICOLOR`          | `CLICOLOR_FORCE`   | colorize?
    /// :---------  | :---------          | :---------------   | :--------
    /// unset       | unset               | unset              | true (default)
    /// unset       | `!= 0`              | unset              | true
    /// unset       | `== 0`              | unset              | false
    /// set         | unset/`== 0`/`!= 0` | unset              | false
    /// set/unset   | unset/`== 0`/`!= 0` | `== 0`             | false
    /// set/unset   | unset/`== 0`/`!= 0` | `!= 0`             | true
    pub fn from_env() -> Self {
        use std::io;

        ShouldColorize {
            clicolor: ShouldColorize::normalize_env(env::var("CLICOLOR")),
            clicolor_force: ShouldColorize::resolve_clicolor_force(
                env::var("NO_COLOR"),
                env::var("CLICOLOR_FORCE"),
            ),
            ..ShouldColorize::default()
        }
    }

    pub fn should_colorize(&self) -> bool {
        if self.has_manual_override.load(Ordering::Relaxed) {
            return self.manual_override.load(Ordering::Relaxed);
        }

        if let Some(forced_value) = self.clicolor_force {
            return forced_value;
        }

        if let Some(value) = self.clicolor {
            return value;
        }

        true
    }

    pub fn set_override(&self, override_colorize: bool) {
        self.has_manual_override.store(true, Ordering::Relaxed);
        self.manual_override
            .store(override_colorize, Ordering::Relaxed);
    }

    pub fn unset_override(&self) {
        self.has_manual_override.store(false, Ordering::Relaxed);
    }

    /* private */

    fn normalize_env(env_res: Result<String, env::VarError>) -> Option<bool> {
        match env_res {
            Ok(string) => Some(string != "0"),
            Err(_) => None,
        }
    }

    fn resolve_clicolor_force(
        no_color: Result<String, env::VarError>,
        clicolor_force: Result<String, env::VarError>,
    ) -> Option<bool> {
        match (
            ShouldColorize::normalize_env(no_color),
            ShouldColorize::normalize_env(clicolor_force),
        ) {
            (_, Some(b)) => Some(b),
            (Some(_), None) => Some(false),
            (None, None) => None,
        }
    }
}

#[cfg(test)]
mod specs {
    use super::*;
    use rspec;
    use rspec::context::*;
    use std::env;

    #[test]
    fn clicolor_behavior() {
        use std::io;

        let stdout = &mut io::stdout();
        let mut formatter = rspec::formatter::Simple::new(stdout);
        let mut runner = describe("ShouldColorize", |ctx| {
            ctx.describe("::normalize_env", |ctx| {
                ctx.it("should return None if error", || {
                    assert_eq!(
                        None,
                        ShouldColorize::normalize_env(Err(env::VarError::NotPresent))
                    );
                    assert_eq!(
                        None,
                        ShouldColorize::normalize_env(Err(env::VarError::NotUnicode("".into())))
                    )
                });

                ctx.it("should return Some(true) if != 0", || {
                    Some(true) == ShouldColorize::normalize_env(Ok(String::from("1")))
                });

                ctx.it("should return Some(false) if == 0", || {
                    Some(false) == ShouldColorize::normalize_env(Ok(String::from("0")))
                });
            });

            ctx.describe("::resolve_clicolor_force", |ctx| {
                ctx.it(
                    "should return None if neither NO_COLOR nor CLICOLOR_FORCE are set",
                    || {
                        assert_eq!(
                            None,
                            ShouldColorize::resolve_clicolor_force(
                                Err(env::VarError::NotPresent),
                                Err(env::VarError::NotPresent)
                            )
                        );
                    },
                );

                ctx.it(
                    "should return Some(false) if NO_COLOR is set and CLICOLOR_FORCE is unset",
                    || {
                        assert_eq!(
                            Some(false),
                            ShouldColorize::resolve_clicolor_force(
                                Ok(String::from("0")),
                                Err(env::VarError::NotPresent)
                            )
                        );
                        assert_eq!(
                            Some(false),
                            ShouldColorize::resolve_clicolor_force(
                                Ok(String::from("1")),
                                Err(env::VarError::NotPresent)
                            )
                        );
                    },
                );

                ctx.it(
                    "should ignore NO_COLOR and return Some(forced_value) if CLICOLOR_FORCE is set to forced_value",
                    || {
                        assert_eq!(
                            Some(true),
                            ShouldColorize::resolve_clicolor_force(
                                Ok(String::from("1")),
                                Ok(String::from("1")),
                            )
                        );
                        assert_eq!(
                            Some(false),
                            ShouldColorize::resolve_clicolor_force(
                                Ok(String::from("1")),
                                Ok(String::from("0")),
                            )
                        );
                        assert_eq!(
                            Some(false),
                            ShouldColorize::resolve_clicolor_force(
                                Err(env::VarError::NotPresent),
                                Ok(String::from("0")),
                            )
                        );
                        assert_eq!(
                            Some(true),
                            ShouldColorize::resolve_clicolor_force(
                                Err(env::VarError::NotPresent),
                                Ok(String::from("1")),
                            )
                        );
                    },
                );
            });

            ctx.describe("constructors", |ctx| {
                ctx.it("should have a default constructor", || {
                    ShouldColorize::default();
                });

                ctx.it("should have an environment constructor", || {
                    ShouldColorize::from_env();
                });
            });

            ctx.describe("when only changing clicolors", |ctx| {
                ctx.it("clicolor == false means no colors", || {
                    let colorize_control = ShouldColorize {
                        clicolor: Some(false),
                        ..ShouldColorize::default()
                    };
                    false == colorize_control.should_colorize()
                });

                ctx.it("clicolor == true means colors !", || {
                    let colorize_control = ShouldColorize {
                        clicolor: Some(true),
                        ..ShouldColorize::default()
                    };
                    true == colorize_control.should_colorize()
                });

                ctx.it("unset clicolors implies true", || {
                    true == ShouldColorize::default().should_colorize()
                });
            });

            ctx.describe("when using clicolor_force", |ctx| {
                ctx.it(
                    "clicolor_force should force to true no matter clicolor",
                    || {
                        let colorize_control = ShouldColorize {
                            clicolor: Some(false),
                            clicolor_force: Some(true),
                            ..ShouldColorize::default()
                        };

                        true == colorize_control.should_colorize()
                    },
                );

                ctx.it(
                    "clicolor_force should force to false no matter clicolor",
                    || {
                        let colorize_control = ShouldColorize {
                            clicolor: Some(true),
                            clicolor_force: Some(false),
                            ..ShouldColorize::default()
                        };

                        false == colorize_control.should_colorize()
                    },
                );
            });

            ctx.describe("using a manual override", |ctx| {
                ctx.it("shoud colorize if manual_override is true, but clicolor is false and clicolor_force also false", || {
                    let colorize_control = ShouldColorize {
                        clicolor: Some(false),
                        clicolor_force: None,
                        has_manual_override: AtomicBool::new(true),
                        manual_override: AtomicBool::new(true),
                        .. ShouldColorize::default()
                    };

                    true == colorize_control.should_colorize()
                });

                ctx.it("should not colorize if manual_override is false, but clicolor is true or clicolor_force is true", || {
                    let colorize_control = ShouldColorize {
                        clicolor: Some(true),
                        clicolor_force: Some(true),
                        has_manual_override: AtomicBool::new(true),
                        manual_override: AtomicBool::new(false),
                        .. ShouldColorize::default()
                    };

                    false == colorize_control.should_colorize()
                })
            });

            ctx.describe("::set_override", |ctx| {
                ctx.it("should exists", || {
                    let colorize_control = ShouldColorize::default();
                    colorize_control.set_override(true);
                });

                ctx.it("set the manual_override property", || {
                    let colorize_control = ShouldColorize::default();
                    colorize_control.set_override(true);
                    {
                        assert_eq!(
                            true,
                            colorize_control.has_manual_override.load(Ordering::Relaxed)
                        );
                        let val = colorize_control.manual_override.load(Ordering::Relaxed);
                        assert_eq!(true, val);
                    }
                    colorize_control.set_override(false);
                    {
                        assert_eq!(
                            true,
                            colorize_control.has_manual_override.load(Ordering::Relaxed)
                        );
                        let val = colorize_control.manual_override.load(Ordering::Relaxed);
                        assert_eq!(false, val);
                    }
                });
            });

            ctx.describe("::unset_override", |ctx| {
                ctx.it("should exists", || {
                    let colorize_control = ShouldColorize::default();
                    colorize_control.unset_override();
                });

                ctx.it("unset the manual_override property", || {
                    let colorize_control = ShouldColorize::default();
                    colorize_control.set_override(true);
                    colorize_control.unset_override();
                    assert_eq!(
                        false,
                        colorize_control.has_manual_override.load(Ordering::Relaxed)
                    );
                });
            });
        });
        runner.add_event_handler(&mut formatter);
        runner.run().unwrap();
    }
}
<|endoftext|>


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

//! This file defines system store APIs that operates data not part of the Libra core data
//! structures but information with regard to system running status, statistics, etc.

use crate::{
    ledger_counters::{LedgerCounterBumps, LedgerCounters},
    schema::ledger_counters::LedgerCountersSchema,
};
use anyhow::Result;
use libra_logger::prelude::*;
use libra_types::transaction::Version;
use schemadb::{SchemaBatch, DB};
use std::sync::Arc;

#[derive(Debug)]
pub(crate) struct SystemStore {
    db: Arc<DB>,
}

impl SystemStore {
    pub fn new(db: Arc<DB>) -> Self {
        Self { db }
    }

    /// Increase ledger counters.
    ///
    /// The base values are read out of db, to which the `diff` is combined to, and the result is
    /// stored to the db, keyed by `last_version`.
    pub fn bump_ledger_counters(
        &self,
        first_version: Version,
        last_version: Version,
        bumps: LedgerCounterBumps,
        batch: &mut SchemaBatch,
    ) -> Result<LedgerCounters> {
        assert!(first_version <= last_version);

        let mut counters = if first_version > 0 {
            let base_version = first_version - 1;
            if let Some(counters) = self.db.get::<LedgerCountersSchema>(&base_version)? {
                counters
            } else {
                error!(
                    "Base version ({}) ledger counters not found. Assuming zeros.",
                    base_version
                );
                LedgerCounters::new()
            }
        } else {
            LedgerCounters::new()
        };

        counters.bump(bumps);
        batch.put::<LedgerCountersSchema>(&last_version, &counters)?;

        Ok(counters)
    }
}

#[cfg(test)]
mod test;
<commit_msg>trivial: downgrade "system counter missing" error log to warning<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

//! This file defines system store APIs that operates data not part of the Libra core data
//! structures but information with regard to system running status, statistics, etc.

use crate::{
    ledger_counters::{LedgerCounterBumps, LedgerCounters},
    schema::ledger_counters::LedgerCountersSchema,
};
use anyhow::Result;
use libra_logger::prelude::*;
use libra_types::transaction::Version;
use schemadb::{SchemaBatch, DB};
use std::sync::Arc;

#[derive(Debug)]
pub(crate) struct SystemStore {
    db: Arc<DB>,
}

impl SystemStore {
    pub fn new(db: Arc<DB>) -> Self {
        Self { db }
    }

    /// Increase ledger counters.
    ///
    /// The base values are read out of db, to which the `diff` is combined to, and the result is
    /// stored to the db, keyed by `last_version`.
    pub fn bump_ledger_counters(
        &self,
        first_version: Version,
        last_version: Version,
        bumps: LedgerCounterBumps,
        batch: &mut SchemaBatch,
    ) -> Result<LedgerCounters> {
        assert!(first_version <= last_version);

        let mut counters = if first_version > 0 {
            let base_version = first_version - 1;
            if let Some(counters) = self.db.get::<LedgerCountersSchema>(&base_version)? {
                counters
            } else {
                warn!(
                    "Base version ({}) ledger counters not found. Assuming zeros.",
                    base_version
                );
                LedgerCounters::new()
            }
        } else {
            LedgerCounters::new()
        };

        counters.bump(bumps);
        batch.put::<LedgerCountersSchema>(&last_version, &counters)?;

        Ok(counters)
    }
}

#[cfg(test)]
mod test;
<|endoftext|>


<commit_before>// This module defines constants and functions for working with zakocmp
// configuration files.

extern crate yaml_rust;

use std::io::{Error, ErrorKind};
use std::result::Result;
use std::vec::Vec;
use yaml_rust::{Yaml, YamlLoader};

const DEFAULT_POLICY_KEY: &'static str = "default-policy";
const POLICIES_KEY: &'static str = "policies";

// Enumerates the string representations of known policies.
const POLICY_REPR_IGNORE: &'static str = "ignore";
const POLICY_REPR_NOADD: &'static str = "noadd";
const POLICY_REPR_NODELETE: &'static str = "nodelete";
const POLICY_REPR_NOMODIFY: &'static str = "nomodify";
const POLICY_REPR_IMMUTABLE: &'static str = "immutable";

// Represents known policies as integers.
pub const POLICY_IGNORE: i32 = 0;
pub const POLICY_NOADD: i32 = 1 << 0;
pub const POLICY_NODELETE: i32 = 1 << 1;
pub const POLICY_NOMODIFY: i32 = 1 << 2;
pub const POLICY_IMMUTABLE: i32 = POLICY_NOADD | POLICY_NODELETE | POLICY_NOMODIFY;

// Represents a sorted vector of zakopane config rules, each mapping a
// path (prefix) to a policy. This type alias is provided for ease of
// coding.
type ZakopanePolicies = Vec<(String, i32)>;

// Represents a zakopane config. Please consult the documentation.
pub struct ZakopaneConfig {
    default_policy: i32,
    policies: ZakopanePolicies,
}

// Borrows the string representation of one policy `token` and returns
// the equivalent integral representation.
fn policy_token_as_int(token: &str) -> Result<i32, Error> {
    match token {
        POLICY_REPR_IGNORE => Ok(POLICY_IGNORE),
        POLICY_REPR_NOADD => Ok(POLICY_NOADD),
        POLICY_REPR_NODELETE => Ok(POLICY_NODELETE),
        POLICY_REPR_NOMODIFY => Ok(POLICY_NOMODIFY),
        POLICY_REPR_IMMUTABLE => Ok(POLICY_IMMUTABLE),
        _ => Err(Error::new(
            ErrorKind::InvalidInput,
            format!("bad token: ``{}''", token),
        )),
    }
}

/// Borrows the string representation of a combined `policy` and returns
/// the equivalent integral representation. This function expects
/// `policy` to comprise one or more policy tokens separated by commas.
///
/// # Examples
///
/// ```
/// # mod zakocmp;
/// let policy: i32 = config::policy_repr_as_int(&"immutable").unwrap();
/// assert!(policy == config::POLICY_IMMUTABLE);
/// ```
///
/// ```
/// # mod zakocmp;
/// // Multiple policies are bitwise OR'd together.
/// let policy: i32 = config::policy_repr_as_int(
///     &"noadd,nomodify").unwrap();
/// assert!(policy == config::POLICY_NOADD | config::POLICY_NOMODIFY);
/// ```
///
/// ```
/// # mod zakocmp;
/// // The biggest bitwise OR equals POLICY_IMMUTABLE.
/// let policy: i32 = config::policy_repr_as_int(
///     &"noadd,nodelete,nomodify").unwrap();
/// assert!(policy == config::POLICY_IMMUTABLE);
/// ```
///
/// # Failures
///
/// ```
/// # mod zakocmp;
/// // Obi-wan was witty, but not good at dictating zakocmp policy.
/// assert!(!config::policy_repr_as_int(&"hello there!").is_ok());
/// ```
///
pub fn policy_repr_as_int(policy: &str) -> Result<i32, Error> {
    let policy_ints: Vec<i32> = policy
        .split(",")
        .map(|tok| policy_token_as_int(tok))
        .collect::<Result<Vec<i32>, Error>>()?;
    return Ok(policy_ints
        .iter()
        .fold(POLICY_IGNORE, |accum, elem| accum | elem));
}

// Borrows yaml representations of one line of zakopane policy and
// returns the corresponding valid tuple suitable for use in building a
// ZakopanePolicies object.
fn extract_policy(ypath: &Yaml, policy_repr: &Yaml) -> Result<(String, i32), Error> {
    let path: String = match ypath.as_str() {
        Some(string) => string.to_owned(),
        None => return Err(Error::new(ErrorKind::InvalidData, "malformed path?")),
    };
    let policy: i32 = match policy_repr.as_str() {
        Some(string) => policy_repr_as_int(string)?,
        None => return Err(Error::new(ErrorKind::InvalidData, "malformed policy?")),
    };
    Ok((path, policy))
}

// Borrows the YAML representation of a zakopane config and returns the
// corresponding ZakopanePolicies. The return value can be benignly
// empty (e.g. if the present config elects not to specify any rules).
fn policies_from_yaml(doc: &Yaml) -> Result<ZakopanePolicies, Error> {
    let policies_map_yaml = &doc[POLICIES_KEY];
    if policies_map_yaml.is_badvalue() {
        // Assumes the config may be benignly devoid of specific
        // policies, returning Ok.
        return Ok(vec![]);
    }
    // Otherwise, iterates over the policies map. Each entry in the
    // policies map correlates a path prefix to a comma-separated list
    // of policies.
    let policies_map: &yaml_rust::yaml::Hash = match policies_map_yaml.as_hash() {
        Some(map) => map,
        None => return Err(Error::new(ErrorKind::InvalidData, "malformed policies")),
    };
    let mut policies: ZakopanePolicies = policies_map
        .into_iter()
        .map(|pair| extract_policy(&pair.0, &pair.1))
        .collect::<Result<ZakopanePolicies, Error>>()?;
    policies.sort_unstable_by_key(|pair| pair.0.to_owned());
    Ok(policies)
}

impl ZakopaneConfig {
    // Borrows the string representation of a zakopane config and
    // returns a corresponding ZakopaneConfig.
    pub fn new(config: &str) -> Result<ZakopaneConfig, Error> {
        let docs: Vec<Yaml> = match YamlLoader::load_from_str(config) {
            Ok(val) => val,
            Err(scan_error) => return Err(Error::new(ErrorKind::InvalidData, scan_error)),
        };
        if docs.len() == 0 {
            return Err(Error::new(ErrorKind::InvalidData, "empty zakopane config"));
        }
        let doc = &docs[0];

        let default_policy_yaml = &doc[DEFAULT_POLICY_KEY];
        if default_policy_yaml.is_badvalue() {
            return Err(Error::new(ErrorKind::InvalidData, DEFAULT_POLICY_KEY));
        }
        let default_policy: i32 = match default_policy_yaml.as_str() {
            None => return Err(Error::new(ErrorKind::InvalidData, DEFAULT_POLICY_KEY)),
            Some(token) => policy_repr_as_int(&token),
        }?;

        let policies: ZakopanePolicies = policies_from_yaml(&doc)?;

        Ok(ZakopaneConfig {
            default_policy: default_policy,
            policies: policies,
        })
    }

    // Returns how many rules this config contains.
    // This is never less than 1 as a default-policy is always required.
    pub fn rules(&self) -> usize {
        1 + self.policies.len()
    }

    // Returns the default policy.
    pub fn default_policy(&self) -> i32 {
        self.default_policy
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_policy_bare_noadd() {
        let policy: i32 = match policy_repr_as_int(&"noadd") {
            Ok(value) => value,
            Err(oof) => panic!(oof),
        };
        assert!(policy == POLICY_NOADD);
    }

    #[test]
    fn test_policy_bare_nodelete() {
        let policy: i32 = match policy_repr_as_int(&"nodelete") {
            Ok(value) => value,
            Err(oof) => panic!(oof),
        };
        assert!(policy == POLICY_NODELETE);
    }

    #[test]
    fn test_policy_bare_nomodify() {
        let policy: i32 = match policy_repr_as_int(&"nomodify") {
            Ok(value) => value,
            Err(oof) => panic!(oof),
        };
        assert!(policy == POLICY_NOMODIFY);
    }

    #[test]
    fn test_policy_combo() {
        let policy: i32 = match policy_repr_as_int(&"noadd,nodelete") {
            Ok(value) => value,
            Err(oof) => panic!(oof),
        };
        assert!(policy == POLICY_NOADD | POLICY_NODELETE);
    }

    #[test]
    fn test_policy_repetition() {
        let policy: i32 =
            match policy_repr_as_int(&"noadd,noadd,noadd,noadd,nodelete,nodelete,nodelete,noadd") {
                Ok(value) => value,
                Err(oof) => panic!(oof),
            };
        assert!(policy == POLICY_NOADD | POLICY_NODELETE);
    }

    #[test]
    fn disallow_empty_config() {
        let config = "";
        assert!(!ZakopaneConfig::new(&config).is_ok());
    }

    #[test]
    fn disallow_obviously_malformed_config() {
        let config = r#"
This is not a zakopane config -
rather, it's two lines of text.
        "#;
        assert!(!ZakopaneConfig::new(&config).is_ok());
    }

    #[test]
    fn config_requires_default_policy() {
        let config = r#"
policies:
    hello-there: nomodify
        "#;
        assert!(!ZakopaneConfig::new(&config).is_ok());

        let mut config_with_default_policy: String = r#"
default-policy: immutable
        "#.to_string();
        config_with_default_policy.push_str(&config);
        assert!(ZakopaneConfig::new(&config_with_default_policy).is_ok())
    }

    #[test]
    fn config_with_no_specific_policies() {
        let config = r#"
default-policy: nodelete
one-irrelevant-key: it doesn't matter what we put here
another-irrelevant-key: this doesn't invalidate the YAML
third-irrelevant-key: so long as it contains a default-policy
        "#;
        assert!(ZakopaneConfig::new(&config).is_ok());
    }

    #[test]
    fn config_with_several_policies() {
        let config = r#"
default-policy: immutable
policies:
    hello-there: noadd
    general-kenobi: nodelete
        "#;
        assert!(ZakopaneConfig::new(&config).is_ok());
    }
}
<commit_msg>zakocmp: rename and clean up unit tests<commit_after>// This module defines constants and functions for working with zakocmp
// configuration files.

extern crate yaml_rust;

use std::io::{Error, ErrorKind};
use std::result::Result;
use std::vec::Vec;
use yaml_rust::{Yaml, YamlLoader};

const DEFAULT_POLICY_KEY: &'static str = "default-policy";
const POLICIES_KEY: &'static str = "policies";

// Enumerates the string representations of known policies.
const POLICY_REPR_IGNORE: &'static str = "ignore";
const POLICY_REPR_NOADD: &'static str = "noadd";
const POLICY_REPR_NODELETE: &'static str = "nodelete";
const POLICY_REPR_NOMODIFY: &'static str = "nomodify";
const POLICY_REPR_IMMUTABLE: &'static str = "immutable";

// Represents known policies as integers.
pub const POLICY_IGNORE: i32 = 0;
pub const POLICY_NOADD: i32 = 1 << 0;
pub const POLICY_NODELETE: i32 = 1 << 1;
pub const POLICY_NOMODIFY: i32 = 1 << 2;
pub const POLICY_IMMUTABLE: i32 = POLICY_NOADD | POLICY_NODELETE | POLICY_NOMODIFY;

// Represents a sorted vector of zakopane config rules, each mapping a
// path (prefix) to a policy. This type alias is provided for ease of
// coding.
type ZakopanePolicies = Vec<(String, i32)>;

// Represents a zakopane config. Please consult the documentation.
pub struct ZakopaneConfig {
    default_policy: i32,
    policies: ZakopanePolicies,
}

// Borrows the string representation of one policy `token` and returns
// the equivalent integral representation.
fn policy_token_as_int(token: &str) -> Result<i32, Error> {
    match token {
        POLICY_REPR_IGNORE => Ok(POLICY_IGNORE),
        POLICY_REPR_NOADD => Ok(POLICY_NOADD),
        POLICY_REPR_NODELETE => Ok(POLICY_NODELETE),
        POLICY_REPR_NOMODIFY => Ok(POLICY_NOMODIFY),
        POLICY_REPR_IMMUTABLE => Ok(POLICY_IMMUTABLE),
        _ => Err(Error::new(
            ErrorKind::InvalidInput,
            format!("bad token: ``{}''", token),
        )),
    }
}

// Borrows the string representation of a combined `policy` and returns
// the equivalent integral representation. This function expects
// `policy` to comprise one or more policy tokens separated by commas.
fn policy_repr_as_int(policy: &str) -> Result<i32, Error> {
    let policy_ints: Vec<i32> = policy
        .split(",")
        .map(|tok| policy_token_as_int(tok))
        .collect::<Result<Vec<i32>, Error>>()?;
    return Ok(policy_ints
        .iter()
        .fold(POLICY_IGNORE, |accum, elem| accum | elem));
}

// Borrows yaml representations of one line of zakopane policy and
// returns the corresponding valid tuple suitable for use in building a
// ZakopanePolicies object.
fn extract_policy(ypath: &Yaml, policy_repr: &Yaml) -> Result<(String, i32), Error> {
    let path: String = match ypath.as_str() {
        Some(string) => string.to_owned(),
        None => return Err(Error::new(ErrorKind::InvalidData, "malformed path?")),
    };
    let policy: i32 = match policy_repr.as_str() {
        Some(string) => policy_repr_as_int(string)?,
        None => return Err(Error::new(ErrorKind::InvalidData, "malformed policy?")),
    };
    Ok((path, policy))
}

// Borrows the YAML representation of a zakopane config and returns the
// corresponding ZakopanePolicies. The return value can be benignly
// empty (e.g. if the present config elects not to specify any rules).
fn policies_from_yaml(doc: &Yaml) -> Result<ZakopanePolicies, Error> {
    let policies_map_yaml = &doc[POLICIES_KEY];
    if policies_map_yaml.is_badvalue() {
        // Assumes the config may be benignly devoid of specific
        // policies, returning Ok.
        return Ok(vec![]);
    }
    // Otherwise, iterates over the policies map. Each entry in the
    // policies map correlates a path prefix to a comma-separated list
    // of policies.
    let policies_map: &yaml_rust::yaml::Hash = match policies_map_yaml.as_hash() {
        Some(map) => map,
        None => return Err(Error::new(ErrorKind::InvalidData, "malformed policies")),
    };
    let mut policies: ZakopanePolicies = policies_map
        .into_iter()
        .map(|pair| extract_policy(&pair.0, &pair.1))
        .collect::<Result<ZakopanePolicies, Error>>()?;
    policies.sort_unstable_by_key(|pair| pair.0.to_owned());
    Ok(policies)
}

impl ZakopaneConfig {
    // Borrows the string representation of a zakopane config and
    // returns a corresponding ZakopaneConfig.
    pub fn new(config: &str) -> Result<ZakopaneConfig, Error> {
        let docs: Vec<Yaml> = match YamlLoader::load_from_str(config) {
            Ok(val) => val,
            Err(scan_error) => return Err(Error::new(ErrorKind::InvalidData, scan_error)),
        };
        if docs.len() == 0 {
            return Err(Error::new(ErrorKind::InvalidData, "empty zakopane config"));
        }
        let doc = &docs[0];

        let default_policy_yaml = &doc[DEFAULT_POLICY_KEY];
        if default_policy_yaml.is_badvalue() {
            return Err(Error::new(ErrorKind::InvalidData, DEFAULT_POLICY_KEY));
        }
        let default_policy: i32 = match default_policy_yaml.as_str() {
            None => return Err(Error::new(ErrorKind::InvalidData, DEFAULT_POLICY_KEY)),
            Some(token) => policy_repr_as_int(&token),
        }?;

        let policies: ZakopanePolicies = policies_from_yaml(&doc)?;

        Ok(ZakopaneConfig {
            default_policy: default_policy,
            policies: policies,
        })
    }

    // Returns how many rules this config contains.
    // This is never less than 1 as a default-policy is always required.
    pub fn rules(&self) -> usize {
        1 + self.policies.len()
    }

    // Returns the default policy.
    pub fn default_policy(&self) -> i32 {
        self.default_policy
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn policy_token_bare_noadd() {
        let policy: i32 = match policy_repr_as_int(&"noadd") {
            Ok(value) => value,
            Err(oof) => panic!(oof),
        };
        assert!(policy == POLICY_NOADD);
    }

    #[test]
    fn policy_token_bare_nodelete() {
        let policy: i32 = match policy_repr_as_int(&"nodelete") {
            Ok(value) => value,
            Err(oof) => panic!(oof),
        };
        assert!(policy == POLICY_NODELETE);
    }

    #[test]
    fn policy_token_bare_nomodify() {
        let policy: i32 = match policy_repr_as_int(&"nomodify") {
            Ok(value) => value,
            Err(oof) => panic!(oof),
        };
        assert!(policy == POLICY_NOMODIFY);
    }

    #[test]
    fn policy_tokens_can_combo() {
        let policy: i32 = match policy_repr_as_int(&"noadd,nodelete") {
            Ok(value) => value,
            Err(oof) => panic!(oof),
        };
        assert!(policy == POLICY_NOADD | POLICY_NODELETE);
    }

    #[test]
    fn policy_tokens_can_repeat() {
        let policy: i32 =
            match policy_repr_as_int(&"noadd,noadd,noadd,noadd,nodelete,nodelete,nodelete,noadd") {
                Ok(value) => value,
                Err(oof) => panic!(oof),
            };
        assert!(policy == POLICY_NOADD | POLICY_NODELETE);
    }

    #[test]
    fn disallow_empty_config() {
        let config = "";
        assert!(!ZakopaneConfig::new(&config).is_ok());
    }

    #[test]
    fn disallow_obviously_malformed_config() {
        let config = r#"
This is not a zakopane config -
rather, it's two lines of text.
        "#;
        assert!(!ZakopaneConfig::new(&config).is_ok());
    }

    #[test]
    fn config_requires_default_policy() {
        let config = r#"
policies:
    hello-there: nomodify
        "#;
        assert!(!ZakopaneConfig::new(&config).is_ok());

        let mut config_with_default_policy: String = r#"
default-policy: immutable
        "#.to_string();
        config_with_default_policy.push_str(&config);
        assert!(ZakopaneConfig::new(&config_with_default_policy).is_ok())
    }

    #[test]
    fn config_with_no_specific_policies() {
        let config = r#"
default-policy: nodelete
one-irrelevant-key: it doesn't matter what we put here
another-irrelevant-key: this doesn't invalidate the YAML
third-irrelevant-key: so long as it contains a default-policy
        "#;
        assert!(ZakopaneConfig::new(&config).is_ok());
    }

    #[test]
    fn config_with_several_policies() {
        let config = r#"
default-policy: immutable
policies:
    hello-there: noadd
    general-kenobi: nodelete
        "#;
        assert!(ZakopaneConfig::new(&config).is_ok());
    }
}
<|endoftext|>