<commit_before>use runtime::Error;
use memory::Memory;
use values::{RcValue, Value};

pub static PRIMITIVES: [&'static str; 18] = [
    "*",
    "+",
    "-",
    "/",
    "<",
    "<=",
    "=",
    ">",
    ">=",
    "car",
    "cdr",
    "cons",
    "length",
    "list",
    "list?",
    "not",
    "null?",
    "pair?",
];

pub fn apply(name: &String, args: Vec<RcValue>, mem: &mut Memory) -> Result<RcValue, Error> {
    match name.as_slice() {
        "*"      => product(args, mem),
        "+"      => plus(args, mem),
        "-"      => minus(args, mem),
        "/"      => division(args, mem),
        "<"      => less_than(args, mem),
        "<="     => less_than_or_equal(args, mem),
        "="      => equals(args, mem),
        ">"      => greater_than(args, mem),
        ">="     => greater_than_or_equal(args, mem),
        "car"    => car(args),
        "cdr"    => cdr(args, mem),
        "cons"   => cons(args, mem),
        "length" => length(args, mem),
        "list"   => list(args, mem),
        "list?"  => list_question_mark(args, mem),
        "not"    => not(args, mem),
        "null?"  => null(args, mem),
        "pair?"  => pair(args, mem),
        _        => Err(Error::PrimitiveFailed(name.to_string()))
    }
}

fn plus(args: Vec<RcValue>, mem: &mut Memory) -> Result<RcValue, Error> {
    let integers = try!(list_of_integers(args));
    let sum = integers.into_iter().fold(0, |sum, n| sum + n);
    Ok(mem.integer(sum))
}

fn minus(args: Vec<RcValue>, mem: &mut Memory) -> Result<RcValue, Error> {
    if args.len() == 0 {
        return Err(Error::BadArity(Some("-".to_string())))
    }

    let integers = try!(list_of_integers(args));
    let first = integers[0];

    if integers.len() == 1 {
        Ok(mem.integer(-first))
    } else {
        let sum_of_the_rest = integers.into_iter().skip(1).fold(0, |sum, n| sum + n);
        Ok(mem.integer(first - sum_of_the_rest))
    }
}

fn division(args: Vec<RcValue>, mem: &mut Memory) -> Result<RcValue, Error> {
    if args.len() == 0 {
        return Err(Error::BadArity(Some("/".to_string())))
    }

    let integers = try!(list_of_integers(args));
    let first = integers[0];

    if integers.len() == 1 {
        Ok(mem.integer(1 / first))
    } else {
        let div = integers.into_iter().skip(1).fold(first, |div, n| div / n);
        Ok(mem.integer(div))
    }
}

fn product(args: Vec<RcValue>, mem: &mut Memory) -> Result<RcValue, Error> {
    let integers = try!(list_of_integers(args));
    let product = integers.into_iter().fold(1, |product, n| product * n);
    Ok(mem.integer(product))
}

fn equals(args: Vec<RcValue>, mem: &mut Memory) -> Result<RcValue, Error> {
    if args.len() < 2 {
        return Ok(mem.b_true());
    }

    let integers = try!(list_of_integers(args));
    let first = integers[0];

    let equality = integers.into_iter().skip(1).all(|n| n == first);
    Ok(mem.boolean(equality))
}

fn less_than(args: Vec<RcValue>, mem: &mut Memory) -> Result<RcValue, Error> {
    ord(args, mem, |a, b| a < b)
}

fn less_than_or_equal(args: Vec<RcValue>, mem: &mut Memory) -> Result<RcValue, Error> {
    ord(args, mem, |a, b| a <= b)
}

fn greater_than(args: Vec<RcValue>, mem: &mut Memory) -> Result<RcValue, Error> {
    ord(args, mem, |a, b| a > b)
}

fn greater_than_or_equal(args: Vec<RcValue>, mem: &mut Memory) -> Result<RcValue, Error> {
    ord(args, mem, |a, b| a >= b)
}

fn not(args: Vec<RcValue>, mem: &mut Memory) -> Result<RcValue, Error> {
    if args.len() != 1 {
        return Err(Error::BadArity(Some("not".to_string())))
    }

    Ok(mem.boolean(args[0] == mem.b_false()))
}

fn list(args: Vec<RcValue>, mem: &mut Memory) -> Result<RcValue, Error> {
    Ok(mem.list(args))
}

fn length(args: Vec<RcValue>, mem: &mut Memory) -> Result<RcValue, Error> {
    if args.len() != 1 {
        return Err(Error::BadArity(Some("length".to_string())));
    }

    match *args[0] {
        Value::List(ref list) =>
            Ok(mem.integer(list.len() as i64)),
        _ =>
            Err(Error::WrongArgumentType(args[0].clone())),
    }
}

fn pair(args: Vec<RcValue>, mem: &mut Memory) -> Result<RcValue, Error> {
    if args.len() != 1 {
        return Err(Error::BadArity(Some("pair?".to_string())));
    }

    let outcome = match *args[0] {
        Value::List(ref list) =>
            !list.is_empty(),
        Value::DottedList(ref _list, ref _el) =>
            true,
        _ =>
            false,
    };

    Ok(mem.boolean(outcome))
}

fn cons(args: Vec<RcValue>, mem: &mut Memory) -> Result<RcValue, Error> {
    if args.len() != 2 {
        return Err(Error::BadArity(Some("cons".to_string())));
    }

    let mut list: Vec<RcValue> = Vec::new();
    list.push(args[0].clone());

    if let Value::List(ref l) = *args[1] {
        for item in l.iter() {
            list.push(item.clone());
        }

        Ok(mem.list(list))
    } else {
        Ok(mem.dotted_list(list, args[1].clone()))
    }
}

fn car(args: Vec<RcValue>) -> Result<RcValue, Error> {
    if args.len() != 1 {
        return Err(Error::BadArity(Some("car".to_string())));
    }

    match *args[0] {
        Value::List(ref l) if !l.is_empty() =>
            Ok(l[0].clone()),
        Value::DottedList(ref l, ref _t) =>
            Ok(l[0].clone()),
        _ =>
            Err(Error::WrongArgumentType(args[0].clone())),
    }
}

fn cdr(args: Vec<RcValue>, mem: &mut Memory) -> Result<RcValue, Error> {
    if args.len() != 1 {
        return Err(Error::BadArity(Some("cdr".to_string())));
    }

    match *args[0] {
        Value::List(ref l) if !l.is_empty() =>
            match l.tail() {
                tail if tail.is_empty() =>
                    Ok(mem.empty_list()),
                tail => {
                    let list = tail.iter().map(|v| v.clone()).collect();
                    Ok(mem.list(list))
                }
            },
        Value::DottedList(ref _l, ref t) =>
            Ok(t.clone()),
        _ =>
            Err(Error::WrongArgumentType(args[0].clone())),
    }
}

fn null(args: Vec<RcValue>, mem: &mut Memory) -> Result<RcValue, Error> {
    if args.len() != 1 {
        return Err(Error::BadArity(Some("null?".to_string())));
    }

    Ok(mem.boolean(args[0] == mem.empty_list()))
}

fn list_question_mark(args: Vec<RcValue>, mem: &mut Memory) -> Result<RcValue, Error> {
    if args.len() != 1 {
        return Err(Error::BadArity(Some("list?".to_string())));
    }

    let outcome = if let Value::List(ref _l) = *args[0] {
        true
    } else {
        false
    };

    Ok(mem.boolean(outcome))
}

fn list_of_integers(list: Vec<RcValue>) -> Result<Vec<i64>, Error> {
    let mut integers = Vec::with_capacity(list.len());

    for val in list.into_iter() {
        match *val {
            Value::Integer(n) =>
                integers.push(n),
            _ =>
                return Err(Error::WrongArgumentType(val.clone())),
        }
    }

    Ok(integers)
}

fn ord(args: Vec<RcValue>, mem: &mut Memory, cmp: |i64, i64| -> bool) -> Result<RcValue, Error> {
    if args.len() < 2 {
        return Ok(mem.b_true())
    }

    let integers = try!(list_of_integers(args));
    let outcome = range(0u, integers.len() - 1).all(|i|
        cmp(integers[i], integers[i + 1])
    );

    return Ok(mem.boolean(outcome))
}
<commit_msg>Added primitive `display`.<commit_after>use runtime::Error;
use memory::Memory;
use values::{RcValue, Value};

pub static PRIMITIVES: [&'static str; 19] = [
    "*",
    "+",
    "-",
    "/",
    "<",
    "<=",
    "=",
    ">",
    ">=",
    "car",
    "cdr",
    "cons",
    "length",
    "list",
    "list?",
    "not",
    "null?",
    "pair?",
    "display",
];

pub fn apply(name: &String, args: Vec<RcValue>, mem: &mut Memory) -> Result<RcValue, Error> {
    match name.as_slice() {
        "*"      => product(args, mem),
        "+"      => plus(args, mem),
        "-"      => minus(args, mem),
        "/"      => division(args, mem),
        "<"      => less_than(args, mem),
        "<="     => less_than_or_equal(args, mem),
        "="      => equals(args, mem),
        ">"      => greater_than(args, mem),
        ">="     => greater_than_or_equal(args, mem),
        "car"    => car(args),
        "cdr"    => cdr(args, mem),
        "cons"   => cons(args, mem),
        "length" => length(args, mem),
        "list"   => list(args, mem),
        "list?"  => list_question_mark(args, mem),
        "not"    => not(args, mem),
        "null?"  => null(args, mem),
        "pair?"  => pair(args, mem),
        "display"  => display(args, mem),
        _        => Err(Error::PrimitiveFailed(name.to_string()))
    }
}

fn plus(args: Vec<RcValue>, mem: &mut Memory) -> Result<RcValue, Error> {
    let integers = try!(list_of_integers(args));
    let sum = integers.into_iter().fold(0, |sum, n| sum + n);
    Ok(mem.integer(sum))
}

fn minus(args: Vec<RcValue>, mem: &mut Memory) -> Result<RcValue, Error> {
    if args.len() == 0 {
        return Err(Error::BadArity(Some("-".to_string())))
    }

    let integers = try!(list_of_integers(args));
    let first = integers[0];

    if integers.len() == 1 {
        Ok(mem.integer(-first))
    } else {
        let sum_of_the_rest = integers.into_iter().skip(1).fold(0, |sum, n| sum + n);
        Ok(mem.integer(first - sum_of_the_rest))
    }
}

fn division(args: Vec<RcValue>, mem: &mut Memory) -> Result<RcValue, Error> {
    if args.len() == 0 {
        return Err(Error::BadArity(Some("/".to_string())))
    }

    let integers = try!(list_of_integers(args));
    let first = integers[0];

    if integers.len() == 1 {
        Ok(mem.integer(1 / first))
    } else {
        let div = integers.into_iter().skip(1).fold(first, |div, n| div / n);
        Ok(mem.integer(div))
    }
}

fn product(args: Vec<RcValue>, mem: &mut Memory) -> Result<RcValue, Error> {
    let integers = try!(list_of_integers(args));
    let product = integers.into_iter().fold(1, |product, n| product * n);
    Ok(mem.integer(product))
}

fn equals(args: Vec<RcValue>, mem: &mut Memory) -> Result<RcValue, Error> {
    if args.len() < 2 {
        return Ok(mem.b_true());
    }

    let integers = try!(list_of_integers(args));
    let first = integers[0];

    let equality = integers.into_iter().skip(1).all(|n| n == first);
    Ok(mem.boolean(equality))
}

fn less_than(args: Vec<RcValue>, mem: &mut Memory) -> Result<RcValue, Error> {
    ord(args, mem, |a, b| a < b)
}

fn less_than_or_equal(args: Vec<RcValue>, mem: &mut Memory) -> Result<RcValue, Error> {
    ord(args, mem, |a, b| a <= b)
}

fn greater_than(args: Vec<RcValue>, mem: &mut Memory) -> Result<RcValue, Error> {
    ord(args, mem, |a, b| a > b)
}

fn greater_than_or_equal(args: Vec<RcValue>, mem: &mut Memory) -> Result<RcValue, Error> {
    ord(args, mem, |a, b| a >= b)
}

fn not(args: Vec<RcValue>, mem: &mut Memory) -> Result<RcValue, Error> {
    if args.len() != 1 {
        return Err(Error::BadArity(Some("not".to_string())))
    }

    Ok(mem.boolean(args[0] == mem.b_false()))
}

fn list(args: Vec<RcValue>, mem: &mut Memory) -> Result<RcValue, Error> {
    Ok(mem.list(args))
}

fn length(args: Vec<RcValue>, mem: &mut Memory) -> Result<RcValue, Error> {
    if args.len() != 1 {
        return Err(Error::BadArity(Some("length".to_string())));
    }

    match *args[0] {
        Value::List(ref list) =>
            Ok(mem.integer(list.len() as i64)),
        _ =>
            Err(Error::WrongArgumentType(args[0].clone())),
    }
}

fn pair(args: Vec<RcValue>, mem: &mut Memory) -> Result<RcValue, Error> {
    if args.len() != 1 {
        return Err(Error::BadArity(Some("pair?".to_string())));
    }

    let outcome = match *args[0] {
        Value::List(ref list) =>
            !list.is_empty(),
        Value::DottedList(ref _list, ref _el) =>
            true,
        _ =>
            false,
    };

    Ok(mem.boolean(outcome))
}

fn cons(args: Vec<RcValue>, mem: &mut Memory) -> Result<RcValue, Error> {
    if args.len() != 2 {
        return Err(Error::BadArity(Some("cons".to_string())));
    }

    let mut list: Vec<RcValue> = Vec::new();
    list.push(args[0].clone());

    if let Value::List(ref l) = *args[1] {
        for item in l.iter() {
            list.push(item.clone());
        }

        Ok(mem.list(list))
    } else {
        Ok(mem.dotted_list(list, args[1].clone()))
    }
}

fn car(args: Vec<RcValue>) -> Result<RcValue, Error> {
    if args.len() != 1 {
        return Err(Error::BadArity(Some("car".to_string())));
    }

    match *args[0] {
        Value::List(ref l) if !l.is_empty() =>
            Ok(l[0].clone()),
        Value::DottedList(ref l, ref _t) =>
            Ok(l[0].clone()),
        _ =>
            Err(Error::WrongArgumentType(args[0].clone())),
    }
}

fn cdr(args: Vec<RcValue>, mem: &mut Memory) -> Result<RcValue, Error> {
    if args.len() != 1 {
        return Err(Error::BadArity(Some("cdr".to_string())));
    }

    match *args[0] {
        Value::List(ref l) if !l.is_empty() =>
            match l.tail() {
                tail if tail.is_empty() =>
                    Ok(mem.empty_list()),
                tail => {
                    let list = tail.iter().map(|v| v.clone()).collect();
                    Ok(mem.list(list))
                }
            },
        Value::DottedList(ref _l, ref t) =>
            Ok(t.clone()),
        _ =>
            Err(Error::WrongArgumentType(args[0].clone())),
    }
}

fn null(args: Vec<RcValue>, mem: &mut Memory) -> Result<RcValue, Error> {
    if args.len() != 1 {
        return Err(Error::BadArity(Some("null?".to_string())));
    }

    Ok(mem.boolean(args[0] == mem.empty_list()))
}

fn list_question_mark(args: Vec<RcValue>, mem: &mut Memory) -> Result<RcValue, Error> {
    if args.len() != 1 {
        return Err(Error::BadArity(Some("list?".to_string())));
    }

    let outcome = if let Value::List(ref _l) = *args[0] {
        true
    } else {
        false
    };

    Ok(mem.boolean(outcome))
}

fn list_of_integers(list: Vec<RcValue>) -> Result<Vec<i64>, Error> {
    let mut integers = Vec::with_capacity(list.len());

    for val in list.into_iter() {
        match *val {
            Value::Integer(n) =>
                integers.push(n),
            _ =>
                return Err(Error::WrongArgumentType(val.clone())),
        }
    }

    Ok(integers)
}

fn ord(args: Vec<RcValue>, mem: &mut Memory, cmp: |i64, i64| -> bool) -> Result<RcValue, Error> {
    if args.len() < 2 {
        return Ok(mem.b_true())
    }

    let integers = try!(list_of_integers(args));
    let outcome = range(0u, integers.len() - 1).all(|i|
        cmp(integers[i], integers[i + 1])
    );

    return Ok(mem.boolean(outcome))
}

fn display(args: Vec<RcValue>, mem: &mut Memory) -> Result<RcValue, Error> {
    if args.len() != 1 {
        return Err(Error::BadArity(Some("display".to_string())));
    }

    print!("{}", args.first().unwrap());

    Ok(mem.b_true())
}
<|endoftext|>


<commit_before>#[doc(
    brief = "The attribute parsing pass",
    desc =
    "Traverses the document tree, pulling relevant documention out of the \
     corresponding AST nodes. The information gathered here is the basis \
     of the natural-language documentation for a crate."
)];

import rustc::syntax::ast;
import rustc::middle::ast_map;

export mk_pass;

fn mk_pass() -> pass {
    run
}

fn run(
    srv: astsrv::srv,
    doc: doc::cratedoc
) -> doc::cratedoc {
    let fold = fold::fold({
        fold_crate: fold_crate,
        fold_mod: fold_mod,
        fold_fn: fold_fn,
        fold_const: fold_const
        with *fold::default_seq_fold(srv)
    });
    fold.fold_crate(fold, doc)
}

fn fold_crate(
    fold: fold::fold<astsrv::srv>,
    doc: doc::cratedoc
) -> doc::cratedoc {

    let srv = fold.ctxt;
    let doc = fold::default_seq_fold_crate(fold, doc);

    let attrs = astsrv::exec(srv) {|ctxt|
        let attrs = ctxt.ast.node.attrs;
        attr_parser::parse_crate(attrs)
    };

    ~{
        topmod: ~{
            name: option::from_maybe(doc.topmod.name, attrs.name)
            with *doc.topmod
        }
    }
}

#[test]
fn should_replace_top_module_name_with_crate_name() {
    let source = "#[link(name = \"bond\")];";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let fold = fold::default_seq_fold(srv);
    let doc = fold_crate(fold, doc);
    assert doc.topmod.name == "bond";
}

fn parse_item_attrs<T>(
    srv: astsrv::srv,
    id: doc::ast_id,
    parse_attrs: fn~([ast::attribute]) -> T) -> T {
    astsrv::exec(srv) {|ctxt|
        let attrs = alt ctxt.map.get(id) {
          ast_map::node_item(item) { item.attrs }
        };
        parse_attrs(attrs)
    }
}

fn fold_mod(fold: fold::fold<astsrv::srv>, doc: doc::moddoc) -> doc::moddoc {
    let srv = fold.ctxt;
    let attrs = if doc.id == ast::crate_node_id {
        // This is the top-level mod, use the crate attributes
        astsrv::exec(srv) {|ctxt|
            attr_parser::parse_mod(ctxt.ast.node.attrs)
        }
    } else {
        parse_item_attrs(srv, doc.id, attr_parser::parse_mod)
    };
    let doc = fold::default_seq_fold_mod(fold, doc);
    ret merge_mod_attrs(doc, attrs);

    fn merge_mod_attrs(
        doc: doc::moddoc,
        attrs: attr_parser::mod_attrs
    ) -> doc::moddoc {
        ~{
            brief: attrs.brief,
            desc: attrs.desc
            with *doc
        }
    }
}

#[test]
fn fold_mod_should_extract_mod_attributes() {
    let source = "#[doc = \"test\"] mod a { }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let fold = fold::default_seq_fold(srv);
    let doc = fold_mod(fold, doc.topmod.mods[0]);
    assert doc.desc == some("test");
}

#[test]
fn fold_mod_should_extract_top_mod_attributes() {
    let source = "#[doc = \"test\"];";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let fold = fold::default_seq_fold(srv);
    let doc = fold_mod(fold, doc.topmod);
    assert doc.desc == some("test");
}

fn fold_fn(
    fold: fold::fold<astsrv::srv>,
    doc: doc::fndoc
) -> doc::fndoc {

    let srv = fold.ctxt;

    let attrs = parse_item_attrs(srv, doc.id, attr_parser::parse_fn);
    ret merge_fn_attrs(doc, attrs);

    fn merge_fn_attrs(
        doc: doc::fndoc,
        attrs: attr_parser::fn_attrs
    ) -> doc::fndoc {
        ret ~{
            brief: attrs.brief,
            desc: attrs.desc,
            args: merge_arg_attrs(doc.args, attrs.args),
            return: merge_ret_attrs(doc.return, attrs.return),
            failure: attrs.failure
            with *doc
        };
    }

    fn merge_arg_attrs(
        docs: [doc::argdoc],
        attrs: [attr_parser::arg_attrs]
    ) -> [doc::argdoc] {
        vec::map(docs) {|doc|
            alt vec::find(attrs) {|attr|
                attr.name == doc.name
            } {
                some(attr) {
                    ~{
                        desc: some(attr.desc)
                        with *doc
                    }
                }
                none { doc }
            }
        }
        // FIXME: Warning when documenting a non-existent arg
    }

    fn merge_ret_attrs(
        doc: doc::retdoc,
        attrs: option<str>
    ) -> doc::retdoc {
        {
            desc: attrs
            with doc
        }
    }
}

#[test]
fn fold_fn_should_extract_fn_attributes() {
    let source = "#[doc = \"test\"] fn a() -> int { }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let fold = fold::default_seq_fold(srv);
    let doc = fold_fn(fold, doc.topmod.fns[0]);
    assert doc.desc == some("test");
}

#[test]
fn fold_fn_should_extract_arg_attributes() {
    let source = "#[doc(args(a = \"b\"))] fn c(a: bool) { }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let fold = fold::default_seq_fold(srv);
    let doc = fold_fn(fold, doc.topmod.fns[0]);
    assert doc.args[0].desc == some("b");
}

#[test]
fn fold_fn_should_extract_return_attributes() {
    let source = "#[doc(return = \"what\")] fn a() -> int { }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let doc = tystr_pass::mk_pass()(srv, doc);
    let fold = fold::default_seq_fold(srv);
    let doc = fold_fn(fold, doc.topmod.fns[0]);
    assert doc.return.desc == some("what");
}

#[test]
fn fold_fn_should_preserve_sig() {
    let source = "fn a() -> int { }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let doc = tystr_pass::mk_pass()(srv, doc);
    let fold = fold::default_seq_fold(srv);
    let doc = fold_fn(fold, doc.topmod.fns[0]);
    assert doc.sig == some("fn a() -> int");
}

#[test]
fn fold_fn_should_extract_failure_conditions() {
    let source = "#[doc(failure = \"what\")] fn a() { }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let fold = fold::default_seq_fold(srv);
    let doc = fold_fn(fold, doc.topmod.fns[0]);
    assert doc.failure == some("what");
}

fn fold_const(
    fold: fold::fold<astsrv::srv>,
    doc: doc::constdoc
) -> doc::constdoc {
    let srv = fold.ctxt;
    let attrs = parse_item_attrs(srv, doc.id, attr_parser::parse_mod);

    ~{
        brief: attrs.brief,
        desc: attrs.desc
        with *doc
    }
}

#[test]
fn fold_const_should_extract_docs() {
    let source = "#[doc(brief = \"foo\", desc = \"bar\")]\
                  const a: bool = true;";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let fold = fold::default_seq_fold(srv);
    let doc = fold_const(fold, doc.topmod.consts[0]);
    assert doc.brief == some("foo");
    assert doc.desc == some("bar");
}
<commit_msg>rustdoc: Add enum doc attributes to the doc tree<commit_after>#[doc(
    brief = "The attribute parsing pass",
    desc =
    "Traverses the document tree, pulling relevant documention out of the \
     corresponding AST nodes. The information gathered here is the basis \
     of the natural-language documentation for a crate."
)];

import rustc::syntax::ast;
import rustc::middle::ast_map;

export mk_pass;

fn mk_pass() -> pass {
    run
}

fn run(
    srv: astsrv::srv,
    doc: doc::cratedoc
) -> doc::cratedoc {
    let fold = fold::fold({
        fold_crate: fold_crate,
        fold_mod: fold_mod,
        fold_fn: fold_fn,
        fold_const: fold_const,
        fold_enum: fold_enum
        with *fold::default_seq_fold(srv)
    });
    fold.fold_crate(fold, doc)
}

fn fold_crate(
    fold: fold::fold<astsrv::srv>,
    doc: doc::cratedoc
) -> doc::cratedoc {

    let srv = fold.ctxt;
    let doc = fold::default_seq_fold_crate(fold, doc);

    let attrs = astsrv::exec(srv) {|ctxt|
        let attrs = ctxt.ast.node.attrs;
        attr_parser::parse_crate(attrs)
    };

    ~{
        topmod: ~{
            name: option::from_maybe(doc.topmod.name, attrs.name)
            with *doc.topmod
        }
    }
}

#[test]
fn should_replace_top_module_name_with_crate_name() {
    let source = "#[link(name = \"bond\")];";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let fold = fold::default_seq_fold(srv);
    let doc = fold_crate(fold, doc);
    assert doc.topmod.name == "bond";
}

fn parse_item_attrs<T>(
    srv: astsrv::srv,
    id: doc::ast_id,
    parse_attrs: fn~([ast::attribute]) -> T) -> T {
    astsrv::exec(srv) {|ctxt|
        let attrs = alt ctxt.map.get(id) {
          ast_map::node_item(item) { item.attrs }
        };
        parse_attrs(attrs)
    }
}

fn fold_mod(fold: fold::fold<astsrv::srv>, doc: doc::moddoc) -> doc::moddoc {
    let srv = fold.ctxt;
    let attrs = if doc.id == ast::crate_node_id {
        // This is the top-level mod, use the crate attributes
        astsrv::exec(srv) {|ctxt|
            attr_parser::parse_mod(ctxt.ast.node.attrs)
        }
    } else {
        parse_item_attrs(srv, doc.id, attr_parser::parse_mod)
    };
    let doc = fold::default_seq_fold_mod(fold, doc);
    ret merge_mod_attrs(doc, attrs);

    fn merge_mod_attrs(
        doc: doc::moddoc,
        attrs: attr_parser::mod_attrs
    ) -> doc::moddoc {
        ~{
            brief: attrs.brief,
            desc: attrs.desc
            with *doc
        }
    }
}

#[test]
fn fold_mod_should_extract_mod_attributes() {
    let source = "#[doc = \"test\"] mod a { }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let fold = fold::default_seq_fold(srv);
    let doc = fold_mod(fold, doc.topmod.mods[0]);
    assert doc.desc == some("test");
}

#[test]
fn fold_mod_should_extract_top_mod_attributes() {
    let source = "#[doc = \"test\"];";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let fold = fold::default_seq_fold(srv);
    let doc = fold_mod(fold, doc.topmod);
    assert doc.desc == some("test");
}

fn fold_fn(
    fold: fold::fold<astsrv::srv>,
    doc: doc::fndoc
) -> doc::fndoc {

    let srv = fold.ctxt;

    let attrs = parse_item_attrs(srv, doc.id, attr_parser::parse_fn);
    ret merge_fn_attrs(doc, attrs);

    fn merge_fn_attrs(
        doc: doc::fndoc,
        attrs: attr_parser::fn_attrs
    ) -> doc::fndoc {
        ret ~{
            brief: attrs.brief,
            desc: attrs.desc,
            args: merge_arg_attrs(doc.args, attrs.args),
            return: merge_ret_attrs(doc.return, attrs.return),
            failure: attrs.failure
            with *doc
        };
    }

    fn merge_arg_attrs(
        docs: [doc::argdoc],
        attrs: [attr_parser::arg_attrs]
    ) -> [doc::argdoc] {
        vec::map(docs) {|doc|
            alt vec::find(attrs) {|attr|
                attr.name == doc.name
            } {
                some(attr) {
                    ~{
                        desc: some(attr.desc)
                        with *doc
                    }
                }
                none { doc }
            }
        }
        // FIXME: Warning when documenting a non-existent arg
    }

    fn merge_ret_attrs(
        doc: doc::retdoc,
        attrs: option<str>
    ) -> doc::retdoc {
        {
            desc: attrs
            with doc
        }
    }
}

#[test]
fn fold_fn_should_extract_fn_attributes() {
    let source = "#[doc = \"test\"] fn a() -> int { }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let fold = fold::default_seq_fold(srv);
    let doc = fold_fn(fold, doc.topmod.fns[0]);
    assert doc.desc == some("test");
}

#[test]
fn fold_fn_should_extract_arg_attributes() {
    let source = "#[doc(args(a = \"b\"))] fn c(a: bool) { }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let fold = fold::default_seq_fold(srv);
    let doc = fold_fn(fold, doc.topmod.fns[0]);
    assert doc.args[0].desc == some("b");
}

#[test]
fn fold_fn_should_extract_return_attributes() {
    let source = "#[doc(return = \"what\")] fn a() -> int { }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let doc = tystr_pass::mk_pass()(srv, doc);
    let fold = fold::default_seq_fold(srv);
    let doc = fold_fn(fold, doc.topmod.fns[0]);
    assert doc.return.desc == some("what");
}

#[test]
fn fold_fn_should_preserve_sig() {
    let source = "fn a() -> int { }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let doc = tystr_pass::mk_pass()(srv, doc);
    let fold = fold::default_seq_fold(srv);
    let doc = fold_fn(fold, doc.topmod.fns[0]);
    assert doc.sig == some("fn a() -> int");
}

#[test]
fn fold_fn_should_extract_failure_conditions() {
    let source = "#[doc(failure = \"what\")] fn a() { }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let fold = fold::default_seq_fold(srv);
    let doc = fold_fn(fold, doc.topmod.fns[0]);
    assert doc.failure == some("what");
}

fn fold_const(
    fold: fold::fold<astsrv::srv>,
    doc: doc::constdoc
) -> doc::constdoc {
    let srv = fold.ctxt;
    let attrs = parse_item_attrs(srv, doc.id, attr_parser::parse_mod);

    ~{
        brief: attrs.brief,
        desc: attrs.desc
        with *doc
    }
}

#[test]
fn fold_const_should_extract_docs() {
    let source = "#[doc(brief = \"foo\", desc = \"bar\")]\
                  const a: bool = true;";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let fold = fold::default_seq_fold(srv);
    let doc = fold_const(fold, doc.topmod.consts[0]);
    assert doc.brief == some("foo");
    assert doc.desc == some("bar");
}

fn fold_enum(
    fold: fold::fold<astsrv::srv>,
    doc: doc::enumdoc
) -> doc::enumdoc {
    let srv = fold.ctxt;
    let attrs = parse_item_attrs(srv, doc.id, attr_parser::parse_enum);

    ~{
        brief: attrs.brief,
        desc: attrs.desc,
        variants: vec::map(doc.variants) {|variant|
            let attrs = astsrv::exec(srv) {|ctxt|
                alt ctxt.map.get(doc.id) {
                  ast_map::node_item(@{
                    node: ast::item_enum(ast_variants, _), _
                  }) {
                    let ast_variant = option::get(
                        vec::find(ast_variants) {|v|
                            v.node.name == variant.name
                        });

                    attr_parser::parse_variant(ast_variant.node.attrs)
                  }
                }
            };

            ~{
                desc: attrs.desc
                with *variant
            }
        }
        with *doc
    }
}

#[test]
fn fold_enum_should_extract_docs() {
    let source = "#[doc(brief = \"a\", desc = \"b\")]\
                  enum a { v }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let fold = fold::default_seq_fold(srv);
    let doc = fold_enum(fold, doc.topmod.enums[0]);
    assert doc.brief == some("a");
    assert doc.desc == some("b");
}

#[test]
fn fold_enum_should_extract_variant_docs() {
    let source = "enum a { #[doc = \"c\"] v }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let fold = fold::default_seq_fold(srv);
    let doc = fold_enum(fold, doc.topmod.enums[0]);
    assert doc.variants[0].desc == some("c");
}
<|endoftext|>


<commit_before>use PatternValue;
use mir;

/// An adjustment to a pattern.
///
/// Not all possible patterns are an identical match to
/// the MIR. To accomodate this, we have the concept of a
/// pattern _adjustment_.
///
/// When matching patterns, we can have several adjustments
/// which define permutations that would need to be made to the
/// original pattern in order to match.
///
/// We can then look at all the adjustments and figure out which
/// pattern is the most optimal to select.
///
/// Take the case where we have
///
/// ```ignore
/// (add %a, (add %foo, %bar))
/// ```
///
/// This will likely have to have an adjustment to demote the
/// nested addition to a register, so that the code becomes.
///
/// ```ignore
/// %tmp = (add %foo, %bar)
/// (add %a, %tmp)
/// ```
#[derive(Clone,Debug,PartialEq,Eq)]
pub enum Adjustment<V: PatternValue>
{
    /// Demotes a subnode to a register.
    DemoteToRegister {
        demotee: mir::Node,
    },
    Target(V::Adjustment),
}

/// The result of an adjustment application.
#[derive(Clone,Debug,PartialEq,Eq)]
pub struct AdjustmentApplication
{
    /// An adjustment may create extra nodes preceding the node
    /// that was adjusted. For example, promoting an operand
    /// to a register would a register set node to precede the adjusted node.
    pub preceding_nodes: Vec<mir::Node>,

    /// The original node that was adjusted.
    pub adjusted_node: mir::Node,
}

impl AdjustmentApplication
{
    pub fn unadjusted(node: mir::Node) -> Self {
        AdjustmentApplication {
            preceding_nodes: Vec::new(),
            adjusted_node: node,
        }
    }

    /// Gets all of the nodes (in order) that were created or modified
    /// by the adjustment.
    pub fn nodes(&self) -> Vec<mir::Node> {
        let mut nodes = self.preceding_nodes.clone();
        nodes.push(self.adjusted_node.clone());
        nodes
    }

    fn merge(mut self, other: Self) -> Self {
        self.preceding_nodes.extend(other.preceding_nodes);
        self.adjusted_node = other.adjusted_node;
        self
    }
}

impl<V: PatternValue> Adjustment<V>
{
    pub fn demote_to_register(node: &mir::Node) -> Self {
        Adjustment::DemoteToRegister {
            demotee: node.clone(),
        }
    }

    pub fn apply_several_to(root_node: mir::Node, adjustments: &[Self]) -> AdjustmentApplication {
        adjustments.iter().fold(AdjustmentApplication::unadjusted(root_node), |last_application, adjustment| {
            let current_node = last_application.adjusted_node.clone();
            last_application.merge(adjustment.apply_to(current_node))
        })
    }

    /// Applies an adjustment to a node.
    pub fn apply_to(&self, root_node: mir::Node) -> AdjustmentApplication {
        match *self {
            Adjustment::DemoteToRegister { ref demotee } => {
                let mut preceding_nodes = Vec::new();

                let adjusted_node = root_node.recursive_map(&mut |node| {
                    if node == *demotee {
                        let register_ref = mir::Node::new_register_ref(node.ty());
                        preceding_nodes.push(mir::Node::set(register_ref.clone(), node));
                        register_ref
                    } else {
                        node
                    }
                });

                AdjustmentApplication { preceding_nodes: preceding_nodes, adjusted_node: adjusted_node }
            },
            Adjustment::Target(ref _adjustment) => {
                unimplemented!();
            },
        }
    }
}

#[cfg(test)]
mod test
{
    mod apply_to {
        use super::super::*;
        use mir;
        use pattern::DummyPatternValue;

        #[test]
        fn demote_to_register() {
            let register_ref = mir::Node::new_register_ref(mir::Type::i8());
            let example_node = mir::Node::set(register_ref.clone(), mir::Node::i(8, 2));

            let adjustment: Adjustment<DummyPatternValue> = Adjustment::DemoteToRegister {
                demotee: mir::Node::i(8, 2)
            };

            let application = adjustment.apply_to(example_node);

            assert_eq!(application.preceding_nodes.len(), 1);

            let new_set_node = application.preceding_nodes[0].expect_branch();
            let new_register_ref = new_set_node.operands[0].clone();
            assert_eq!(new_set_node.operands[1], mir::Node::i(8, 2));

            let permuted_node = application.adjusted_node.expect_branch();
            assert_eq!(permuted_node.operands[1], new_register_ref);
        }
    }
}

<commit_msg>Add ApplyConstraint adjustment<commit_after>use PatternValue;
use Constraint;
use mir;

/// An adjustment to a pattern.
///
/// Not all possible patterns are an identical match to
/// the MIR. To accomodate this, we have the concept of a
/// pattern _adjustment_.
///
/// When matching patterns, we can have several adjustments
/// which define permutations that would need to be made to the
/// original pattern in order to match.
///
/// We can then look at all the adjustments and figure out which
/// pattern is the most optimal to select.
///
/// Take the case where we have
///
/// ```ignore
/// (add %a, (add %foo, %bar))
/// ```
///
/// This will likely have to have an adjustment to demote the
/// nested addition to a register, so that the code becomes.
///
/// ```ignore
/// %tmp = (add %foo, %bar)
/// (add %a, %tmp)
/// ```
#[derive(Clone,Debug,PartialEq,Eq)]
pub enum Adjustment<V: PatternValue>
{
    /// Demotes a subnode to a register.
    DemoteToRegister {
        demotee: mir::Node,
    },
    /// Apply a constraint to the original MIR sequence.
    ApplyConstraint(Constraint),
    /// A target-specific constraint.
    Target(V::Adjustment),
}

/// The result of an adjustment application.
#[derive(Clone,Debug,PartialEq,Eq)]
pub struct AdjustmentApplication
{
    /// An adjustment may create extra nodes preceding the node
    /// that was adjusted. For example, promoting an operand
    /// to a register would a register set node to precede the adjusted node.
    pub preceding_nodes: Vec<mir::Node>,

    /// The original node that was adjusted.
    pub adjusted_node: mir::Node,
}

impl AdjustmentApplication
{
    pub fn unadjusted(node: mir::Node) -> Self {
        AdjustmentApplication {
            preceding_nodes: Vec::new(),
            adjusted_node: node,
        }
    }

    /// Gets all of the nodes (in order) that were created or modified
    /// by the adjustment.
    pub fn nodes(&self) -> Vec<mir::Node> {
        let mut nodes = self.preceding_nodes.clone();
        nodes.push(self.adjusted_node.clone());
        nodes
    }

    fn merge(mut self, other: Self) -> Self {
        self.preceding_nodes.extend(other.preceding_nodes);
        self.adjusted_node = other.adjusted_node;
        self
    }
}

impl<V: PatternValue> Adjustment<V>
{
    pub fn demote_to_register(node: &mir::Node) -> Self {
        Adjustment::DemoteToRegister {
            demotee: node.clone(),
        }
    }

    pub fn apply_several_to(root_node: mir::Node, adjustments: &[Self]) -> AdjustmentApplication {
        adjustments.iter().fold(AdjustmentApplication::unadjusted(root_node), |last_application, adjustment| {
            let current_node = last_application.adjusted_node.clone();
            last_application.merge(adjustment.apply_to(current_node))
        })
    }

    /// Applies an adjustment to a node.
    pub fn apply_to(&self, root_node: mir::Node) -> AdjustmentApplication {
        match *self {
            Adjustment::DemoteToRegister { ref demotee } => {
                let mut preceding_nodes = Vec::new();

                let adjusted_node = root_node.recursive_map(&mut |node| {
                    if node == *demotee {
                        let register_ref = mir::Node::new_register_ref(node.ty());
                        preceding_nodes.push(mir::Node::set(register_ref.clone(), node));
                        register_ref
                    } else {
                        node
                    }
                });

                AdjustmentApplication { preceding_nodes: preceding_nodes, adjusted_node: adjusted_node }
            },
            Adjustment::ApplyConstraint(ref _constraint) => {
                unimplemented!();
            },
            Adjustment::Target(ref _adjustment) => {
                unimplemented!();
            },
        }
    }
}

#[cfg(test)]
mod test
{
    mod apply_to {
        use super::super::*;
        use mir;
        use pattern::DummyPatternValue;

        #[test]
        fn demote_to_register() {
            let register_ref = mir::Node::new_register_ref(mir::Type::i8());
            let example_node = mir::Node::set(register_ref.clone(), mir::Node::i(8, 2));

            let adjustment: Adjustment<DummyPatternValue> = Adjustment::DemoteToRegister {
                demotee: mir::Node::i(8, 2)
            };

            let application = adjustment.apply_to(example_node);

            assert_eq!(application.preceding_nodes.len(), 1);

            let new_set_node = application.preceding_nodes[0].expect_branch();
            let new_register_ref = new_set_node.operands[0].clone();
            assert_eq!(new_set_node.operands[1], mir::Node::i(8, 2));

            let permuted_node = application.adjusted_node.expect_branch();
            assert_eq!(permuted_node.operands[1], new_register_ref);
        }
    }
}

<|endoftext|>


<commit_before><commit_msg>Use only Path not strings for template loading<commit_after><|endoftext|>


<commit_before>import std::str;
import std::rope::*;
import std::option;
import std::uint;

//Utility function, used for sanity check
fn rope_to_string(r: rope) -> str {
    alt(r) {
      node::empty. { ret "" }
      node::content(x) {
        let str = @mutable "";
        fn aux(str: @mutable str, node: @node::node) {
            alt(*node) {
              node::leaf(x) {
                *str += str::substr(*x.content, x.byte_offset, x.byte_len);
              }
              node::concat(x) {
                aux(str, x.left);
                aux(str, x.right);
              }
            }
        }
        aux(str, x);
        ret *str
      }
    }
}

#[test]
fn trivial() {
    assert char_len(empty()) == 0u;
    assert byte_len(empty()) == 0u;
}

#[test]
fn of_string1() {
    let sample = @"0123456789ABCDE";
    let r      = of_str(sample);

    assert char_len(r) == str::char_len(*sample);
    assert rope_to_string(r) == *sample;
}

#[test]
fn of_string2() {
    let buf = @ mutable "1234567890";
    let i = 0;
    while i < 10 { *buf = *buf + *buf; i+=1;}
    let sample = @*buf;
    let r      = of_str(sample);
    assert char_len(r) == str::char_len(*sample);
    assert rope_to_string(r) == *sample;

    let string_iter = 0u;
    let string_len  = str::byte_len(*sample);
    let rope_iter   = iterator::char::start(r);
    let equal       = true;
    let pos         = 0u;
    while equal {
        alt(node::char_iterator::next(rope_iter)) {
          option::none. {
            if string_iter < string_len {
                equal = false;
            } break; }
          option::some(c) {
            let {ch, next} = str::char_range_at(*sample, string_iter);
            string_iter = next;
            if ch != c { equal = false; break; }
          }
        }
        pos += 1u;
    }

    assert equal;
}

#[test]
fn iter1() {
    let buf = @ mutable "1234567890";
    let i = 0;
    while i < 10 { *buf = *buf + *buf; i+=1;}
    let sample = @*buf;
    let r      = of_str(sample);

    let len = 0u;
    let it  = iterator::char::start(r);
    while true {
        alt(node::char_iterator::next(it)) {
          option::none. { break; }
          option::some(_) { len += 1u; }
        }
    }

    assert len == str::char_len(*sample);
}

#[test]
fn bal1() {
    let init = @ "1234567890";
    let buf  = @ mutable * init;
    let i = 0;
    while i < 16 { *buf = *buf + *buf; i+=1;}
    let sample = @*buf;
    let r1     = of_str(sample);
    let r2     = of_str(init);
    i = 0;
    while i < 16 { r2 = append_rope(r2, r2); i+= 1;}

    assert eq(r1, r2);
    let r3 = bal(r2);
    assert char_len(r1) == char_len(r3);

    assert eq(r1, r3);
}

#[test]
fn char_at1() {
    //Generate a large rope
    let r = of_str(@ "123456789");
    uint::range(0u, 10u){|_i|
        r = append_rope(r, r);
    }

    //Copy it in the slowest possible way
    let r2 = empty();
    uint::range(0u, char_len(r)){|i|
        r2 = append_char(r2, char_at(r, i));
    }
    assert eq(r, r2);

    let r3 = empty();
    uint::range(0u, char_len(r)){|i|
        r3 = prepend_char(r3, char_at(r, char_len(r) - i - 1u));
    }
    assert eq(r, r3);

    //Additional sanity checks
    let balr = bal(r);
    let bal2 = bal(r2);
    let bal3 = bal(r3);
    assert eq(r, balr);
    assert eq(r, bal2);
    assert eq(r, bal3);
    assert eq(r2, r3);
    assert eq(bal2, bal3);
}
<commit_msg>[Test] rope.rs: testing concat<commit_after>import std::str;
import std::rope::*;
import std::option;
import std::uint;
import std::vec;

//Utility function, used for sanity check
fn rope_to_string(r: rope) -> str {
    alt(r) {
      node::empty. { ret "" }
      node::content(x) {
        let str = @mutable "";
        fn aux(str: @mutable str, node: @node::node) {
            alt(*node) {
              node::leaf(x) {
                *str += str::substr(*x.content, x.byte_offset, x.byte_len);
              }
              node::concat(x) {
                aux(str, x.left);
                aux(str, x.right);
              }
            }
        }
        aux(str, x);
        ret *str
      }
    }
}

#[test]
fn trivial() {
    assert char_len(empty()) == 0u;
    assert byte_len(empty()) == 0u;
}

#[test]
fn of_string1() {
    let sample = @"0123456789ABCDE";
    let r      = of_str(sample);

    assert char_len(r) == str::char_len(*sample);
    assert rope_to_string(r) == *sample;
}

#[test]
fn of_string2() {
    let buf = @ mutable "1234567890";
    let i = 0;
    while i < 10 { *buf = *buf + *buf; i+=1;}
    let sample = @*buf;
    let r      = of_str(sample);
    assert char_len(r) == str::char_len(*sample);
    assert rope_to_string(r) == *sample;

    let string_iter = 0u;
    let string_len  = str::byte_len(*sample);
    let rope_iter   = iterator::char::start(r);
    let equal       = true;
    let pos         = 0u;
    while equal {
        alt(node::char_iterator::next(rope_iter)) {
          option::none. {
            if string_iter < string_len {
                equal = false;
            } break; }
          option::some(c) {
            let {ch, next} = str::char_range_at(*sample, string_iter);
            string_iter = next;
            if ch != c { equal = false; break; }
          }
        }
        pos += 1u;
    }

    assert equal;
}

#[test]
fn iter1() {
    let buf = @ mutable "1234567890";
    let i = 0;
    while i < 10 { *buf = *buf + *buf; i+=1;}
    let sample = @*buf;
    let r      = of_str(sample);

    let len = 0u;
    let it  = iterator::char::start(r);
    while true {
        alt(node::char_iterator::next(it)) {
          option::none. { break; }
          option::some(_) { len += 1u; }
        }
    }

    assert len == str::char_len(*sample);
}

#[test]
fn bal1() {
    let init = @ "1234567890";
    let buf  = @ mutable * init;
    let i = 0;
    while i < 16 { *buf = *buf + *buf; i+=1;}
    let sample = @*buf;
    let r1     = of_str(sample);
    let r2     = of_str(init);
    i = 0;
    while i < 16 { r2 = append_rope(r2, r2); i+= 1;}

    assert eq(r1, r2);
    let r3 = bal(r2);
    assert char_len(r1) == char_len(r3);

    assert eq(r1, r3);
}

#[test]
fn char_at1() {
    //Generate a large rope
    let r = of_str(@ "123456789");
    uint::range(0u, 10u){|_i|
        r = append_rope(r, r);
    }

    //Copy it in the slowest possible way
    let r2 = empty();
    uint::range(0u, char_len(r)){|i|
        r2 = append_char(r2, char_at(r, i));
    }
    assert eq(r, r2);

    let r3 = empty();
    uint::range(0u, char_len(r)){|i|
        r3 = prepend_char(r3, char_at(r, char_len(r) - i - 1u));
    }
    assert eq(r, r3);

    //Additional sanity checks
    let balr = bal(r);
    let bal2 = bal(r2);
    let bal3 = bal(r3);
    assert eq(r, balr);
    assert eq(r, bal2);
    assert eq(r, bal3);
    assert eq(r2, r3);
    assert eq(bal2, bal3);
}

#[test]
fn concat1() {
    //Generate a reasonable rope
    let chunk = of_str(@ "123456789");
    let r = empty();
    uint::range(0u, 10u){|_i|
        r = append_rope(r, chunk);
    }

    //Same rope, obtained with rope::concat
    let r2 = concat(vec::init_elt(chunk, 10u));

    assert eq(r, r2);
}<|endoftext|>


<commit_before>import std::test;
import std::str;
import std::option;
import std::either;
import std::ivec;

#[test]
fn do_not_run_ignored_tests() {
    auto ran = @mutable false;
    auto f = bind fn(@mutable bool ran) {
        *ran = true;
    } (ran);

    auto desc = rec(name = "whatever",
                    fn = f,
                    ignore = true);

    auto res = test::run_test(desc);

    assert ran == false;
}

#[test]
fn ignored_tests_result_in_ignored() {
    fn f() { }
    auto desc = rec(name = "whatever",
                    fn = f,
                    ignore = true);
    auto res = test::run_test(desc);
    assert res == test::tr_ignored;
}

#[test]
fn first_free_arg_should_be_a_filter() {
    auto args = ~["progname", "filter"];
    check ivec::is_not_empty(args);
    auto opts = alt test::parse_opts(args) { either::left(?o) { o } };
    assert str::eq("filter", option::get(opts.filter));
}

#[test]
fn parse_ignored_flag() {
    auto args = ~["progname", "filter", "--ignored"];
    check ivec::is_not_empty(args);
    auto opts = alt test::parse_opts(args) { either::left(?o) { o } };
    assert opts.run_ignored;
}

#[test]
fn filter_for_ignored_option() {
    // When we run ignored tests the test filter should filter out all the
    // unignored tests and flip the ignore flag on the rest to false

    auto opts = rec(filter = option::none,
                    run_ignored = true);
    auto tests = ~[rec(name = "1",
                       fn = fn() {},
                       ignore = true),
                   rec(name = "2",
                       fn = fn() {},
                       ignore = false)];
    auto filtered = test::filter_tests(opts, tests);

    assert ivec::len(filtered) == 1u;
    assert filtered.(0).name == "1";
    assert filtered.(0).ignore == false;
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<commit_msg>Remove unused variable from test tests<commit_after>import std::test;
import std::str;
import std::option;
import std::either;
import std::ivec;

#[test]
fn do_not_run_ignored_tests() {
    auto ran = @mutable false;
    auto f = bind fn(@mutable bool ran) {
        *ran = true;
    } (ran);

    auto desc = rec(name = "whatever",
                    fn = f,
                    ignore = true);

    test::run_test(desc);

    assert ran == false;
}

#[test]
fn ignored_tests_result_in_ignored() {
    fn f() { }
    auto desc = rec(name = "whatever",
                    fn = f,
                    ignore = true);
    auto res = test::run_test(desc);
    assert res == test::tr_ignored;
}

#[test]
fn first_free_arg_should_be_a_filter() {
    auto args = ~["progname", "filter"];
    check ivec::is_not_empty(args);
    auto opts = alt test::parse_opts(args) { either::left(?o) { o } };
    assert str::eq("filter", option::get(opts.filter));
}

#[test]
fn parse_ignored_flag() {
    auto args = ~["progname", "filter", "--ignored"];
    check ivec::is_not_empty(args);
    auto opts = alt test::parse_opts(args) { either::left(?o) { o } };
    assert opts.run_ignored;
}

#[test]
fn filter_for_ignored_option() {
    // When we run ignored tests the test filter should filter out all the
    // unignored tests and flip the ignore flag on the rest to false

    auto opts = rec(filter = option::none,
                    run_ignored = true);
    auto tests = ~[rec(name = "1",
                       fn = fn() {},
                       ignore = true),
                   rec(name = "2",
                       fn = fn() {},
                       ignore = false)];
    auto filtered = test::filter_tests(opts, tests);

    assert ivec::len(filtered) == 1u;
    assert filtered.(0).name == "1";
    assert filtered.(0).ignore == false;
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<|endoftext|>


<commit_before>// build.rs

use std::process::Command;
use std::env;
use std::path::Path;
#[macro_use]
extern crate error_chain;

error_chain!{
 foreign_links {
        Io(std::io::Error);
    }
}

fn program_exists(program: &str) -> Result<()> {
    Command::new(program)
        .arg("-v")
        .output()
        .chain_err(|| format!("Please install '{}'!", program))?;
    Ok(())
}

fn npm_package_exists(package: &str) -> Result<()> {
    let status = Command::new("npm")
        .args(&["list", "-g"])
        .arg(package)
        .output();

    match status {
        Ok(ref out) if out.status.success() => Ok(()),
        _ => {
            bail!("Missing npm package '{0}' \
                  install with: 'npm -g install {0}'",
                  package)
        },
    }
}

pub enum Resource<'a> {
    Program(&'a str),
    Package(&'a str),
}
use Resource::{Program, Package};

impl<'a> Resource<'a> {
    pub fn exists(&self) -> Result<()> {
        match *self {
            Program(name) => program_exists(name),
            Package(name) => npm_package_exists(name),
        }
    }
}

fn run() -> Result<()> {

    if let Ok(_) = env::var("CARGO_FEATURE_REGENERATE_CSS") {
        // Check dependencies
        Program("npm").exists()?;
        Program("node").exists()?;
        Package("nib").exists()?;
        Package("stylus").exists()?;

        // Compile stylus stylesheet to css
        let manifest_dir = env::var("CARGO_MANIFEST_DIR")
            .chain_err(|| "Please run the script with: 'cargo build'!")?;
        let theme_dir = Path::new(&manifest_dir).join("src/theme/");
        let stylus_dir = theme_dir.join("stylus/book.styl");

        if !Command::new("stylus")
                .arg(stylus_dir)
                .arg("--out")
                .arg(theme_dir)
                .arg("--use")
                .arg("nib")
                .status()?
                .success() {
            bail!("Stylus encoutered an error");
        }
    }
    Ok(())
}

quick_main!(run);
<commit_msg>Workaround for not being able to run stylus on windows<commit_after>// build.rs

use std::process::Command;
use std::env;
use std::path::Path;
#[macro_use]
extern crate error_chain;

#[cfg(windows)]
mod execs {
    pub const NPM: &str = "npm.cmd";
    pub const STYLUS: &str = "stylus.cmd";
}
#[cfg(not(windows))]
mod execs {
    pub const NPM: &str = "npm";
    pub const STYLUS: &str = "stylus";
}

error_chain!{
 foreign_links {
        Io(std::io::Error);
    }
}

fn program_exists(program: &str) -> Result<()> {
    Command::new(program)
        .arg("-v")
        .output()
        .chain_err(|| format!("Please install '{}'!", program))?;
    Ok(())
}

fn npm_package_exists(package: &str) -> Result<()> {
    let status = Command::new(execs::NPM)
        .args(&["list", "-g"])
        .arg(package)
        .output();

    match status {
        Ok(ref out) if out.status.success() => Ok(()),
        _ => {
            bail!("Missing npm package '{0}' \
                  install with: 'npm -g install {0}'",
                  package)
        },
    }
}

pub enum Resource<'a> {
    Program(&'a str),
    Package(&'a str),
}
use Resource::{Program, Package};

impl<'a> Resource<'a> {
    pub fn exists(&self) -> Result<()> {
        match *self {
            Program(name) => program_exists(name),
            Package(name) => npm_package_exists(name),
        }
    }
}

fn run() -> Result<()> {

    if let Ok(_) = env::var("CARGO_FEATURE_REGENERATE_CSS") {
        // Check dependencies
        Program(execs::NPM).exists()?;
        Program("node").exists()?;
        Package("nib").exists()?;
        Package("stylus").exists()?;

        // Compile stylus stylesheet to css
        let manifest_dir = env::var("CARGO_MANIFEST_DIR")
            .chain_err(|| "Please run the script with: 'cargo build'!")?;
        let theme_dir = Path::new(&manifest_dir).join("src/theme/");
        let stylus_dir = theme_dir.join("stylus/book.styl");

        if !Command::new(execs::STYLUS)
                .arg(stylus_dir)
                .arg("--out")
                .arg(theme_dir)
                .arg("--use")
                .arg("nib")
                .status()?
                .success() {
            bail!("Stylus encoutered an error");
        }
    }
    Ok(())
}

quick_main!(run);
<|endoftext|>


<commit_before>// Copyright (c) 2017-2020, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

#![allow(clippy::print_literal)]
#![allow(clippy::unused_io_amount)]

use rustc_version::{version, Version};
#[allow(unused_imports)]
use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::exit;

#[allow(dead_code)]
fn rerun_dir<P: AsRef<Path>>(dir: P) {
  for entry in fs::read_dir(dir).unwrap() {
    let entry = entry.unwrap();
    let path = entry.path();
    println!("cargo:rerun-if-changed={}", path.to_string_lossy());

    if path.is_dir() {
      rerun_dir(path);
    }
  }
}

#[allow(dead_code)]
fn hash_changed(
  files: &[&str], out_dir: &str, config: &Path,
) -> Option<([u8; 8], PathBuf)> {
  use std::collections::hash_map::DefaultHasher;
  use std::hash::Hasher;
  use std::io::Read;

  let mut hasher = DefaultHasher::new();

  let paths = files.iter().map(Path::new).chain(std::iter::once(config));

  for path in paths {
    if let Ok(mut f) = std::fs::File::open(path) {
      let mut buf = Vec::new();
      f.read_to_end(&mut buf).unwrap();

      hasher.write(&buf);
    } else {
      panic!("Cannot open {}", path.display());
    }
  }

  let hash = hasher.finish().to_be_bytes();

  let hash_path = Path::new(&out_dir).join("asm.hash");

  if let Ok(old_hash) = std::fs::read(&hash_path) {
    if old_hash == hash {
      return None;
    }
  }

  Some((hash, hash_path))
}

#[cfg(feature = "asm")]
fn build_nasm_files() {
  use std::fs::File;
  use std::io::Write;
  let out_dir = env::var("OUT_DIR").unwrap();

  let dest_path = Path::new(&out_dir).join("config.asm");
  let mut config_file = File::create(&dest_path).unwrap();
  config_file.write(b"	%define private_prefix rav1e\n").unwrap();
  config_file.write(b"	%define ARCH_X86_32 0\n").unwrap();
  config_file.write(b" %define ARCH_X86_64 1\n").unwrap();
  config_file.write(b"	%define PIC 1\n").unwrap();
  config_file.write(b" %define STACK_ALIGNMENT 16\n").unwrap();
  config_file.write(b" %define HAVE_AVX512ICL 1\n").unwrap();
  if env::var("CARGO_CFG_TARGET_OS").unwrap() == "macos" {
    config_file.write(b" %define PREFIX 1\n").unwrap();
  }

  let asm_files = &[
    "src/x86/ipred.asm",
    "src/x86/ipred_ssse3.asm",
    "src/x86/itx.asm",
    "src/x86/itx_ssse3.asm",
    "src/x86/mc.asm",
    "src/x86/mc_ssse3.asm",
    "src/x86/me.asm",
    "src/x86/sad_sse2.asm",
    "src/x86/sad_avx.asm",
    "src/x86/satd.asm",
    "src/x86/sse.asm",
    "src/x86/cdef.asm",
    "src/x86/tables.asm",
  ];

  if let Some((hash, hash_path)) =
    hash_changed(asm_files, &out_dir, &dest_path)
  {
    let mut config_include_arg = String::from("-I");
    config_include_arg.push_str(&out_dir);
    config_include_arg.push('/');
    nasm_rs::compile_library_args(
      "rav1easm",
      asm_files,
      &[&config_include_arg, "-Isrc/"],
    )
    .expect(
      "NASM build failed. Make sure you have nasm installed. https://nasm.us",
    );
    std::fs::write(hash_path, &hash[..]).unwrap();
  } else {
    println!("cargo:rustc-link-search={}", out_dir);
  }
  println!("cargo:rustc-link-lib=static=rav1easm");
  rerun_dir("src/x86");
  rerun_dir("src/ext/x86");
}

#[cfg(feature = "asm")]
fn build_asm_files() {
  use std::fs::File;
  use std::io::Write;
  let out_dir = env::var("OUT_DIR").unwrap();

  let dest_path = Path::new(&out_dir).join("config.h");
  let mut config_file = File::create(&dest_path).unwrap();
  config_file.write(b" #define PRIVATE_PREFIX rav1e_\n").unwrap();
  config_file.write(b" #define ARCH_AARCH64 1\n").unwrap();
  config_file.write(b" #define ARCH_ARM 0\n").unwrap();
  config_file.write(b" #define CONFIG_LOG 1 \n").unwrap();
  config_file.write(b" #define HAVE_ASM 1\n").unwrap();
  config_file.sync_all().unwrap();

  let asm_files = &[
    "src/arm/64/cdef.S",
    "src/arm/64/cdef16.S",
    "src/arm/64/mc.S",
    "src/arm/64/mc16.S",
    "src/arm/64/itx.S",
    "src/arm/64/itx16.S",
    "src/arm/64/ipred.S",
    "src/arm/64/ipred16.S",
    "src/arm/64/sad.S",
    "src/arm/tables.S",
  ];

  if let Some((hash, hash_path)) =
    hash_changed(asm_files, &out_dir, &dest_path)
  {
    cc::Build::new()
      .files(asm_files)
      .include(".")
      .include(&out_dir)
      .compile("rav1e-aarch64");

    std::fs::write(hash_path, &hash[..]).unwrap();
  } else {
    println!("cargo:rustc-link-search={}", out_dir);
    println!("cargo:rustc-link-lib=static=rav1e-aarch64");
  }
  rerun_dir("src/arm");
}

fn rustc_version_check() {
  // This should match the version in .travis.yml
  const REQUIRED_VERSION: &str = "1.36.0";
  if version().unwrap() < Version::parse(REQUIRED_VERSION).unwrap() {
    eprintln!("rav1e requires rustc >= {}.", REQUIRED_VERSION);
    exit(1);
  }
}

#[cfg(feature = "asm")]
fn is_nasm_new_enough(
  min_version: Option<(u8, u8, u8)>, nasm_path: &Path,
) -> Result<(), String> {
  match get_output(std::process::Command::new(nasm_path).arg("-v")) {
    Ok(version) => {
      if version.contains("NASM version 0.") {
        Err(version)
      } else if let Some((major, minor, micro)) = min_version {
        let ver = parse_nasm_version(&version)?;
        eprintln!("{:?} {:?} {:?}", min_version, version, ver);
        if major > ver.0
          || (major == ver.0 && minor > ver.1)
          || (major == ver.0 && minor == ver.1 && micro > ver.2)
        {
          Err(version)
        } else {
          Ok(())
        }
      } else {
        Ok(())
      }
    }
    Err(err) => Err(err),
  }
}

#[cfg(feature = "asm")]
fn parse_nasm_version(version_string: &str) -> Result<(u8, u8, u8), String> {
  // Rust regex lib doesn't support empty expressions in alterations,
  // so workaround the other way
  let regex1 =
    regex::Regex::new(r"(?:NASM version )?(\d+)\.(\d+)\.(\d+)").unwrap();
  if let Some(captures) = regex1.captures(version_string) {
    Ok((
      captures[1].parse().expect("Invalid version component"),
      captures[2].parse().expect("Invalid version component"),
      captures[3].parse().expect("Invalid version component"),
    ))
  } else {
    let regex2 = regex::Regex::new(r"(?:NASM version )?(\d+)\.(\d+)").unwrap();
    let captures = regex2
      .captures(version_string)
      .ok_or_else(|| "Unable to parse NASM version string".to_string())?;
    Ok((
      captures[1].parse().expect("Invalid version component"),
      captures[2].parse().expect("Invalid version component"),
      0,
    ))
  }
}

#[test]
fn test_parse_nasm_version() {
  let ver_str = "NASM version 2.14.02 compiled on Jan 22 2019";
  assert_eq!((2, 14, 2), parse_nasm_version(ver_str));
  let ver_str = "NASM version 2.14 compiled on Jan 22 2019";
  assert_eq!((2, 14, 0), parse_nasm_version(ver_str));
}

#[cfg(feature = "asm")]
fn nasm_version_check() -> std::path::PathBuf {
  let nasm_path = std::path::PathBuf::from("nasm");
  match is_nasm_new_enough(Some((2, 14, 0)), &nasm_path) {
    Ok(_) => nasm_path,
    Err(version) => {
      panic!("This version of NASM is too old: {}", version);
    }
  }
}

#[cfg(feature = "asm")]
fn get_output(cmd: &mut std::process::Command) -> Result<String, String> {
  let out = cmd.output().map_err(|e| e.to_string())?;
  if out.status.success() {
    Ok(String::from_utf8_lossy(&out.stdout).to_string())
  } else {
    Err(String::from_utf8_lossy(&out.stderr).to_string())
  }
}

#[allow(unused_variables)]
fn main() {
  rustc_version_check();

  let arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
  let os = env::var("CARGO_CFG_TARGET_OS").unwrap();
  // let env = env::var("CARGO_CFG_TARGET_ENV").unwrap();

  #[cfg(feature = "asm")]
  {
    if arch == "x86_64" {
      println!("cargo:rustc-cfg={}", "nasm_x86_64");
      nasm_version_check();
      build_nasm_files()
    }
    if arch == "aarch64" {
      println!("cargo:rustc-cfg={}", "asm_neon");
      build_asm_files()
    }
  }

  if os == "windows" && cfg!(feature = "decode_test") {
    panic!("Unsupported feature on this platform!");
  }

  vergen::generate_cargo_keys(vergen::ConstantsFlags::all())
    .expect("Unable to generate the cargo keys!");

  println!("cargo:rustc-env=PROFILE={}", env::var("PROFILE").unwrap());
}
<commit_msg>Sync up build.rs with the CI<commit_after>// Copyright (c) 2017-2020, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

#![allow(clippy::print_literal)]
#![allow(clippy::unused_io_amount)]

use rustc_version::{version, Version};
#[allow(unused_imports)]
use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::exit;

#[allow(dead_code)]
fn rerun_dir<P: AsRef<Path>>(dir: P) {
  for entry in fs::read_dir(dir).unwrap() {
    let entry = entry.unwrap();
    let path = entry.path();
    println!("cargo:rerun-if-changed={}", path.to_string_lossy());

    if path.is_dir() {
      rerun_dir(path);
    }
  }
}

#[allow(dead_code)]
fn hash_changed(
  files: &[&str], out_dir: &str, config: &Path,
) -> Option<([u8; 8], PathBuf)> {
  use std::collections::hash_map::DefaultHasher;
  use std::hash::Hasher;
  use std::io::Read;

  let mut hasher = DefaultHasher::new();

  let paths = files.iter().map(Path::new).chain(std::iter::once(config));

  for path in paths {
    if let Ok(mut f) = std::fs::File::open(path) {
      let mut buf = Vec::new();
      f.read_to_end(&mut buf).unwrap();

      hasher.write(&buf);
    } else {
      panic!("Cannot open {}", path.display());
    }
  }

  let hash = hasher.finish().to_be_bytes();

  let hash_path = Path::new(&out_dir).join("asm.hash");

  if let Ok(old_hash) = std::fs::read(&hash_path) {
    if old_hash == hash {
      return None;
    }
  }

  Some((hash, hash_path))
}

#[cfg(feature = "asm")]
fn build_nasm_files() {
  use std::fs::File;
  use std::io::Write;
  let out_dir = env::var("OUT_DIR").unwrap();

  let dest_path = Path::new(&out_dir).join("config.asm");
  let mut config_file = File::create(&dest_path).unwrap();
  config_file.write(b"	%define private_prefix rav1e\n").unwrap();
  config_file.write(b"	%define ARCH_X86_32 0\n").unwrap();
  config_file.write(b" %define ARCH_X86_64 1\n").unwrap();
  config_file.write(b"	%define PIC 1\n").unwrap();
  config_file.write(b" %define STACK_ALIGNMENT 16\n").unwrap();
  config_file.write(b" %define HAVE_AVX512ICL 1\n").unwrap();
  if env::var("CARGO_CFG_TARGET_OS").unwrap() == "macos" {
    config_file.write(b" %define PREFIX 1\n").unwrap();
  }

  let asm_files = &[
    "src/x86/ipred.asm",
    "src/x86/ipred_ssse3.asm",
    "src/x86/itx.asm",
    "src/x86/itx_ssse3.asm",
    "src/x86/mc.asm",
    "src/x86/mc_ssse3.asm",
    "src/x86/me.asm",
    "src/x86/sad_sse2.asm",
    "src/x86/sad_avx.asm",
    "src/x86/satd.asm",
    "src/x86/sse.asm",
    "src/x86/cdef.asm",
    "src/x86/tables.asm",
  ];

  if let Some((hash, hash_path)) =
    hash_changed(asm_files, &out_dir, &dest_path)
  {
    let mut config_include_arg = String::from("-I");
    config_include_arg.push_str(&out_dir);
    config_include_arg.push('/');
    nasm_rs::compile_library_args(
      "rav1easm",
      asm_files,
      &[&config_include_arg, "-Isrc/"],
    )
    .expect(
      "NASM build failed. Make sure you have nasm installed. https://nasm.us",
    );
    std::fs::write(hash_path, &hash[..]).unwrap();
  } else {
    println!("cargo:rustc-link-search={}", out_dir);
  }
  println!("cargo:rustc-link-lib=static=rav1easm");
  rerun_dir("src/x86");
  rerun_dir("src/ext/x86");
}

#[cfg(feature = "asm")]
fn build_asm_files() {
  use std::fs::File;
  use std::io::Write;
  let out_dir = env::var("OUT_DIR").unwrap();

  let dest_path = Path::new(&out_dir).join("config.h");
  let mut config_file = File::create(&dest_path).unwrap();
  config_file.write(b" #define PRIVATE_PREFIX rav1e_\n").unwrap();
  config_file.write(b" #define ARCH_AARCH64 1\n").unwrap();
  config_file.write(b" #define ARCH_ARM 0\n").unwrap();
  config_file.write(b" #define CONFIG_LOG 1 \n").unwrap();
  config_file.write(b" #define HAVE_ASM 1\n").unwrap();
  config_file.sync_all().unwrap();

  let asm_files = &[
    "src/arm/64/cdef.S",
    "src/arm/64/cdef16.S",
    "src/arm/64/mc.S",
    "src/arm/64/mc16.S",
    "src/arm/64/itx.S",
    "src/arm/64/itx16.S",
    "src/arm/64/ipred.S",
    "src/arm/64/ipred16.S",
    "src/arm/64/sad.S",
    "src/arm/tables.S",
  ];

  if let Some((hash, hash_path)) =
    hash_changed(asm_files, &out_dir, &dest_path)
  {
    cc::Build::new()
      .files(asm_files)
      .include(".")
      .include(&out_dir)
      .compile("rav1e-aarch64");

    std::fs::write(hash_path, &hash[..]).unwrap();
  } else {
    println!("cargo:rustc-link-search={}", out_dir);
    println!("cargo:rustc-link-lib=static=rav1e-aarch64");
  }
  rerun_dir("src/arm");
}

fn rustc_version_check() {
  // This should match the version in the CI
  const REQUIRED_VERSION: &str = "1.43.1";
  if version().unwrap() < Version::parse(REQUIRED_VERSION).unwrap() {
    eprintln!("rav1e requires rustc >= {}.", REQUIRED_VERSION);
    exit(1);
  }
}

#[cfg(feature = "asm")]
fn is_nasm_new_enough(
  min_version: Option<(u8, u8, u8)>, nasm_path: &Path,
) -> Result<(), String> {
  match get_output(std::process::Command::new(nasm_path).arg("-v")) {
    Ok(version) => {
      if version.contains("NASM version 0.") {
        Err(version)
      } else if let Some((major, minor, micro)) = min_version {
        let ver = parse_nasm_version(&version)?;
        eprintln!("{:?} {:?} {:?}", min_version, version, ver);
        if major > ver.0
          || (major == ver.0 && minor > ver.1)
          || (major == ver.0 && minor == ver.1 && micro > ver.2)
        {
          Err(version)
        } else {
          Ok(())
        }
      } else {
        Ok(())
      }
    }
    Err(err) => Err(err),
  }
}

#[cfg(feature = "asm")]
fn parse_nasm_version(version_string: &str) -> Result<(u8, u8, u8), String> {
  // Rust regex lib doesn't support empty expressions in alterations,
  // so workaround the other way
  let regex1 =
    regex::Regex::new(r"(?:NASM version )?(\d+)\.(\d+)\.(\d+)").unwrap();
  if let Some(captures) = regex1.captures(version_string) {
    Ok((
      captures[1].parse().expect("Invalid version component"),
      captures[2].parse().expect("Invalid version component"),
      captures[3].parse().expect("Invalid version component"),
    ))
  } else {
    let regex2 = regex::Regex::new(r"(?:NASM version )?(\d+)\.(\d+)").unwrap();
    let captures = regex2
      .captures(version_string)
      .ok_or_else(|| "Unable to parse NASM version string".to_string())?;
    Ok((
      captures[1].parse().expect("Invalid version component"),
      captures[2].parse().expect("Invalid version component"),
      0,
    ))
  }
}

#[test]
fn test_parse_nasm_version() {
  let ver_str = "NASM version 2.14.02 compiled on Jan 22 2019";
  assert_eq!((2, 14, 2), parse_nasm_version(ver_str));
  let ver_str = "NASM version 2.14 compiled on Jan 22 2019";
  assert_eq!((2, 14, 0), parse_nasm_version(ver_str));
}

#[cfg(feature = "asm")]
fn nasm_version_check() -> std::path::PathBuf {
  let nasm_path = std::path::PathBuf::from("nasm");
  match is_nasm_new_enough(Some((2, 14, 0)), &nasm_path) {
    Ok(_) => nasm_path,
    Err(version) => {
      panic!("This version of NASM is too old: {}", version);
    }
  }
}

#[cfg(feature = "asm")]
fn get_output(cmd: &mut std::process::Command) -> Result<String, String> {
  let out = cmd.output().map_err(|e| e.to_string())?;
  if out.status.success() {
    Ok(String::from_utf8_lossy(&out.stdout).to_string())
  } else {
    Err(String::from_utf8_lossy(&out.stderr).to_string())
  }
}

#[allow(unused_variables)]
fn main() {
  rustc_version_check();

  let arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
  let os = env::var("CARGO_CFG_TARGET_OS").unwrap();
  // let env = env::var("CARGO_CFG_TARGET_ENV").unwrap();

  #[cfg(feature = "asm")]
  {
    if arch == "x86_64" {
      println!("cargo:rustc-cfg={}", "nasm_x86_64");
      nasm_version_check();
      build_nasm_files()
    }
    if arch == "aarch64" {
      println!("cargo:rustc-cfg={}", "asm_neon");
      build_asm_files()
    }
  }

  if os == "windows" && cfg!(feature = "decode_test") {
    panic!("Unsupported feature on this platform!");
  }

  vergen::generate_cargo_keys(vergen::ConstantsFlags::all())
    .expect("Unable to generate the cargo keys!");

  println!("cargo:rustc-env=PROFILE={}", env::var("PROFILE").unwrap());
}
<|endoftext|>


<commit_before>// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate openssl;

use openssl::asn1;
use openssl::ec;
use openssl::nid::Nid;
use openssl::pkey::PKey;
use openssl::x509;
use std::env;
use std::fs::File;
use std::io::Write;
use std::path::Path;

fn main() {
    println!("cargo:rerun-if-changed=crypto_data/opensk.key");
    println!("cargo:rerun-if-changed=crypto_data/opensk_cert.pem");

    let out_dir = env::var_os("OUT_DIR").unwrap();
    let priv_key_bin_path = Path::new(&out_dir).join("opensk_pkey.bin");
    let cert_bin_path = Path::new(&out_dir).join("opensk_cert.bin");
    let aaguid_bin_path = Path::new(&out_dir).join("opensk_aaguid.bin");

    // Load the OpenSSL PEM ECC key
    let ecc_data = include_bytes!("crypto_data/opensk.key");
    let pkey = ec::EcKey::private_key_from_pem(ecc_data)
        .ok()
        .expect("Failed to load OpenSK private key file");

    // Check key validity
    pkey.check_key().unwrap();
    assert_eq!(pkey.group().curve_name(), Some(Nid::X9_62_PRIME256V1));

    let mut priv_key = pkey.private_key().to_vec();
    if priv_key.len() == 33 && priv_key[0] == 0 {
        priv_key.remove(0);
    }
    assert_eq!(priv_key.len(), 32);

    // Create the raw private key out of the OpenSSL data
    let mut priv_key_bin_file = File::create(&priv_key_bin_path).unwrap();
    priv_key_bin_file.write_all(&priv_key).unwrap();

    // Convert the PEM certificate to DER and extract the serial for AAGUID
    let input_pem_cert = include_bytes!("crypto_data/opensk_cert.pem");
    let cert = x509::X509::from_pem(input_pem_cert)
        .ok()
        .expect("Failed to load OpenSK certificate");

    // Do some sanity check on the certificate
    assert!(cert
        .public_key()
        .unwrap()
        .public_eq(&PKey::from_ec_key(pkey).unwrap()));
    let now = asn1::Asn1Time::days_from_now(0).unwrap();
    assert!(cert.not_after() > now);
    assert!(cert.not_before() <= now);

    let mut cert_bin_file = File::create(&cert_bin_path).unwrap();
    cert_bin_file.write_all(&cert.to_der().unwrap()).unwrap();

    let mut aaguid_bin_file = File::create(&aaguid_bin_path).unwrap();
    let mut serial = cert.serial_number().to_bn().unwrap().to_vec();
    serial.resize(16, 0);
    aaguid_bin_file.write_all(&serial).unwrap();
}
<commit_msg>Better handling of OpenSSL generated keys.<commit_after>// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate openssl;

use openssl::asn1;
use openssl::ec;
use openssl::nid::Nid;
use openssl::pkey::PKey;
use openssl::x509;
use std::env;
use std::fs::File;
use std::io::Write;
use std::path::Path;

fn main() {
    println!("cargo:rerun-if-changed=crypto_data/opensk.key");
    println!("cargo:rerun-if-changed=crypto_data/opensk_cert.pem");

    let out_dir = env::var_os("OUT_DIR").unwrap();
    let priv_key_bin_path = Path::new(&out_dir).join("opensk_pkey.bin");
    let cert_bin_path = Path::new(&out_dir).join("opensk_cert.bin");
    let aaguid_bin_path = Path::new(&out_dir).join("opensk_aaguid.bin");

    // Load the OpenSSL PEM ECC key
    let ecc_data = include_bytes!("crypto_data/opensk.key");
    let pkey = ec::EcKey::private_key_from_pem(ecc_data)
        .ok()
        .expect("Failed to load OpenSK private key file");

    // Check key validity
    pkey.check_key().unwrap();
    assert_eq!(pkey.group().curve_name(), Some(Nid::X9_62_PRIME256V1));

    // Private keys generated by OpenSSL have variable size but we only handle
    // constant size. Serialization is done in big endian so if the size is less
    // than 32 bytes, we need to prepend with null bytes.
    // If the size is 33 bytes, this means the serialized BigInt is negative.
    // Any other size is invalid.
    let priv_key_hex = pkey.private_key().to_hex_str().unwrap();
    let priv_key_vec = pkey.private_key().to_vec();
    let key_len = priv_key_vec.len();

    assert!(
        key_len >= 30,
        "Invalid private key (too small): {} ({:#?})",
        priv_key_hex,
        priv_key_vec,
    );
    assert!(
        key_len <= 33,
        "Invalid private key (too big): {} ({:#?})",
        priv_key_hex,
        priv_key_vec,
    );

    // Copy OpenSSL generated key to our vec, starting from the end
    let mut output_vec = [0u8; 32];
    let min_key_len = std::cmp::min(key_len, 32);
    output_vec[32usize.saturating_sub(min_key_len)..]
        .copy_from_slice(&priv_key_vec[key_len.saturating_sub(min_key_len)..]);

    // Create the raw private key out of the OpenSSL data
    let mut priv_key_bin_file = File::create(&priv_key_bin_path).unwrap();
    priv_key_bin_file.write_all(&output_vec).unwrap();

    // Convert the PEM certificate to DER and extract the serial for AAGUID
    let input_pem_cert = include_bytes!("crypto_data/opensk_cert.pem");
    let cert = x509::X509::from_pem(input_pem_cert)
        .ok()
        .expect("Failed to load OpenSK certificate");

    // Do some sanity check on the certificate
    assert!(cert
        .public_key()
        .unwrap()
        .public_eq(&PKey::from_ec_key(pkey).unwrap()));
    let now = asn1::Asn1Time::days_from_now(0).unwrap();
    assert!(cert.not_after() > now);
    assert!(cert.not_before() <= now);

    let mut cert_bin_file = File::create(&cert_bin_path).unwrap();
    cert_bin_file.write_all(&cert.to_der().unwrap()).unwrap();

    let mut aaguid_bin_file = File::create(&aaguid_bin_path).unwrap();
    let mut serial = cert.serial_number().to_bn().unwrap().to_vec();
    serial.resize(16, 0);
    aaguid_bin_file.write_all(&serial).unwrap();
}
<|endoftext|>


<commit_before>use rover;
use coords::Position2D;

#[test]
fn should_create_new_rover(){
    let r = rover::new();
    assert_eq!(r.position, Position2D{x: 0, y: 0})
}

#[test]
fn should_move_north(){
    let mut r = rover::new();
    r.move(rover::YDelta(1));
    assert_eq!(r.position, Position2D{x: 0, y: 1})
}

#[test]
fn should_move_north_twice(){
    let mut r = rover::new();
    r.move(rover::YDelta(2));
    assert_eq!(r.position, Position2D{x: 0, y: 2})
}

#[test]
fn should_move_east(){
    let mut r = rover::new();
    r.move(rover::XDelta(1));
    assert_eq!(r.position, Position2D{x: 1, y: 0})
}

#[test]
fn should_move_east_twice(){
    let mut r = rover::new();
    r.move(rover::XDelta(2));
    assert_eq!(r.position, Position2D{x: 2, y: 0})
}

#[test]
fn should_move_south(){
    let mut r = rover::new();
    r.move(rover::YDelta(-1));
    assert_eq!(r.position, Position2D{x: 0, y: -1})
}

#[test]
fn should_move_south_twice(){
    let mut r = rover::new();
    r.move(rover::YDelta(-2));
    assert_eq!(r.position, Position2D{x: 0, y: -2})
}

#[test]
fn should_move_west(){
    let mut r = rover::new();
    r.move(rover::XDelta(-1));
    assert_eq!(r.position, Position2D{x: -1, y: 0})
}

#[test]
fn should_move_west_twice(){
    let mut r = rover::new();
    r.move(rover::XDelta(-2));
    assert_eq!(r.position, Position2D{x: -2, y: 0})
}

#[test]
fn should_move_by_vector(){
    let mut r = rover::new();
    r.move(rover::Vector(2, 3));
    assert_eq!(r.position, Position2D{x: 2, y: 3})
}

#[test]
fn should_advance_north(){
    let mut r = rover::new();
    r.advance();
    assert_eq!(r.position, Position2D{x: 0, y: 1})
}

#[test]
fn should_advance_east(){
    let mut r = rover::new();
    r.facing = rover::East;
    r.advance();
    assert_eq!(r.position, Position2D{x: 1, y: 0})
}

#[test]
fn should_advance_south(){
    let mut r = rover::new();
    r.facing = rover::South;
    r.advance();
    assert_eq!(r.position, Position2D{x: 0, y: -1})
}

#[test]
fn should_advance_west(){
    let mut r = rover::new();
    r.facing = rover::West;
    r.advance();
    assert_eq!(r.position, Position2D{x: -1, y: 0})
}

#[test]
fn should_not_overflow_default_world_while_moving_north(){
    let mut r = rover::new();
    r.move(rover::XDelta(150));

    assert_eq!(r.position, Position2D{x: 49, y: 0})
}

#[test]
fn should_not_overflow_default_world_while_moving_east(){
    let mut r = rover::new();
    r.move(rover::YDelta(150));

    assert_eq!(r.position, Position2D{x: 0, y: 49})
}

#[test]
fn should_not_overflow_both_coordinates(){
    let mut r = rover::new();
    r.move(rover::Vector(1338, 143));

    assert_eq!(r.position, Position2D{x: 37, y: 42})
}

#[test]
fn should_not_overflow_while_advancing(){
    let mut r = rover::new();
    r.move(rover::YDelta(100));
    assert_eq!(r.position, Position2D{x: 0, y: 100})

    r.advance();

    assert_eq!(r.position, Position2D{x: 0, y: 0})
}

#[test]
fn should_abort_transaction_when_colliding(){
    let mut r = rover::new();
    r.world.insert("moon monster", Position2D{x: 5, y: 5});
    r.move(rover::Vector(5, 5));
    assert_eq!(r.position, Position2D{x: 0, y: 0})
}

#[test]
fn should_abort_last_transaction_when_colliding_in_single_steps(){
    let mut r = rover::new();
    r.world.insert("moon monster", Position2D{x: 5, y: 5});
    r.move(rover::Vector(5, 4));
    r.advance();

    assert_eq!(r.position, Position2D{x: 5, y: 4})

}
<commit_msg>ported some tests to use the shiny framework<commit_after>use rover;
use coords::Position2D;

describe!(
    it "should create new rover" {
        let r = rover::new();
        assert_eq!(r.position, Position2D{x: 0, y: 0})
    }

    it "should move north" {
        let mut r = rover::new();
        r.move(rover::YDelta(1));
        assert_eq!(r.position, Position2D{x: 0, y: 1})
    }

    it "should move north twice" {
        let mut r = rover::new();
        r.move(rover::YDelta(2));
        assert_eq!(r.position, Position2D{x: 0, y: 2})
    }

    it "should move east" {
        let mut r = rover::new();
        r.move(rover::XDelta(1));
        assert_eq!(r.position, Position2D{x: 1, y: 0})
    }

    it "should move east twice" {
        let mut r = rover::new();
        r.move(rover::XDelta(2));
        assert_eq!(r.position, Position2D{x: 2, y: 0})
    }

    it "should move south" {
        let mut r = rover::new();
        r.move(rover::YDelta(-1));
        assert_eq!(r.position, Position2D{x: 0, y: -1})
    }

    it "should move south twice" {
        let mut r = rover::new();
        r.move(rover::YDelta(-2));
        assert_eq!(r.position, Position2D{x: 0, y: -2})
    }

    it "should move west" {
        let mut r = rover::new();
        r.move(rover::XDelta(-1));
        assert_eq!(r.position, Position2D{x: -1, y: 0})
    }

    it "should move west twice" {
        let mut r = rover::new();
        r.move(rover::XDelta(-2));
        assert_eq!(r.position, Position2D{x: -2, y: 0})
    }
  )

#[test]
fn should_move_by_vector(){
    let mut r = rover::new();
    r.move(rover::Vector(2, 3));
    assert_eq!(r.position, Position2D{x: 2, y: 3})
}

#[test]
fn should_advance_north(){
    let mut r = rover::new();
    r.advance();
    assert_eq!(r.position, Position2D{x: 0, y: 1})
}

#[test]
fn should_advance_east(){
    let mut r = rover::new();
    r.facing = rover::East;
    r.advance();
    assert_eq!(r.position, Position2D{x: 1, y: 0})
}

#[test]
fn should_advance_south(){
    let mut r = rover::new();
    r.facing = rover::South;
    r.advance();
    assert_eq!(r.position, Position2D{x: 0, y: -1})
}

#[test]
fn should_advance_west(){
    let mut r = rover::new();
    r.facing = rover::West;
    r.advance();
    assert_eq!(r.position, Position2D{x: -1, y: 0})
}

#[test]
fn should_not_overflow_default_world_while_moving_north(){
    let mut r = rover::new();
    r.move(rover::XDelta(150));

    assert_eq!(r.position, Position2D{x: 49, y: 0})
}

#[test]
fn should_not_overflow_default_world_while_moving_east(){
    let mut r = rover::new();
    r.move(rover::YDelta(150));

    assert_eq!(r.position, Position2D{x: 0, y: 49})
}

#[test]
fn should_not_overflow_both_coordinates(){
    let mut r = rover::new();
    r.move(rover::Vector(1338, 143));

    assert_eq!(r.position, Position2D{x: 37, y: 42})
}

#[test]
fn should_not_overflow_while_advancing(){
    let mut r = rover::new();
    r.move(rover::YDelta(100));
    assert_eq!(r.position, Position2D{x: 0, y: 100})

    r.advance();

    assert_eq!(r.position, Position2D{x: 0, y: 0})
}

#[test]
fn should_abort_transaction_when_colliding(){
    let mut r = rover::new();
    r.world.insert("moon monster", Position2D{x: 5, y: 5});
    r.move(rover::Vector(5, 5));
    assert_eq!(r.position, Position2D{x: 0, y: 0})
}

#[test]
fn should_abort_last_transaction_when_colliding_in_single_steps(){
    let mut r = rover::new();
    r.world.insert("moon monster", Position2D{x: 5, y: 5});
    r.move(rover::Vector(5, 4));
    r.advance();

    assert_eq!(r.position, Position2D{x: 5, y: 4})

}
<|endoftext|>


<commit_before>use std::mem;
use std::ptr;
use std::sync::{Arc, Mutex};
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread;
use std::time::Duration;

use winapi::winsock2::{fd_set, timeval, SOCKET_ERROR, WSADATA};
use ws2_32::{select, WSACleanup, WSAStartup};

use c_ares;

use error::Error;
use eventloop::EventLoopHandle;

// The EventLoop will use select() to check on the status of file descriptors
// that c-ares cares about.
pub struct EventLoop {
    pub ares_channel: Arc<Mutex<c_ares::Channel>>,
    quit: Arc<AtomicBool>,
}

impl EventLoop {
    // Create a new event loop.
    pub fn new(options: c_ares::Options) -> Result<EventLoop, Error> {
        // Initialize sockets.
        unsafe {
            let mut wsadata: WSADATA = mem::uninitialized();
            WSAStartup(0x101, &mut wsadata);
        }

        // Create the c-ares channel.
        let ares_channel = c_ares::Channel::with_options(options)?;
        let locked_channel = Arc::new(Mutex::new(ares_channel));

        // Create and return the event loop.
        let event_loop = EventLoop {
            ares_channel: locked_channel,
            quit: Arc::new(AtomicBool::new(false)),
        };
        Ok(event_loop)
    }

    // Run the event loop.
    pub fn run(self) -> EventLoopHandle {
        let quit = Arc::clone(&self.quit);
        let join_handle = thread::spawn(|| self.event_loop_thread());
        EventLoopHandle::new(join_handle, quit)
    }

    // Event loop thread - waits for events, and handles them.
    fn event_loop_thread(self) {
        let mut read_fds: fd_set = unsafe { mem::uninitialized() };
        let mut write_fds: fd_set = unsafe { mem::uninitialized() };

        // Loop round, asking c-ares what it cares about and doing as asked.
        loop {
            read_fds.fd_count = 0;
            write_fds.fd_count = 0;
            let count = self.ares_channel
                .lock()
                .unwrap()
                .fds(&mut read_fds, &mut write_fds);

            if count == 0 {
                thread::sleep(Duration::from_millis(100));
            } else {
                let timeout = timeval {
                    tv_sec: 0,
                    tv_usec: 100000,
                };
                let results = unsafe {
                    select(0, &mut read_fds, &mut write_fds, ptr::null_mut(), &timeout)
                };

                // Process whatever happened.
                match results {
                    SOCKET_ERROR => panic!("Socket error"),
                    _ => self.ares_channel
                        .lock()
                        .unwrap()
                        .process(&mut read_fds, &mut write_fds),
                }
            }
            if self.quit.load(Ordering::Relaxed) {
                break;
            }
        }
    }
}

impl Drop for EventLoop {
    fn drop(&mut self) {
        unsafe {
            WSACleanup();
        }
    }
}
<commit_msg>rustfmt, make up your mind<commit_after>use std::mem;
use std::ptr;
use std::sync::{Arc, Mutex};
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread;
use std::time::Duration;

use winapi::winsock2::{fd_set, timeval, SOCKET_ERROR, WSADATA};
use ws2_32::{select, WSACleanup, WSAStartup};

use c_ares;

use error::Error;
use eventloop::EventLoopHandle;

// The EventLoop will use select() to check on the status of file descriptors
// that c-ares cares about.
pub struct EventLoop {
    pub ares_channel: Arc<Mutex<c_ares::Channel>>,
    quit: Arc<AtomicBool>,
}

impl EventLoop {
    // Create a new event loop.
    pub fn new(options: c_ares::Options) -> Result<EventLoop, Error> {
        // Initialize sockets.
        unsafe {
            let mut wsadata: WSADATA = mem::uninitialized();
            WSAStartup(0x101, &mut wsadata);
        }

        // Create the c-ares channel.
        let ares_channel = c_ares::Channel::with_options(options)?;
        let locked_channel = Arc::new(Mutex::new(ares_channel));

        // Create and return the event loop.
        let event_loop = EventLoop {
            ares_channel: locked_channel,
            quit: Arc::new(AtomicBool::new(false)),
        };
        Ok(event_loop)
    }

    // Run the event loop.
    pub fn run(self) -> EventLoopHandle {
        let quit = Arc::clone(&self.quit);
        let join_handle = thread::spawn(|| self.event_loop_thread());
        EventLoopHandle::new(join_handle, quit)
    }

    // Event loop thread - waits for events, and handles them.
    fn event_loop_thread(self) {
        let mut read_fds: fd_set = unsafe { mem::uninitialized() };
        let mut write_fds: fd_set = unsafe { mem::uninitialized() };

        // Loop round, asking c-ares what it cares about and doing as asked.
        loop {
            read_fds.fd_count = 0;
            write_fds.fd_count = 0;
            let count = self.ares_channel
                .lock()
                .unwrap()
                .fds(&mut read_fds, &mut write_fds);

            if count == 0 {
                thread::sleep(Duration::from_millis(100));
            } else {
                let timeout = timeval {
                    tv_sec: 0,
                    tv_usec: 100000,
                };
                let results =
                    unsafe { select(0, &mut read_fds, &mut write_fds, ptr::null_mut(), &timeout) };

                // Process whatever happened.
                match results {
                    SOCKET_ERROR => panic!("Socket error"),
                    _ => self.ares_channel
                        .lock()
                        .unwrap()
                        .process(&mut read_fds, &mut write_fds),
                }
            }
            if self.quit.load(Ordering::Relaxed) {
                break;
            }
        }
    }
}

impl Drop for EventLoop {
    fn drop(&mut self) {
        unsafe {
            WSACleanup();
        }
    }
}
<|endoftext|>


<commit_before>use std::fmt::{self, Display, Formatter};

/// A primitive defines the type that a requested value should satisfy.
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub enum Primitive {
    Str,
    StrArray,
    Boolean,
    BooleanArray,
    Integer,
    IntegerArray,
    Float,
    FloatArray,
    HashMap(Box<Primitive>),
    BTreeMap(Box<Primitive>),
    Indexed(String, Box<Primitive>),
}

impl Primitive {
    pub(crate) fn parse(data: &str) -> Option<Primitive> {
        match data {
            "str" => Some(Primitive::Str),
            "[str]" => Some(Primitive::StrArray),
            "bool" => Some(Primitive::Boolean),
            "[bool]" => Some(Primitive::BooleanArray),
            "int" => Some(Primitive::Integer),
            "[int]" => Some(Primitive::IntegerArray),
            "float" => Some(Primitive::Float),
            "[float]" => Some(Primitive::FloatArray),
            _ => {
                let open_bracket = data.find('[')?;
                let close_bracket = data.rfind(']')?;
                let kind = &data[..open_bracket].trim_start();
                let inner = &data[open_bracket + 1..close_bracket];

                if *kind == "hmap" {
                    Some(Primitive::HashMap(Box::new(Primitive::parse(inner)?)))
                } else if *kind == "bmap" {
                    Some(Primitive::BTreeMap(Box::new(Primitive::parse(inner)?)))
                } else {
                    None
                }
            }
        }
    }
}

impl Display for Primitive {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        match *self {
            Primitive::Str => write!(f, "str"),
            Primitive::StrArray => write!(f, "[str]"),
            Primitive::Boolean => write!(f, "bool"),
            Primitive::BooleanArray => write!(f, "[bool]"),
            Primitive::Float => write!(f, "float"),
            Primitive::FloatArray => write!(f, "[float]"),
            Primitive::Integer => write!(f, "int"),
            Primitive::IntegerArray => write!(f, "[int]"),
            Primitive::HashMap(ref kind) => match **kind {
                Primitive::Str => write!(f, "hmap[]"),
                ref kind => write!(f, "hmap[{}]", kind),
            },
            Primitive::BTreeMap(ref kind) => match **kind {
                Primitive::Str => write!(f, "bmap[]"),
                ref kind => write!(f, "bmap[{}]", kind),
            },
            Primitive::Indexed(_, ref kind) => write!(f, "{}", kind),
        }
    }
}
<commit_msg>Remove unneeded trim. Terminator handles this<commit_after>use std::fmt::{self, Display, Formatter};

/// A primitive defines the type that a requested value should satisfy.
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub enum Primitive {
    Str,
    StrArray,
    Boolean,
    BooleanArray,
    Integer,
    IntegerArray,
    Float,
    FloatArray,
    HashMap(Box<Primitive>),
    BTreeMap(Box<Primitive>),
    Indexed(String, Box<Primitive>),
}

impl Primitive {
    pub(crate) fn parse(data: &str) -> Option<Primitive> {
        match data {
            "str" => Some(Primitive::Str),
            "[str]" => Some(Primitive::StrArray),
            "bool" => Some(Primitive::Boolean),
            "[bool]" => Some(Primitive::BooleanArray),
            "int" => Some(Primitive::Integer),
            "[int]" => Some(Primitive::IntegerArray),
            "float" => Some(Primitive::Float),
            "[float]" => Some(Primitive::FloatArray),
            _ => {
                let open_bracket = data.find('[')?;
                let close_bracket = data.rfind(']')?;
                let kind = &data[..open_bracket];
                let inner = &data[open_bracket + 1..close_bracket];

                if kind == "hmap" {
                    Some(Primitive::HashMap(Box::new(Primitive::parse(inner)?)))
                } else if kind == "bmap" {
                    Some(Primitive::BTreeMap(Box::new(Primitive::parse(inner)?)))
                } else {
                    None
                }
            }
        }
    }
}

impl Display for Primitive {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        match *self {
            Primitive::Str => write!(f, "str"),
            Primitive::StrArray => write!(f, "[str]"),
            Primitive::Boolean => write!(f, "bool"),
            Primitive::BooleanArray => write!(f, "[bool]"),
            Primitive::Float => write!(f, "float"),
            Primitive::FloatArray => write!(f, "[float]"),
            Primitive::Integer => write!(f, "int"),
            Primitive::IntegerArray => write!(f, "[int]"),
            Primitive::HashMap(ref kind) => match **kind {
                Primitive::Str => write!(f, "hmap[]"),
                ref kind => write!(f, "hmap[{}]", kind),
            },
            Primitive::BTreeMap(ref kind) => match **kind {
                Primitive::Str => write!(f, "bmap[]"),
                ref kind => write!(f, "bmap[{}]", kind),
            },
            Primitive::Indexed(_, ref kind) => write!(f, "{}", kind),
        }
    }
}
<|endoftext|>