<commit_before>/// The compiler code necessary to implement the #[deriving_eq] and
/// #[deriving_ord] extensions.

use ast::{and, bind_by_value, binop, blk, default_blk, deref, enum_def, expr};
use ast::{expr_, expr_addr_of, expr_binary, expr_call, expr_field, expr_lit};
use ast::{expr_match, expr_path, expr_unary, ident, infer, item, item_};
use ast::{item_class, item_enum, item_impl, lit_bool, m_imm, meta_item};
use ast::{method, named_field, or, pat, pat_ident, pat_wild, path, public};
use ast::{pure_fn, re_anon, return_val, struct_def, sty_region, ty_path};
use ast::{ty_rptr, unnamed_field};
use base::ext_ctxt;
use codemap::span;
use parse::token::special_idents::clownshoes_extensions;

enum Junction {
    Conjunction,
    Disjunction,
}

impl Junction {
    fn to_binop(self) -> binop {
        match self {
            Conjunction => and,
            Disjunction => or,
        }
    }
}

pub fn expand_deriving_eq(cx: ext_ctxt,
                          span: span,
                          _mitem: meta_item,
                          in_items: ~[@item])
                       -> ~[@item] {
    let result = dvec::DVec();
    for in_items.each |item| {
        result.push(copy *item);
        match item.node {
            item_class(struct_def, _) => {
                result.push(expand_deriving_struct_def(cx,
                                                       span,
                                                       struct_def,
                                                       item.ident));
            }
            item_enum(ref enum_definition, _) => {
                result.push(expand_deriving_enum_def(cx,
                                                     span,
                                                     enum_definition,
                                                     item.ident));
            }
            _ => result.push(copy *item)    // XXX: Don't copy.
        }
    }
    dvec::unwrap(move result)
}

fn create_impl_item(cx: ext_ctxt, span: span, +item: item_) -> @item {
    @{
        ident: clownshoes_extensions,
        attrs: ~[],
        id: cx.next_id(),
        node: move item,
        vis: ast::public,
        span: span,
    }
}

/// Creates a method from the given expression, the signature of which
/// conforms to the `eq` or `ne` method.
fn create_method(cx: ext_ctxt,
                 span: span,
                 method_ident: ident,
                 type_ident: ident,
                 body: @expr)
              -> @method {
    // Create the type of the `other` parameter.
    let arg_path_type = build::mk_raw_path(span, ~[ type_ident ]);
    let arg_path_type = ty_path(arg_path_type, cx.next_id());
    let arg_path_type = @{
        id: cx.next_id(),
        node: move arg_path_type,
        span: span
    };
    let arg_region = @{ id: cx.next_id(), node: re_anon };
    let arg_type = ty_rptr(arg_region, { ty: arg_path_type, mutbl: m_imm });
    let arg_type = @{ id: cx.next_id(), node: move arg_type, span: span };

    // Create the `other` parameter.
    let other_ident = cx.ident_of(~"__other");
    let arg_pat = build::mk_pat_ident(cx, span, other_ident);
    let arg = {
        mode: infer(cx.next_id()),
        ty: arg_type,
        pat: arg_pat,
        id: cx.next_id()
    };

    // Create the type of the return value.
    let bool_ident = cx.ident_of(~"bool");
    let output_type = build::mk_raw_path(span, ~[ bool_ident ]);
    let output_type = ty_path(output_type, cx.next_id());
    let output_type = @{
        id: cx.next_id(),
        node: move output_type,
        span: span
    };

    // Create the function declaration.
    let fn_decl = {
        inputs: ~[ move arg ],
        output: output_type,
        cf: return_val
    };

    // Create the body block.
    let body_block = build::mk_simple_block(cx, span, body);

    // Create the method.
    let self_ty = { node: sty_region(m_imm), span: span };
    return @{
        ident: method_ident,
        attrs: ~[],
        tps: ~[],
        self_ty: self_ty,
        purity: pure_fn,
        decl: move fn_decl,
        body: move body_block,
        id: cx.next_id(),
        span: span,
        self_id: cx.next_id(),
        vis: public
    };
}

fn create_derived_impl(cx: ext_ctxt,
                       span: span,
                       type_ident: ident,
                       eq_method: @method,
                       ne_method: @method)
                    -> @item {
    // Create the reference to the `core::cmp::Eq` trait.
    let core_ident = cx.ident_of(~"core");
    let cmp_ident = cx.ident_of(~"cmp");
    let eq_ident = cx.ident_of(~"Eq");
    let core_cmp_eq_idents = ~[
        move core_ident,
        move cmp_ident,
        move eq_ident
    ];
    let core_cmp_eq_path = {
        span: span,
        global: false,
        idents: move core_cmp_eq_idents,
        rp: None,
        types: ~[]
    };
    let core_cmp_eq_path = @move core_cmp_eq_path;
    let trait_ref = {
        path: core_cmp_eq_path,
        ref_id: cx.next_id(),
        impl_id: cx.next_id(),
    };
    let trait_ref = @move trait_ref;

    // Create the type of `self`.
    let self_type = build::mk_raw_path(span, ~[ type_ident ]);
    let self_type = ty_path(self_type, cx.next_id());
    let self_type = @{ id: cx.next_id(), node: move self_type, span: span };

    // Create the impl item.
    let impl_item = item_impl(~[],
                              Some(trait_ref),
                              self_type,
                              ~[ eq_method, ne_method ]);
    return create_impl_item(cx, span, move impl_item);
}

fn expand_deriving_struct_def(cx: ext_ctxt,
                              span: span,
                              struct_def: &struct_def,
                              type_ident: ident)
                           -> @item {
    // Create the methods.
    let eq_ident = cx.ident_of(~"eq");
    let ne_ident = cx.ident_of(~"ne");
    let eq_method = expand_deriving_struct_method(cx,
                                                  span,
                                                  struct_def,
                                                  eq_ident,
                                                  type_ident,
                                                  Conjunction);
    let ne_method = expand_deriving_struct_method(cx,
                                                  span,
                                                  struct_def,
                                                  ne_ident,
                                                  type_ident,
                                                  Disjunction);

    // Create the implementation.
    return create_derived_impl(cx, span, type_ident, eq_method, ne_method);
}

fn expand_deriving_struct_method(cx: ext_ctxt,
                                 span: span,
                                 struct_def: &struct_def,
                                 method_ident: ident,
                                 type_ident: ident,
                                 junction: Junction)
                              -> @method {
    let self_ident = cx.ident_of(~"self");
    let other_ident = cx.ident_of(~"__other");

    let binop = junction.to_binop();

    // Create the body of the method.
    let mut outer_expr = None;
    for struct_def.fields.each |struct_field| {
        match struct_field.node.kind {
            named_field(ident, _, _) => {
                // Create the accessor for the other field.
                let other_field = build::mk_access(cx,
                                                   span,
                                                   ~[ other_ident ],
                                                   ident);
                let other_field_ref = build::mk_addr_of(cx,
                                                        span,
                                                        other_field);

                // Create the accessor for this field.
                let self_field = build::mk_access(cx,
                                                  span,
                                                  ~[ self_ident ],
                                                  ident);

                // Call the substructure method.
                let self_method = build::mk_access_(cx,
                                                    span,
                                                    self_field,
                                                    method_ident);
                let self_call = build::mk_call_(cx,
                                                span,
                                                self_method,
                                                ~[ other_field_ref ]);

                // Connect to the outer expression if necessary.
                outer_expr = match outer_expr {
                    None => Some(self_call),
                    Some(old_outer_expr) => {
                        let chain_expr = build::mk_binary(cx,
                                                          span,
                                                          binop,
                                                          old_outer_expr,
                                                          self_call);
                        Some(chain_expr)
                    }
                };
            }
            unnamed_field => {
                cx.span_unimpl(span, ~"unnamed fields with `deriving_eq`");
            }
        }
    }

    // Create the method itself.
    let body;
    match outer_expr {
        None => cx.span_unimpl(span, ~"empty structs with `deriving_eq`"),
        Some(outer_expr) => body = outer_expr,
    }

    return create_method(cx, span, method_ident, type_ident, body);
}

fn expand_deriving_enum_def(cx: ext_ctxt,
                            span: span,
                            enum_definition: &enum_def,
                            type_ident: ident)
                         -> @item {
    // Create the methods.
    let eq_ident = cx.ident_of(~"eq");
    let ne_ident = cx.ident_of(~"ne");
    let eq_method = expand_deriving_enum_method(cx,
                                                span,
                                                enum_definition,
                                                eq_ident,
                                                type_ident,
                                                Conjunction);
    let ne_method = expand_deriving_enum_method(cx,
                                                span,
                                                enum_definition,
                                                ne_ident,
                                                type_ident,
                                                Disjunction);

    // Create the implementation.
    return create_derived_impl(cx, span, type_ident, eq_method, ne_method);
}

fn expand_deriving_enum_method(cx: ext_ctxt,
                               span: span,
                               enum_definition: &enum_def,
                               method_ident: ident,
                               type_ident: ident,
                               junction: Junction)
                            -> @method {
    let self_ident = cx.ident_of(~"self");
    let other_ident = cx.ident_of(~"__other");

    let _binop = junction.to_binop();

    let is_eq;
    match junction {
        Conjunction => is_eq = true,
        Disjunction => is_eq = false,
    }

    // Create the arms of the self match in the method body.
    let self_arms = dvec::DVec();
    for enum_definition.variants.each |self_variant| {
        let other_arms = dvec::DVec();
        let self_variant_ident = self_variant.node.name;

        // Create the matching pattern.
        let matching_pat = build::mk_pat_ident(cx, span, self_variant_ident);

        // Create the matching pattern body.
        let matching_body_expr = build::mk_bool(cx, span, is_eq);
        let matching_body_block = build::mk_simple_block(cx,
                                                         span,
                                                         matching_body_expr);

        // Create the matching arm.
        let matching_arm = {
            pats: ~[ matching_pat ],
            guard: None,
            body: move matching_body_block
        };
        other_arms.push(move matching_arm);

        // Create the nonmatching pattern.
        let nonmatching_pat = @{
            id: cx.next_id(),
            node: pat_wild,
            span: span
        };

        // Create the nonmatching pattern body.
        let nonmatching_expr = build::mk_bool(cx, span, !is_eq);
        let nonmatching_body_block = build::mk_simple_block(cx,
                                                            span,
                                                            nonmatching_expr);

        // Create the nonmatching arm.
        let nonmatching_arm = {
            pats: ~[ nonmatching_pat ],
            guard: None,
            body: move nonmatching_body_block
        };
        other_arms.push(move nonmatching_arm);

        // Create the self pattern.
        let self_pat = build::mk_pat_ident(cx, span, self_variant_ident);

        // Create the self pattern body.
        let other_expr = build::mk_path(cx, span, ~[ other_ident ]);
        let other_expr = build::mk_unary(cx, span, deref, other_expr);
        let other_arms = dvec::unwrap(move other_arms);
        let other_match_expr = expr_match(other_expr, move other_arms);
        let other_match_expr = build::mk_expr(cx,
                                              span,
                                              move other_match_expr);
        let other_match_body_block = build::mk_simple_block(cx,
                                                            span,
                                                            other_match_expr);

        // Create the self arm.
        let self_arm = {
            pats: ~[ self_pat ],
            guard: None,
            body: move other_match_body_block
        };
        self_arms.push(move self_arm);
    }

    // Create the method body.
    let self_expr = build::mk_path(cx, span, ~[ self_ident ]);
    let self_expr = build::mk_unary(cx, span, deref, self_expr);
    let self_arms = dvec::unwrap(move self_arms);
    let self_match_expr = expr_match(self_expr, move self_arms);
    let self_match_expr = build::mk_expr(cx, span, move self_match_expr);

    // Create the method.
    return create_method(cx, span, method_ident, type_ident, self_match_expr);
}

<commit_msg>libsyntax: Long line. rs=make-tidy<commit_after>/// The compiler code necessary to implement the #[deriving_eq] and
/// #[deriving_ord] extensions.

use ast::{and, bind_by_value, binop, blk, default_blk, deref, enum_def, expr};
use ast::{expr_, expr_addr_of, expr_binary, expr_call, expr_field, expr_lit};
use ast::{expr_match, expr_path, expr_unary, ident, infer, item, item_};
use ast::{item_class, item_enum, item_impl, lit_bool, m_imm, meta_item};
use ast::{method, named_field, or, pat, pat_ident, pat_wild, path, public};
use ast::{pure_fn, re_anon, return_val, struct_def, sty_region, ty_path};
use ast::{ty_rptr, unnamed_field};
use base::ext_ctxt;
use codemap::span;
use parse::token::special_idents::clownshoes_extensions;

enum Junction {
    Conjunction,
    Disjunction,
}

impl Junction {
    fn to_binop(self) -> binop {
        match self {
            Conjunction => and,
            Disjunction => or,
        }
    }
}

pub fn expand_deriving_eq(cx: ext_ctxt,
                          span: span,
                          _mitem: meta_item,
                          in_items: ~[@item])
                       -> ~[@item] {
    let result = dvec::DVec();
    for in_items.each |item| {
        result.push(copy *item);
        match item.node {
            item_class(struct_def, _) => {
                result.push(expand_deriving_struct_def(cx,
                                                       span,
                                                       struct_def,
                                                       item.ident));
            }
            item_enum(ref enum_definition, _) => {
                result.push(expand_deriving_enum_def(cx,
                                                     span,
                                                     enum_definition,
                                                     item.ident));
            }
            _ => result.push(copy *item)    // XXX: Don't copy.
        }
    }
    dvec::unwrap(move result)
}

fn create_impl_item(cx: ext_ctxt, span: span, +item: item_) -> @item {
    @{
        ident: clownshoes_extensions,
        attrs: ~[],
        id: cx.next_id(),
        node: move item,
        vis: ast::public,
        span: span,
    }
}

/// Creates a method from the given expression, the signature of which
/// conforms to the `eq` or `ne` method.
fn create_method(cx: ext_ctxt,
                 span: span,
                 method_ident: ident,
                 type_ident: ident,
                 body: @expr)
              -> @method {
    // Create the type of the `other` parameter.
    let arg_path_type = build::mk_raw_path(span, ~[ type_ident ]);
    let arg_path_type = ty_path(arg_path_type, cx.next_id());
    let arg_path_type = @{
        id: cx.next_id(),
        node: move arg_path_type,
        span: span
    };
    let arg_region = @{ id: cx.next_id(), node: re_anon };
    let arg_type = ty_rptr(arg_region, { ty: arg_path_type, mutbl: m_imm });
    let arg_type = @{ id: cx.next_id(), node: move arg_type, span: span };

    // Create the `other` parameter.
    let other_ident = cx.ident_of(~"__other");
    let arg_pat = build::mk_pat_ident(cx, span, other_ident);
    let arg = {
        mode: infer(cx.next_id()),
        ty: arg_type,
        pat: arg_pat,
        id: cx.next_id()
    };

    // Create the type of the return value.
    let bool_ident = cx.ident_of(~"bool");
    let output_type = build::mk_raw_path(span, ~[ bool_ident ]);
    let output_type = ty_path(output_type, cx.next_id());
    let output_type = @{
        id: cx.next_id(),
        node: move output_type,
        span: span
    };

    // Create the function declaration.
    let fn_decl = {
        inputs: ~[ move arg ],
        output: output_type,
        cf: return_val
    };

    // Create the body block.
    let body_block = build::mk_simple_block(cx, span, body);

    // Create the method.
    let self_ty = { node: sty_region(m_imm), span: span };
    return @{
        ident: method_ident,
        attrs: ~[],
        tps: ~[],
        self_ty: self_ty,
        purity: pure_fn,
        decl: move fn_decl,
        body: move body_block,
        id: cx.next_id(),
        span: span,
        self_id: cx.next_id(),
        vis: public
    };
}

fn create_derived_impl(cx: ext_ctxt,
                       span: span,
                       type_ident: ident,
                       eq_method: @method,
                       ne_method: @method)
                    -> @item {
    // Create the reference to the `core::cmp::Eq` trait.
    let core_ident = cx.ident_of(~"core");
    let cmp_ident = cx.ident_of(~"cmp");
    let eq_ident = cx.ident_of(~"Eq");
    let core_cmp_eq_idents = ~[
        move core_ident,
        move cmp_ident,
        move eq_ident
    ];
    let core_cmp_eq_path = {
        span: span,
        global: false,
        idents: move core_cmp_eq_idents,
        rp: None,
        types: ~[]
    };
    let core_cmp_eq_path = @move core_cmp_eq_path;
    let trait_ref = {
        path: core_cmp_eq_path,
        ref_id: cx.next_id(),
        impl_id: cx.next_id(),
    };
    let trait_ref = @move trait_ref;

    // Create the type of `self`.
    let self_type = build::mk_raw_path(span, ~[ type_ident ]);
    let self_type = ty_path(self_type, cx.next_id());
    let self_type = @{ id: cx.next_id(), node: move self_type, span: span };

    // Create the impl item.
    let impl_item = item_impl(~[],
                              Some(trait_ref),
                              self_type,
                              ~[ eq_method, ne_method ]);
    return create_impl_item(cx, span, move impl_item);
}

fn expand_deriving_struct_def(cx: ext_ctxt,
                              span: span,
                              struct_def: &struct_def,
                              type_ident: ident)
                           -> @item {
    // Create the methods.
    let eq_ident = cx.ident_of(~"eq");
    let ne_ident = cx.ident_of(~"ne");
    let eq_method = expand_deriving_struct_method(cx,
                                                  span,
                                                  struct_def,
                                                  eq_ident,
                                                  type_ident,
                                                  Conjunction);
    let ne_method = expand_deriving_struct_method(cx,
                                                  span,
                                                  struct_def,
                                                  ne_ident,
                                                  type_ident,
                                                  Disjunction);

    // Create the implementation.
    return create_derived_impl(cx, span, type_ident, eq_method, ne_method);
}

fn expand_deriving_struct_method(cx: ext_ctxt,
                                 span: span,
                                 struct_def: &struct_def,
                                 method_ident: ident,
                                 type_ident: ident,
                                 junction: Junction)
                              -> @method {
    let self_ident = cx.ident_of(~"self");
    let other_ident = cx.ident_of(~"__other");

    let binop = junction.to_binop();

    // Create the body of the method.
    let mut outer_expr = None;
    for struct_def.fields.each |struct_field| {
        match struct_field.node.kind {
            named_field(ident, _, _) => {
                // Create the accessor for the other field.
                let other_field = build::mk_access(cx,
                                                   span,
                                                   ~[ other_ident ],
                                                   ident);
                let other_field_ref = build::mk_addr_of(cx,
                                                        span,
                                                        other_field);

                // Create the accessor for this field.
                let self_field = build::mk_access(cx,
                                                  span,
                                                  ~[ self_ident ],
                                                  ident);

                // Call the substructure method.
                let self_method = build::mk_access_(cx,
                                                    span,
                                                    self_field,
                                                    method_ident);
                let self_call = build::mk_call_(cx,
                                                span,
                                                self_method,
                                                ~[ other_field_ref ]);

                // Connect to the outer expression if necessary.
                outer_expr = match outer_expr {
                    None => Some(self_call),
                    Some(old_outer_expr) => {
                        let chain_expr = build::mk_binary(cx,
                                                          span,
                                                          binop,
                                                          old_outer_expr,
                                                          self_call);
                        Some(chain_expr)
                    }
                };
            }
            unnamed_field => {
                cx.span_unimpl(span, ~"unnamed fields with `deriving_eq`");
            }
        }
    }

    // Create the method itself.
    let body;
    match outer_expr {
        None => cx.span_unimpl(span, ~"empty structs with `deriving_eq`"),
        Some(outer_expr) => body = outer_expr,
    }

    return create_method(cx, span, method_ident, type_ident, body);
}

fn expand_deriving_enum_def(cx: ext_ctxt,
                            span: span,
                            enum_definition: &enum_def,
                            type_ident: ident)
                         -> @item {
    // Create the methods.
    let eq_ident = cx.ident_of(~"eq");
    let ne_ident = cx.ident_of(~"ne");
    let eq_method = expand_deriving_enum_method(cx,
                                                span,
                                                enum_definition,
                                                eq_ident,
                                                type_ident,
                                                Conjunction);
    let ne_method = expand_deriving_enum_method(cx,
                                                span,
                                                enum_definition,
                                                ne_ident,
                                                type_ident,
                                                Disjunction);

    // Create the implementation.
    return create_derived_impl(cx, span, type_ident, eq_method, ne_method);
}

fn expand_deriving_enum_method(cx: ext_ctxt,
                               span: span,
                               enum_definition: &enum_def,
                               method_ident: ident,
                               type_ident: ident,
                               junction: Junction)
                            -> @method {
    let self_ident = cx.ident_of(~"self");
    let other_ident = cx.ident_of(~"__other");

    let _binop = junction.to_binop();

    let is_eq;
    match junction {
        Conjunction => is_eq = true,
        Disjunction => is_eq = false,
    }

    // Create the arms of the self match in the method body.
    let self_arms = dvec::DVec();
    for enum_definition.variants.each |self_variant| {
        let other_arms = dvec::DVec();
        let self_variant_ident = self_variant.node.name;

        // Create the matching pattern.
        let matching_pat = build::mk_pat_ident(cx, span, self_variant_ident);

        // Create the matching pattern body.
        let matching_body_expr = build::mk_bool(cx, span, is_eq);
        let matching_body_block = build::mk_simple_block(cx,
                                                         span,
                                                         matching_body_expr);

        // Create the matching arm.
        let matching_arm = {
            pats: ~[ matching_pat ],
            guard: None,
            body: move matching_body_block
        };
        other_arms.push(move matching_arm);

        // Create the nonmatching pattern.
        let nonmatching_pat = @{
            id: cx.next_id(),
            node: pat_wild,
            span: span
        };

        // Create the nonmatching pattern body.
        let nonmatching_expr = build::mk_bool(cx, span, !is_eq);
        let nonmatching_body_block = build::mk_simple_block(cx,
                                                            span,
                                                            nonmatching_expr);

        // Create the nonmatching arm.
        let nonmatching_arm = {
            pats: ~[ nonmatching_pat ],
            guard: None,
            body: move nonmatching_body_block
        };
        other_arms.push(move nonmatching_arm);

        // Create the self pattern.
        let self_pat = build::mk_pat_ident(cx, span, self_variant_ident);

        // Create the self pattern body.
        let other_expr = build::mk_path(cx, span, ~[ other_ident ]);
        let other_expr = build::mk_unary(cx, span, deref, other_expr);
        let other_arms = dvec::unwrap(move other_arms);
        let other_match_expr = expr_match(other_expr, move other_arms);
        let other_match_expr = build::mk_expr(cx,
                                              span,
                                              move other_match_expr);
        let other_match_body_block = build::mk_simple_block(cx,
                                                            span,
                                                            other_match_expr);

        // Create the self arm.
        let self_arm = {
            pats: ~[ self_pat ],
            guard: None,
            body: move other_match_body_block
        };
        self_arms.push(move self_arm);
    }

    // Create the method body.
    let self_expr = build::mk_path(cx, span, ~[ self_ident ]);
    let self_expr = build::mk_unary(cx, span, deref, self_expr);
    let self_arms = dvec::unwrap(move self_arms);
    let self_match_expr = expr_match(self_expr, move self_arms);
    let self_match_expr = build::mk_expr(cx, span, move self_match_expr);

    // Create the method.
    return create_method(cx, span, method_ident, type_ident, self_match_expr);
}

<|endoftext|>


<commit_before>
pub fn extract_links(s: &String) -> Vec<String> {
    use pulldown_cmark::Parser;
    use pulldown_cmark::Event;
    use pulldown_cmark::Tag;

    Parser::new(&s[..])
        .filter_map(|e| {
            match e {
                Event::Start(t) => Some(t),
                Event::End(t)   => Some(t),
                _               => None
            }
        })
        .filter_map(|tag| {
            match tag {
                Tag::Link(url, text) => Some((url, text)),
                _               => None
            }
        })
        .map(|(url, text)| {
            text.into_owned()
        }).collect::<Vec<String>>()
}

<commit_msg>Rewrite markdown parsing, so we can extract links and quotes (and maybe more)<commit_after>mod markdown {
    use pulldown_cmark::Parser;
    use pulldown_cmark::Event;
    use pulldown_cmark::Tag;

    pub struct MarkdownParser<'a> {
        text: &'a String
    }

    impl<'a> MarkdownParser<'a> {

        pub fn new(s: &'a String) -> MarkdownParser {
            MarkdownParser {
                text: s
            }
        }

        pub fn links(&self) -> Vec<String> {
            Parser::new(&self.text[..])
                .filter_map(|e| {
                    match e {
                        Event::Start(t) => Some(t),
                        Event::End(t)   => Some(t),
                        _               => None
                    }
                })
                .filter_map(|tag| {
                    match tag {
                        Tag::Link(url, text) => Some((url, text)),
                        _               => None
                    }
                })
                .map(|(url, text)| {
                    text.into_owned()
                }).collect::<Vec<String>>()
        }

        pub fn codeblocks(&self) -> Vec<String> {
            Parser::new(&self.text[..])
                .filter_map(|e| {
                    match e {
                        Event::Start(t) => Some(t),
                        Event::End(t)   => Some(t),
                        _               => None
                    }
                })
                .filter_map(|tag| {
                    match tag {
                        Tag::CodeBlock(text)    => Some(text),
                        _                       => None
                    }
                })
                .map(|text| {
                    text.into_owned()
                }).collect::<Vec<String>>()
        }

    }

}
<|endoftext|>


<commit_before>// Impelmentation note: to allow unprivileged users to run it, this test makes
// use of user and mount namespaces. On systems that allow unprivileged user
// namespaces (Linux >= 3.8 compiled with CONFIG_USER_NS), the test should run
// without root.

extern crate libc;
extern crate nix;
extern crate tempdir;

#[cfg(target_os = "linux")]
mod test_mount {
    use std::fs::{self, File};
    use std::io::{Read, Write};
    use std::os::unix::fs::OpenOptionsExt;
    use std::os::unix::fs::PermissionsExt;
    use std::process::Command;

    use libc::{self, EACCES, EROFS};

    use nix::mount::{mount, umount, MsFlags, MS_BIND, MS_RDONLY, MS_NOEXEC};
    use nix::sched::{unshare, CLONE_NEWNS, CLONE_NEWUSER};
    use nix::sys::stat::{self, S_IRWXU, S_IRWXG, S_IRWXO, S_IXUSR, S_IXGRP, S_IXOTH};

    use tempdir::TempDir;

    static SCRIPT_CONTENTS: &'static [u8] = b"#!/bin/sh
exit 23";

    const EXPECTED_STATUS: i32 = 23;

    const NONE: Option<&'static [u8]> = None;
    pub fn test_mount_tmpfs_without_flags_allows_rwx() {
        let tempdir = TempDir::new("nix-test_mount")
                          .unwrap_or_else(|e| panic!("tempdir failed: {}", e));

        mount(NONE,
              tempdir.path(),
              Some(b"tmpfs".as_ref()),
              MsFlags::empty(),
              NONE)
            .unwrap_or_else(|e| panic!("mount failed: {}", e));

        let test_path = tempdir.path().join("test");

        // Verify write.
        fs::OpenOptions::new()
            .create(true)
            .write(true)
            .mode((S_IRWXU | S_IRWXG | S_IRWXO).bits())
            .open(&test_path)
            .and_then(|mut f| f.write(SCRIPT_CONTENTS))
            .unwrap_or_else(|e| panic!("write failed: {}", e));

        // Verify read.
        let mut buf = Vec::new();
        File::open(&test_path)
            .and_then(|mut f| f.read_to_end(&mut buf))
            .unwrap_or_else(|e| panic!("read failed: {}", e));
        assert_eq!(buf, SCRIPT_CONTENTS);

        // Verify execute.
        assert_eq!(EXPECTED_STATUS,
                   Command::new(&test_path)
                       .status()
                       .unwrap_or_else(|e| panic!("exec failed: {}", e))
                       .code()
                       .unwrap_or_else(|| panic!("child killed by signal")));

        umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {}", e));
    }

    pub fn test_mount_rdonly_disallows_write() {
        let tempdir = TempDir::new("nix-test_mount")
                          .unwrap_or_else(|e| panic!("tempdir failed: {}", e));

        mount(NONE,
              tempdir.path(),
              Some(b"tmpfs".as_ref()),
              MS_RDONLY,
              NONE)
            .unwrap_or_else(|e| panic!("mount failed: {}", e));

        // EROFS: Read-only file system
        assert_eq!(EROFS as i32,
                   File::create(tempdir.path().join("test")).unwrap_err().raw_os_error().unwrap());

        umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {}", e));
    }

    pub fn test_mount_noexec_disallows_exec() {
        let tempdir = TempDir::new("nix-test_mount")
                          .unwrap_or_else(|e| panic!("tempdir failed: {}", e));

        mount(NONE,
              tempdir.path(),
              Some(b"tmpfs".as_ref()),
              MS_NOEXEC,
              NONE)
            .unwrap_or_else(|e| panic!("mount failed: {}", e));

        let test_path = tempdir.path().join("test");

        fs::OpenOptions::new()
            .create(true)
            .write(true)
            .mode((S_IRWXU | S_IRWXG | S_IRWXO).bits())
            .open(&test_path)
            .and_then(|mut f| f.write(SCRIPT_CONTENTS))
            .unwrap_or_else(|e| panic!("write failed: {}", e));

        // Verify that we cannot execute despite a+x permissions being set.
        let mode = stat::Mode::from_bits_truncate(fs::metadata(&test_path)
                                                      .map(|md| md.permissions().mode())
                                                      .unwrap_or_else(|e| {
                                                          panic!("metadata failed: {}", e)
                                                      }));

        assert!(mode.contains(S_IXUSR | S_IXGRP | S_IXOTH),
                "{:?} did not have execute permissions",
                &test_path);

        // EACCES: Permission denied
        assert_eq!(EACCES as i32,
                   Command::new(&test_path).status().unwrap_err().raw_os_error().unwrap());

        umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {}", e));
    }

    pub fn test_mount_bind() {
        use std::env;
        if env::var("CI").is_ok() && env::var("TRAVIS").is_ok() {
            print!("Travis does not allow bind mounts, skipping.");
            return;
        }

        let tempdir = TempDir::new("nix-test_mount")
                          .unwrap_or_else(|e| panic!("tempdir failed: {}", e));
        let file_name = "test";

        {
            let mount_point = TempDir::new("nix-test_mount")
                                  .unwrap_or_else(|e| panic!("tempdir failed: {}", e));

            mount(Some(tempdir.path()),
                  mount_point.path(),
                  NONE,
                  MS_BIND,
                  NONE)
                .unwrap_or_else(|e| panic!("mount failed: {}", e));

            fs::OpenOptions::new()
                .create(true)
                .write(true)
                .mode((S_IRWXU | S_IRWXG | S_IRWXO).bits())
                .open(mount_point.path().join(file_name))
                .and_then(|mut f| f.write(SCRIPT_CONTENTS))
                .unwrap_or_else(|e| panic!("write failed: {}", e));

            umount(mount_point.path()).unwrap_or_else(|e| panic!("umount failed: {}", e));
        }

        // Verify the file written in the mount shows up in source directory, even
        // after unmounting.

        let mut buf = Vec::new();
        File::open(tempdir.path().join(file_name))
            .and_then(|mut f| f.read_to_end(&mut buf))
            .unwrap_or_else(|e| panic!("read failed: {}", e));
        assert_eq!(buf, SCRIPT_CONTENTS);
    }

    pub fn setup_namespaces() {
        // Hold on to the uid in the parent namespace.
        let uid = unsafe { libc::getuid() };

        unshare(CLONE_NEWNS | CLONE_NEWUSER).unwrap_or_else(|e| {
            panic!("unshare failed: {}. Are unprivileged user namespaces available?",
                   e)
        });

        // Map user as uid 1000.
        fs::OpenOptions::new()
            .write(true)
            .open("/proc/self/uid_map")
            .and_then(|mut f| f.write(format!("1000 {} 1\n", uid).as_bytes()))
            .unwrap_or_else(|e| panic!("could not write uid map: {}", e));
    }
}

// Test runner

/// Mimic normal test output (hackishly).
macro_rules! run_tests {
    ( $($test_fn:ident),* ) => {{
        print!("\n");

        $(
            print!("test test_mount::{} ... ", stringify!($test_fn));
            $test_fn();
            print!("ok\n");
        )*

        print!("\n");
    }}
}

#[cfg(target_os = "linux")]
fn main() {
    use test_mount::{setup_namespaces, test_mount_tmpfs_without_flags_allows_rwx,
                     test_mount_rdonly_disallows_write, test_mount_noexec_disallows_exec,
                     test_mount_bind};
    setup_namespaces();

    run_tests!(test_mount_tmpfs_without_flags_allows_rwx,
               test_mount_rdonly_disallows_write,
               test_mount_noexec_disallows_exec,
               test_mount_bind);
}

#[cfg(not(target_os = "linux"))]
fn main() {}
<commit_msg>mount: Do not treat unshare(2) failure as test failure<commit_after>// Impelmentation note: to allow unprivileged users to run it, this test makes
// use of user and mount namespaces. On systems that allow unprivileged user
// namespaces (Linux >= 3.8 compiled with CONFIG_USER_NS), the test should run
// without root.

extern crate libc;
extern crate nix;
extern crate tempdir;

#[cfg(target_os = "linux")]
mod test_mount {
    use std::fs::{self, File};
    use std::io::{self, Read, Write};
    use std::os::unix::fs::OpenOptionsExt;
    use std::os::unix::fs::PermissionsExt;
    use std::process::{self, Command};

    use libc::{self, EACCES, EROFS};

    use nix::mount::{mount, umount, MsFlags, MS_BIND, MS_RDONLY, MS_NOEXEC};
    use nix::sched::{unshare, CLONE_NEWNS, CLONE_NEWUSER};
    use nix::sys::stat::{self, S_IRWXU, S_IRWXG, S_IRWXO, S_IXUSR, S_IXGRP, S_IXOTH};

    use tempdir::TempDir;

    static SCRIPT_CONTENTS: &'static [u8] = b"#!/bin/sh
exit 23";

    const EXPECTED_STATUS: i32 = 23;

    const NONE: Option<&'static [u8]> = None;
    pub fn test_mount_tmpfs_without_flags_allows_rwx() {
        let tempdir = TempDir::new("nix-test_mount")
                          .unwrap_or_else(|e| panic!("tempdir failed: {}", e));

        mount(NONE,
              tempdir.path(),
              Some(b"tmpfs".as_ref()),
              MsFlags::empty(),
              NONE)
            .unwrap_or_else(|e| panic!("mount failed: {}", e));

        let test_path = tempdir.path().join("test");

        // Verify write.
        fs::OpenOptions::new()
            .create(true)
            .write(true)
            .mode((S_IRWXU | S_IRWXG | S_IRWXO).bits())
            .open(&test_path)
            .and_then(|mut f| f.write(SCRIPT_CONTENTS))
            .unwrap_or_else(|e| panic!("write failed: {}", e));

        // Verify read.
        let mut buf = Vec::new();
        File::open(&test_path)
            .and_then(|mut f| f.read_to_end(&mut buf))
            .unwrap_or_else(|e| panic!("read failed: {}", e));
        assert_eq!(buf, SCRIPT_CONTENTS);

        // Verify execute.
        assert_eq!(EXPECTED_STATUS,
                   Command::new(&test_path)
                       .status()
                       .unwrap_or_else(|e| panic!("exec failed: {}", e))
                       .code()
                       .unwrap_or_else(|| panic!("child killed by signal")));

        umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {}", e));
    }

    pub fn test_mount_rdonly_disallows_write() {
        let tempdir = TempDir::new("nix-test_mount")
                          .unwrap_or_else(|e| panic!("tempdir failed: {}", e));

        mount(NONE,
              tempdir.path(),
              Some(b"tmpfs".as_ref()),
              MS_RDONLY,
              NONE)
            .unwrap_or_else(|e| panic!("mount failed: {}", e));

        // EROFS: Read-only file system
        assert_eq!(EROFS as i32,
                   File::create(tempdir.path().join("test")).unwrap_err().raw_os_error().unwrap());

        umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {}", e));
    }

    pub fn test_mount_noexec_disallows_exec() {
        let tempdir = TempDir::new("nix-test_mount")
                          .unwrap_or_else(|e| panic!("tempdir failed: {}", e));

        mount(NONE,
              tempdir.path(),
              Some(b"tmpfs".as_ref()),
              MS_NOEXEC,
              NONE)
            .unwrap_or_else(|e| panic!("mount failed: {}", e));

        let test_path = tempdir.path().join("test");

        fs::OpenOptions::new()
            .create(true)
            .write(true)
            .mode((S_IRWXU | S_IRWXG | S_IRWXO).bits())
            .open(&test_path)
            .and_then(|mut f| f.write(SCRIPT_CONTENTS))
            .unwrap_or_else(|e| panic!("write failed: {}", e));

        // Verify that we cannot execute despite a+x permissions being set.
        let mode = stat::Mode::from_bits_truncate(fs::metadata(&test_path)
                                                      .map(|md| md.permissions().mode())
                                                      .unwrap_or_else(|e| {
                                                          panic!("metadata failed: {}", e)
                                                      }));

        assert!(mode.contains(S_IXUSR | S_IXGRP | S_IXOTH),
                "{:?} did not have execute permissions",
                &test_path);

        // EACCES: Permission denied
        assert_eq!(EACCES as i32,
                   Command::new(&test_path).status().unwrap_err().raw_os_error().unwrap());

        umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {}", e));
    }

    pub fn test_mount_bind() {
        use std::env;
        if env::var("CI").is_ok() && env::var("TRAVIS").is_ok() {
            print!("Travis does not allow bind mounts, skipping.");
            return;
        }

        let tempdir = TempDir::new("nix-test_mount")
                          .unwrap_or_else(|e| panic!("tempdir failed: {}", e));
        let file_name = "test";

        {
            let mount_point = TempDir::new("nix-test_mount")
                                  .unwrap_or_else(|e| panic!("tempdir failed: {}", e));

            mount(Some(tempdir.path()),
                  mount_point.path(),
                  NONE,
                  MS_BIND,
                  NONE)
                .unwrap_or_else(|e| panic!("mount failed: {}", e));

            fs::OpenOptions::new()
                .create(true)
                .write(true)
                .mode((S_IRWXU | S_IRWXG | S_IRWXO).bits())
                .open(mount_point.path().join(file_name))
                .and_then(|mut f| f.write(SCRIPT_CONTENTS))
                .unwrap_or_else(|e| panic!("write failed: {}", e));

            umount(mount_point.path()).unwrap_or_else(|e| panic!("umount failed: {}", e));
        }

        // Verify the file written in the mount shows up in source directory, even
        // after unmounting.

        let mut buf = Vec::new();
        File::open(tempdir.path().join(file_name))
            .and_then(|mut f| f.read_to_end(&mut buf))
            .unwrap_or_else(|e| panic!("read failed: {}", e));
        assert_eq!(buf, SCRIPT_CONTENTS);
    }

    pub fn setup_namespaces() {
        // Hold on to the uid in the parent namespace.
        let uid = unsafe { libc::getuid() };

        unshare(CLONE_NEWNS | CLONE_NEWUSER).unwrap_or_else(|e| {
            let stderr = io::stderr();
            let mut handle = stderr.lock();
            writeln!(handle,
                     "unshare failed: {}. Are unprivileged user namespaces available?",
                     e);
            writeln!(handle, "mount is not being tested");
            // Exit with success because not all systems support unprivileged user namespaces, and
            // that's not what we're testing for.
            process::exit(0);
        });

        // Map user as uid 1000.
        fs::OpenOptions::new()
            .write(true)
            .open("/proc/self/uid_map")
            .and_then(|mut f| f.write(format!("1000 {} 1\n", uid).as_bytes()))
            .unwrap_or_else(|e| panic!("could not write uid map: {}", e));
    }
}

// Test runner

/// Mimic normal test output (hackishly).
macro_rules! run_tests {
    ( $($test_fn:ident),* ) => {{
        print!("\n");

        $(
            print!("test test_mount::{} ... ", stringify!($test_fn));
            $test_fn();
            print!("ok\n");
        )*

        print!("\n");
    }}
}

#[cfg(target_os = "linux")]
fn main() {
    use test_mount::{setup_namespaces, test_mount_tmpfs_without_flags_allows_rwx,
                     test_mount_rdonly_disallows_write, test_mount_noexec_disallows_exec,
                     test_mount_bind};
    setup_namespaces();

    run_tests!(test_mount_tmpfs_without_flags_allows_rwx,
               test_mount_rdonly_disallows_write,
               test_mount_noexec_disallows_exec,
               test_mount_bind);
}

#[cfg(not(target_os = "linux"))]
fn main() {}
<|endoftext|>


<commit_before>#[test]
#[cfg(feature = "syntax-highlight")]
fn cli_tests() {
    trycmd::TestCases::new().case("tests/cmd/*.md");
}
<commit_msg>test: Increase CLI test coverage under different feature sets<commit_after>#[test]
#[cfg(feature = "syntax-highlight")]
fn cli_tests() {
    let t = trycmd::TestCases::new();
    t.case("tests/cmd/*.md");
    #[cfg(not(feature = "serve"))]
    {
        t.skip("tests/cmd/errors.md");
    }
}
<|endoftext|>


<commit_before>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Alex Lyon <arcterus@mail.com>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

// spell-checker:ignore (ToDO) tstr sigstr cmdname setpgid sigchld

#[macro_use]
extern crate uucore;

extern crate clap;

use clap::{crate_version, App, AppSettings, Arg};
use std::io::ErrorKind;
use std::process::{Command, Stdio};
use std::time::Duration;
use uucore::display::Quotable;
use uucore::process::ChildExt;
use uucore::signals::{signal_by_name_or_value, signal_name_by_value};
use uucore::InvalidEncodingHandling;

static ABOUT: &str = "Start COMMAND, and kill it if still running after DURATION.";

fn usage() -> String {
    format!(
        "{0} [OPTION] DURATION COMMAND...",
        uucore::execution_phrase()
    )
}

const ERR_EXIT_STATUS: i32 = 125;

pub mod options {
    pub static FOREGROUND: &str = "foreground";
    pub static KILL_AFTER: &str = "kill-after";
    pub static SIGNAL: &str = "signal";
    pub static PRESERVE_STATUS: &str = "preserve-status";
    pub static VERBOSE: &str = "verbose";

    // Positional args.
    pub static DURATION: &str = "duration";
    pub static COMMAND: &str = "command";
}

struct Config {
    foreground: bool,
    kill_after: Option<Duration>,
    signal: usize,
    duration: Duration,
    preserve_status: bool,
    verbose: bool,

    command: Vec<String>,
}

impl Config {
    fn from(options: clap::ArgMatches) -> Config {
        let signal = match options.value_of(options::SIGNAL) {
            Some(signal_) => {
                let signal_result = signal_by_name_or_value(signal_);
                match signal_result {
                    None => {
                        unreachable!("invalid signal {}", signal_.quote());
                    }
                    Some(signal_value) => signal_value,
                }
            }
            _ => uucore::signals::signal_by_name_or_value("TERM").unwrap(),
        };

        let kill_after = options
            .value_of(options::KILL_AFTER)
            .map(|time| uucore::parse_time::from_str(time).unwrap());

        let duration: Duration =
            uucore::parse_time::from_str(options.value_of(options::DURATION).unwrap()).unwrap();

        let preserve_status: bool = options.is_present(options::PRESERVE_STATUS);
        let foreground = options.is_present(options::FOREGROUND);
        let verbose = options.is_present(options::VERBOSE);

        let command = options
            .values_of(options::COMMAND)
            .unwrap()
            .map(String::from)
            .collect::<Vec<_>>();

        Config {
            foreground,
            kill_after,
            signal,
            duration,
            preserve_status,
            verbose,
            command,
        }
    }
}

pub fn uumain(args: impl uucore::Args) -> i32 {
    let args = args
        .collect_str(InvalidEncodingHandling::ConvertLossy)
        .accept_any();

    let usage = usage();

    let app = uu_app().usage(&usage[..]);

    let matches = app.get_matches_from(args);

    let config = Config::from(matches);
    timeout(
        &config.command,
        config.duration,
        config.signal,
        config.kill_after,
        config.foreground,
        config.preserve_status,
        config.verbose,
    )
}

pub fn uu_app() -> App<'static, 'static> {
    App::new("timeout")
        .version(crate_version!())
        .about(ABOUT)
        .arg(
            Arg::with_name(options::FOREGROUND)
                .long(options::FOREGROUND)
                .help("when not running timeout directly from a shell prompt, allow COMMAND to read from the TTY and get TTY signals; in this mode, children of COMMAND will not be timed out")
        )
        .arg(
            Arg::with_name(options::KILL_AFTER)
                .short("k")
                .takes_value(true))
        .arg(
            Arg::with_name(options::PRESERVE_STATUS)
                .long(options::PRESERVE_STATUS)
                .help("exit with the same status as COMMAND, even when the command times out")
        )
        .arg(
            Arg::with_name(options::SIGNAL)
                .short("s")
                .long(options::SIGNAL)
                .help("specify the signal to be sent on timeout; SIGNAL may be a name like 'HUP' or a number; see 'kill -l' for a list of signals")
                .takes_value(true)
        )
        .arg(
            Arg::with_name(options::VERBOSE)
              .short("v")
              .long(options::VERBOSE)
              .help("diagnose to stderr any signal sent upon timeout")
        )
        .arg(
            Arg::with_name(options::DURATION)
                .index(1)
                .required(true)
        )
        .arg(
            Arg::with_name(options::COMMAND)
                .index(2)
                .required(true)
                .multiple(true)
        )
        .setting(AppSettings::TrailingVarArg)
}

/// Remove pre-existing SIGCHLD handlers that would make waiting for the child's exit code fail.
fn unblock_sigchld() {
    unsafe {
        nix::sys::signal::signal(
            nix::sys::signal::Signal::SIGCHLD,
            nix::sys::signal::SigHandler::SigDfl,
        )
        .unwrap();
    }
}

/// TODO: Improve exit codes, and make them consistent with the GNU Coreutils exit codes.

fn timeout(
    cmd: &[String],
    duration: Duration,
    signal: usize,
    kill_after: Option<Duration>,
    foreground: bool,
    preserve_status: bool,
    verbose: bool,
) -> i32 {
    if !foreground {
        unsafe { libc::setpgid(0, 0) };
    }
    let mut process = match Command::new(&cmd[0])
        .args(&cmd[1..])
        .stdin(Stdio::inherit())
        .stdout(Stdio::inherit())
        .stderr(Stdio::inherit())
        .spawn()
    {
        Ok(p) => p,
        Err(err) => {
            show_error!("failed to execute process: {}", err);
            if err.kind() == ErrorKind::NotFound {
                // FIXME: not sure which to use
                return 127;
            } else {
                // FIXME: this may not be 100% correct...
                return 126;
            }
        }
    };
    unblock_sigchld();
    match process.wait_or_timeout(duration) {
        Ok(Some(status)) => status.code().unwrap_or_else(|| status.signal().unwrap()),
        Ok(None) => {
            if verbose {
                show_error!(
                    "sending signal {} to command {}",
                    signal_name_by_value(signal).unwrap(),
                    cmd[0].quote()
                );
            }
            crash_if_err!(ERR_EXIT_STATUS, process.send_signal(signal));
            if let Some(kill_after) = kill_after {
                match process.wait_or_timeout(kill_after) {
                    Ok(Some(status)) => {
                        if preserve_status {
                            status.code().unwrap_or_else(|| status.signal().unwrap())
                        } else {
                            124
                        }
                    }
                    Ok(None) => {
                        if verbose {
                            show_error!("sending signal KILL to command {}", cmd[0].quote());
                        }
                        crash_if_err!(
                            ERR_EXIT_STATUS,
                            process.send_signal(
                                uucore::signals::signal_by_name_or_value("KILL").unwrap()
                            )
                        );
                        crash_if_err!(ERR_EXIT_STATUS, process.wait());
                        137
                    }
                    Err(_) => 124,
                }
            } else {
                124
            }
        }
        Err(_) => {
            crash_if_err!(ERR_EXIT_STATUS, process.send_signal(signal));
            ERR_EXIT_STATUS
        }
    }
}
<commit_msg>timeout: return UResult from uumain() function<commit_after>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Alex Lyon <arcterus@mail.com>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

// spell-checker:ignore (ToDO) tstr sigstr cmdname setpgid sigchld

#[macro_use]
extern crate uucore;

extern crate clap;

use clap::{crate_version, App, AppSettings, Arg};
use std::io::ErrorKind;
use std::process::{Command, Stdio};
use std::time::Duration;
use uucore::display::Quotable;
use uucore::error::{UResult, USimpleError};
use uucore::process::ChildExt;
use uucore::signals::{signal_by_name_or_value, signal_name_by_value};
use uucore::InvalidEncodingHandling;

static ABOUT: &str = "Start COMMAND, and kill it if still running after DURATION.";

fn usage() -> String {
    format!(
        "{0} [OPTION] DURATION COMMAND...",
        uucore::execution_phrase()
    )
}

const ERR_EXIT_STATUS: i32 = 125;

pub mod options {
    pub static FOREGROUND: &str = "foreground";
    pub static KILL_AFTER: &str = "kill-after";
    pub static SIGNAL: &str = "signal";
    pub static PRESERVE_STATUS: &str = "preserve-status";
    pub static VERBOSE: &str = "verbose";

    // Positional args.
    pub static DURATION: &str = "duration";
    pub static COMMAND: &str = "command";
}

struct Config {
    foreground: bool,
    kill_after: Option<Duration>,
    signal: usize,
    duration: Duration,
    preserve_status: bool,
    verbose: bool,

    command: Vec<String>,
}

impl Config {
    fn from(options: clap::ArgMatches) -> Config {
        let signal = match options.value_of(options::SIGNAL) {
            Some(signal_) => {
                let signal_result = signal_by_name_or_value(signal_);
                match signal_result {
                    None => {
                        unreachable!("invalid signal {}", signal_.quote());
                    }
                    Some(signal_value) => signal_value,
                }
            }
            _ => uucore::signals::signal_by_name_or_value("TERM").unwrap(),
        };

        let kill_after = options
            .value_of(options::KILL_AFTER)
            .map(|time| uucore::parse_time::from_str(time).unwrap());

        let duration: Duration =
            uucore::parse_time::from_str(options.value_of(options::DURATION).unwrap()).unwrap();

        let preserve_status: bool = options.is_present(options::PRESERVE_STATUS);
        let foreground = options.is_present(options::FOREGROUND);
        let verbose = options.is_present(options::VERBOSE);

        let command = options
            .values_of(options::COMMAND)
            .unwrap()
            .map(String::from)
            .collect::<Vec<_>>();

        Config {
            foreground,
            kill_after,
            signal,
            duration,
            preserve_status,
            verbose,
            command,
        }
    }
}

#[uucore_procs::gen_uumain]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
    let args = args
        .collect_str(InvalidEncodingHandling::ConvertLossy)
        .accept_any();

    let usage = usage();

    let app = uu_app().usage(&usage[..]);

    let matches = app.get_matches_from(args);

    let config = Config::from(matches);
    timeout(
        &config.command,
        config.duration,
        config.signal,
        config.kill_after,
        config.foreground,
        config.preserve_status,
        config.verbose,
    )
}

pub fn uu_app() -> App<'static, 'static> {
    App::new("timeout")
        .version(crate_version!())
        .about(ABOUT)
        .arg(
            Arg::with_name(options::FOREGROUND)
                .long(options::FOREGROUND)
                .help("when not running timeout directly from a shell prompt, allow COMMAND to read from the TTY and get TTY signals; in this mode, children of COMMAND will not be timed out")
        )
        .arg(
            Arg::with_name(options::KILL_AFTER)
                .short("k")
                .takes_value(true))
        .arg(
            Arg::with_name(options::PRESERVE_STATUS)
                .long(options::PRESERVE_STATUS)
                .help("exit with the same status as COMMAND, even when the command times out")
        )
        .arg(
            Arg::with_name(options::SIGNAL)
                .short("s")
                .long(options::SIGNAL)
                .help("specify the signal to be sent on timeout; SIGNAL may be a name like 'HUP' or a number; see 'kill -l' for a list of signals")
                .takes_value(true)
        )
        .arg(
            Arg::with_name(options::VERBOSE)
              .short("v")
              .long(options::VERBOSE)
              .help("diagnose to stderr any signal sent upon timeout")
        )
        .arg(
            Arg::with_name(options::DURATION)
                .index(1)
                .required(true)
        )
        .arg(
            Arg::with_name(options::COMMAND)
                .index(2)
                .required(true)
                .multiple(true)
        )
        .setting(AppSettings::TrailingVarArg)
}

/// Remove pre-existing SIGCHLD handlers that would make waiting for the child's exit code fail.
fn unblock_sigchld() {
    unsafe {
        nix::sys::signal::signal(
            nix::sys::signal::Signal::SIGCHLD,
            nix::sys::signal::SigHandler::SigDfl,
        )
        .unwrap();
    }
}

/// TODO: Improve exit codes, and make them consistent with the GNU Coreutils exit codes.

fn timeout(
    cmd: &[String],
    duration: Duration,
    signal: usize,
    kill_after: Option<Duration>,
    foreground: bool,
    preserve_status: bool,
    verbose: bool,
) -> UResult<()> {
    if !foreground {
        unsafe { libc::setpgid(0, 0) };
    }
    let mut process = Command::new(&cmd[0])
        .args(&cmd[1..])
        .stdin(Stdio::inherit())
        .stdout(Stdio::inherit())
        .stderr(Stdio::inherit())
        .spawn()
        .map_err(|err| {
            let status_code = if err.kind() == ErrorKind::NotFound {
                // FIXME: not sure which to use
                127
            } else {
                // FIXME: this may not be 100% correct...
                126
            };
            USimpleError::new(status_code, format!("failed to execute process: {}", err))
        })?;
    unblock_sigchld();
    match process.wait_or_timeout(duration) {
        Ok(Some(status)) => {
            let status_code = status.code().unwrap_or_else(|| status.signal().unwrap());
            if status_code == 0 {
                Ok(())
            } else {
                Err(status_code.into())
            }
        }
        Ok(None) => {
            if verbose {
                show_error!(
                    "sending signal {} to command {}",
                    signal_name_by_value(signal).unwrap(),
                    cmd[0].quote()
                );
            }
            process
                .send_signal(signal)
                .map_err(|e| USimpleError::new(ERR_EXIT_STATUS, format!("{}", e)))?;
            if let Some(kill_after) = kill_after {
                match process.wait_or_timeout(kill_after) {
                    Ok(Some(status)) => {
                        if preserve_status {
                            let status_code =
                                status.code().unwrap_or_else(|| status.signal().unwrap());
                            if status_code == 0 {
                                Ok(())
                            } else {
                                Err(status_code.into())
                            }
                        } else {
                            Err(124.into())
                        }
                    }
                    Ok(None) => {
                        if verbose {
                            show_error!("sending signal KILL to command {}", cmd[0].quote());
                        }
                        process
                            .send_signal(uucore::signals::signal_by_name_or_value("KILL").unwrap())
                            .map_err(|e| USimpleError::new(ERR_EXIT_STATUS, format!("{}", e)))?;
                        process
                            .wait()
                            .map_err(|e| USimpleError::new(ERR_EXIT_STATUS, format!("{}", e)))?;
                        Err(137.into())
                    }
                    Err(_) => Err(124.into()),
                }
            } else {
                Err(124.into())
            }
        }
        Err(_) => {
            // We're going to return ERR_EXIT_STATUS regardless of
            // whether `send_signal()` succeeds or fails, so just
            // ignore the return value.
            process
                .send_signal(signal)
                .map_err(|e| USimpleError::new(ERR_EXIT_STATUS, format!("{}", e)))?;
            Err(ERR_EXIT_STATUS.into())
        }
    }
}
<|endoftext|>


<commit_before>use core::mem;

use {Future, IntoFuture, Async, Poll};
use stream::Stream;

/// Creates a `Stream` from a seed and a closure returning a `Future`.
///
/// This function is the dual for the `Stream::fold()` adapter: while
/// `Stream:fold()` reduces a `Stream` to one single value, `unfold()` creates a
/// `Stream` from a seed value.
///
/// `unfold()` will call the provided closure with the provided seed, then wait
/// for the returned `Future` to complete with `(a, b)`. It will then yield the
/// value `a`, and use `b` as the next internal state.
///
/// If the closure returns `None` instead of `Some(Future)`, then the `unfold()`
/// will stop producing items and return `Ok(Async::Ready(None))` in future
/// calls to `poll()`.
///
/// In case of error generated by the returned `Future`, the error will be
/// returned by the `Stream`.  The `Stream` will then yield
/// `Ok(Async::Ready(None))` in future calls to `poll()`.
///
/// This function can typically be used when wanting to go from the "world of
/// futures" to the "world of streams": the provided closure can build a
/// `Future` using other library functions working on futures, and `unfold()`
/// will turn it into a `Stream` by repeating the operation.
///
/// # Example
///
/// ```rust
/// use futures::stream::{self, Stream};
/// use futures::future::{self, Future};
///
/// let mut stream = stream::unfold(0, |state| {
///     if state <= 2 {
///         let next_state = state + 1;
///         let yielded = state  * 2;
///         let fut = future::ok::<_, u32>((yielded, next_state));
///         Some(fut)
///     } else {
///         None
///     }
/// });
///
/// let result = stream.collect().wait();
/// assert_eq!(result, Ok(vec![0, 2, 4]));
/// ```
pub fn unfold<T, F, Fut, It>(init: T, f: F) -> Unfold<T, F, Fut>
    where F: FnMut(T) -> Option<Fut>,
          Fut: IntoFuture<Item = (It, T)>,
{
    Unfold {
        f: f,
        state: State::Ready(init),
    }
}

/// A stream which creates futures, polls them and return their result
///
/// This stream is returned by the `futures::stream::unfold` method
#[derive(Debug)]
#[must_use = "streams do nothing unless polled"]
pub struct Unfold<T, F, Fut> where Fut: IntoFuture {
    f: F,
    state: State<T, Fut::Future>,
}

impl <T, F, Fut, It> Stream for Unfold<T, F, Fut>
    where F: FnMut(T) -> Option<Fut>,
          Fut: IntoFuture<Item = (It, T)>,
{
    type Item = It;
    type Error = Fut::Error;

    fn poll(&mut self) -> Poll<Option<It>, Fut::Error> {
        loop {
            match mem::replace(&mut self.state, State::Empty) {
                // State::Empty may happen if the future returned an error
                State::Empty => { return Ok(Async::Ready(None)); }
                State::Ready(state) => {
                    match (self.f)(state) {
                        Some(fut) => { self.state = State::Processing(fut.into_future()); }
                        None => { return Ok(Async::Ready(None)); }
                    }
                }
                State::Processing(mut fut) => {
                    match fut.poll()? {
                        Async:: Ready((item, next_state)) => {
                            self.state = State::Ready(next_state);
                            return Ok(Async::Ready(Some(item)));
                        }
                        Async::NotReady => {
                            self.state = State::Processing(fut);
                            return Ok(Async::NotReady);
                        }
                    }
                }
            }
        }
    }
}

#[derive(Debug)]
enum State<T, F> where F: Future {
    /// Placeholder state when doing work, or when the returned Future generated an error
    Empty,

    /// Ready to generate new future; current internal state is the `T`
    Ready(T),

    /// Working on a future generated previously
    Processing(F),
}
<commit_msg>fix minor inconsistency in Stream::unfold rustdocs<commit_after>use core::mem;

use {Future, IntoFuture, Async, Poll};
use stream::Stream;

/// Creates a `Stream` from a seed and a closure returning a `Future`.
///
/// This function is the dual for the `Stream::fold()` adapter: while
/// `Stream::fold()` reduces a `Stream` to one single value, `unfold()` creates a
/// `Stream` from a seed value.
///
/// `unfold()` will call the provided closure with the provided seed, then wait
/// for the returned `Future` to complete with `(a, b)`. It will then yield the
/// value `a`, and use `b` as the next internal state.
///
/// If the closure returns `None` instead of `Some(Future)`, then the `unfold()`
/// will stop producing items and return `Ok(Async::Ready(None))` in future
/// calls to `poll()`.
///
/// In case of error generated by the returned `Future`, the error will be
/// returned by the `Stream`.  The `Stream` will then yield
/// `Ok(Async::Ready(None))` in future calls to `poll()`.
///
/// This function can typically be used when wanting to go from the "world of
/// futures" to the "world of streams": the provided closure can build a
/// `Future` using other library functions working on futures, and `unfold()`
/// will turn it into a `Stream` by repeating the operation.
///
/// # Example
///
/// ```rust
/// use futures::stream::{self, Stream};
/// use futures::future::{self, Future};
///
/// let mut stream = stream::unfold(0, |state| {
///     if state <= 2 {
///         let next_state = state + 1;
///         let yielded = state  * 2;
///         let fut = future::ok::<_, u32>((yielded, next_state));
///         Some(fut)
///     } else {
///         None
///     }
/// });
///
/// let result = stream.collect().wait();
/// assert_eq!(result, Ok(vec![0, 2, 4]));
/// ```
pub fn unfold<T, F, Fut, It>(init: T, f: F) -> Unfold<T, F, Fut>
    where F: FnMut(T) -> Option<Fut>,
          Fut: IntoFuture<Item = (It, T)>,
{
    Unfold {
        f: f,
        state: State::Ready(init),
    }
}

/// A stream which creates futures, polls them and return their result
///
/// This stream is returned by the `futures::stream::unfold` method
#[derive(Debug)]
#[must_use = "streams do nothing unless polled"]
pub struct Unfold<T, F, Fut> where Fut: IntoFuture {
    f: F,
    state: State<T, Fut::Future>,
}

impl <T, F, Fut, It> Stream for Unfold<T, F, Fut>
    where F: FnMut(T) -> Option<Fut>,
          Fut: IntoFuture<Item = (It, T)>,
{
    type Item = It;
    type Error = Fut::Error;

    fn poll(&mut self) -> Poll<Option<It>, Fut::Error> {
        loop {
            match mem::replace(&mut self.state, State::Empty) {
                // State::Empty may happen if the future returned an error
                State::Empty => { return Ok(Async::Ready(None)); }
                State::Ready(state) => {
                    match (self.f)(state) {
                        Some(fut) => { self.state = State::Processing(fut.into_future()); }
                        None => { return Ok(Async::Ready(None)); }
                    }
                }
                State::Processing(mut fut) => {
                    match fut.poll()? {
                        Async:: Ready((item, next_state)) => {
                            self.state = State::Ready(next_state);
                            return Ok(Async::Ready(Some(item)));
                        }
                        Async::NotReady => {
                            self.state = State::Processing(fut);
                            return Ok(Async::NotReady);
                        }
                    }
                }
            }
        }
    }
}

#[derive(Debug)]
enum State<T, F> where F: Future {
    /// Placeholder state when doing work, or when the returned Future generated an error
    Empty,

    /// Ready to generate new future; current internal state is the `T`
    Ready(T),

    /// Working on a future generated previously
    Processing(F),
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;
use super::context::Context;
use super::vertex_data::{VertexData, VertexBytes, VertexAttribBinder};
use super::buffer::{Buffer, BufferBinding, ArrayBufferBinding};

pub struct VertexBuffer<T: VertexData> {
    pub attrib_binder: Option<T::Binder>,
    buffer: Buffer,
    count: usize,
    phantom: PhantomData<*const T>
}

impl<T: VertexData> VertexBuffer<T> {
    pub fn build_attrib_binder(&self)
        -> <T::Binder as VertexAttribBinder>::Builder
    {
        T::build_attrib_binder()
    }

    pub fn bind(&self, gl_buffer: &ArrayBufferBinding) -> Result<(), ()> {
        match self.attrib_binder {
            Some(ref binder) => {
                binder.bind(gl_buffer);
                Ok(())
            },
            None => { Err(()) }
        }
    }

    pub fn buffer(&self) -> &Buffer {
        &self.buffer
    }

    pub fn buffer_mut(&mut self) -> &mut Buffer {
        &mut self.buffer
    }
}

impl Context {
    pub fn new_vertex_buffer<T: VertexData>(&self) -> VertexBuffer<T> {
        VertexBuffer {
            attrib_binder: None,
            buffer: self.gen_buffer(),
            count: 0,
            phantom: PhantomData
        }
    }
}

pub struct VertexBufferBinding<'a, T: VertexData>
    where T: 'a, T::Binder: 'a
{
    gl_buffer: ArrayBufferBinding<'a>,
    vbo: &'a mut VertexBuffer<T>
}

impl<'a, T: VertexData> VertexBufferBinding<'a, T>
    where T: 'a, T::Binder: 'a
{
    pub fn new(gl_buffer: ArrayBufferBinding<'a>, vbo: &'a mut VertexBuffer<T>)
        -> Self
    {
        VertexBufferBinding {
            gl_buffer: gl_buffer,
            vbo: vbo
        }
    }

    pub fn buffer_data(&mut self, data: &[T], usage: super::BufferDataUsage)
        where [T]: VertexBytes
    {
        self.vbo.count = data.len();
        self.gl_buffer.buffer_bytes(data.vertex_bytes(), usage);
    }
}

#[macro_export]
macro_rules! bind_attrib_pointers {
    ($gl:expr, $vbo:expr, {
        $($field_name:ident => $field_attrib:expr),*
    }) => {
        {
            let vbo = $vbo;
            let binder = vbo.build_attrib_binder()
                            $(.$field_name($field_attrib))*
                            .unwrap($gl);
            vbo.attrib_binder = Some(binder)
        }
    }
}

#[macro_export]
macro_rules! bind_vertex_buffer {
    ($gl:expr, $vbo:expr) => {
        {
            let vbo = $vbo;
            let gl : &mut _ = $gl;

            let gl_buffer = bind_array_buffer!(gl, vbo.buffer_mut());
            vbo.bind(&gl_buffer).unwrap();
            $crate::VertexBufferBinding::new(gl_buffer, vbo)
        }
    }
}
<commit_msg>Add `VertexBufferBinding.draw_arrays()`<commit_after>use std::marker::PhantomData;
use super::context::Context;
use super::vertex_data::{VertexData, VertexBytes, VertexAttribBinder};
use super::buffer::{Buffer, BufferBinding, ArrayBufferBinding};
use super::types::DrawingMode;

pub struct VertexBuffer<T: VertexData> {
    pub attrib_binder: Option<T::Binder>,
    buffer: Buffer,
    count: usize,
    phantom: PhantomData<*const T>
}

impl<T: VertexData> VertexBuffer<T> {
    pub fn build_attrib_binder(&self)
        -> <T::Binder as VertexAttribBinder>::Builder
    {
        T::build_attrib_binder()
    }

    pub fn bind(&self, gl_buffer: &ArrayBufferBinding) -> Result<(), ()> {
        match self.attrib_binder {
            Some(ref binder) => {
                binder.bind(gl_buffer);
                Ok(())
            },
            None => { Err(()) }
        }
    }

    pub fn buffer(&self) -> &Buffer {
        &self.buffer
    }

    pub fn buffer_mut(&mut self) -> &mut Buffer {
        &mut self.buffer
    }
}

pub struct VertexBufferBinding<'a, T: VertexData>
    where T: 'a, T::Binder: 'a
{
    gl_buffer: ArrayBufferBinding<'a>,
    vbo: &'a mut VertexBuffer<T>
}

impl<'a, T: VertexData> VertexBufferBinding<'a, T>
    where T: 'a, T::Binder: 'a
{
    pub fn new(gl_buffer: ArrayBufferBinding<'a>, vbo: &'a mut VertexBuffer<T>)
        -> Self
    {
        VertexBufferBinding {
            gl_buffer: gl_buffer,
            vbo: vbo
        }
    }

    pub fn buffer_data(&mut self, data: &[T], usage: super::BufferDataUsage)
        where [T]: VertexBytes
    {
        self.vbo.count = data.len();
        self.gl_buffer.buffer_bytes(data.vertex_bytes(), usage);
    }

    pub fn draw_arrays(&self, mode: DrawingMode) {
        unsafe {
            let gl = Context::current_context();
            gl.draw_arrays_current(mode, 0, self.vbo.count);
        }
    }
}

impl Context {
    pub fn new_vertex_buffer<T: VertexData>(&self) -> VertexBuffer<T> {
        VertexBuffer {
            attrib_binder: None,
            buffer: self.gen_buffer(),
            count: 0,
            phantom: PhantomData
        }
    }
}

#[macro_export]
macro_rules! bind_attrib_pointers {
    ($gl:expr, $vbo:expr, {
        $($field_name:ident => $field_attrib:expr),*
    }) => {
        {
            let vbo = $vbo;
            let binder = vbo.build_attrib_binder()
                            $(.$field_name($field_attrib))*
                            .unwrap($gl);
            vbo.attrib_binder = Some(binder)
        }
    }
}

#[macro_export]
macro_rules! bind_vertex_buffer {
    ($gl:expr, $vbo:expr) => {
        {
            let vbo = $vbo;
            let gl : &mut _ = $gl;

            let gl_buffer = bind_array_buffer!(gl, vbo.buffer_mut());
            vbo.bind(&gl_buffer).unwrap();
            $crate::VertexBufferBinding::new(gl_buffer, vbo)
        }
    }
}
<|endoftext|>


<commit_before>use neon::vm::{Call, JsResult};
use neon::mem::Handle;
use neon::js::{JsNumber, JsString, JsObject, Object};

pub fn return_js_object(call: Call) -> JsResult<JsObject> {
    Ok(JsObject::new(call.scope))
}

pub fn return_js_object_with_mixed_content(call: Call) -> JsResult<JsObject> {
    let scope = call.scope;
    let js_object: Handle<JsObject> = JsObject::new(scope);
    js_object.set("number", JsNumber::new(scope, 9000))?;
    js_object.set("string", JsString::new(scope, "hello node").unwrap())?;
    Ok(js_object)
}

pub fn return_js_object_with_number(call: Call) -> JsResult<JsObject> {
    let scope = call.scope;
    let js_object: Handle<JsObject> = JsObject::new(scope);
    js_object.set("number", JsNumber::new(scope, 9000.0))?;
    Ok(js_object)
}

pub fn return_js_object_with_string(call: Call) -> JsResult<JsObject> {
    let scope = call.scope;
    let js_object: Handle<JsObject> = JsObject::new(scope);
    js_object.set("string", JsString::new(scope, "hello node").unwrap())?;
    Ok(js_object)
}
<commit_msg>Another test error.<commit_after>use neon::vm::{Call, JsResult};
use neon::mem::Handle;
use neon::js::{JsNumber, JsString, JsObject, Object};

pub fn return_js_object(call: Call) -> JsResult<JsObject> {
    Ok(JsObject::new(call.scope))
}

pub fn return_js_object_with_mixed_content(call: Call) -> JsResult<JsObject> {
    let scope = call.scope;
    let js_object: Handle<JsObject> = JsObject::new(scope);
    js_object.set("number", JsNumber::new(scope, 9000.0))?;
    js_object.set("string", JsString::new(scope, "hello node").unwrap())?;
    Ok(js_object)
}

pub fn return_js_object_with_number(call: Call) -> JsResult<JsObject> {
    let scope = call.scope;
    let js_object: Handle<JsObject> = JsObject::new(scope);
    js_object.set("number", JsNumber::new(scope, 9000.0))?;
    Ok(js_object)
}

pub fn return_js_object_with_string(call: Call) -> JsResult<JsObject> {
    let scope = call.scope;
    let js_object: Handle<JsObject> = JsObject::new(scope);
    js_object.set("string", JsString::new(scope, "hello node").unwrap())?;
    Ok(js_object)
}
<|endoftext|>


<commit_before>use instruction::{Definition, SrcKind, DestKind};
use instruction::Coding::*;
use instruction::OperationKind::*;

pub const CHIP8: &'static [Definition] = &[
    Definition { pattern: [C(0x0), C(0x0), C(0x0), C(0x0)], op: NoOp },
    Definition { pattern: [C(0x0), C(0x0), C(0xE), C(0x0)], op: Cls },
    Definition { pattern: [C(0x0), C(0x0), C(0xE), C(0xE)], op: Ret },
    Definition { pattern: [C(0x1), A(1),   A(1),   A(1)  ], op: Jump(SrcKind::Address12) },
    Definition { pattern: [C(0x2), A(1),   A(1),   A(1)  ], op: Call(SrcKind::Address12) },
    Definition { pattern: [C(0x3), A(1),   A(2),   A(2)  ], op: SkipEq(SrcKind::Register, SrcKind::Literal8) },
    Definition { pattern: [C(0x4), A(1),   A(2),   A(3)  ], op: SkipNotEq(SrcKind::Register, SrcKind::Literal8) },
    Definition { pattern: [C(0x5), A(1),   A(2),   C(0x0)], op: SkipEq(SrcKind::Register, SrcKind::Register) },
    Definition { pattern: [C(0x6), A(1),   A(2),   A(2)  ], op: Load(DestKind::Register, SrcKind::Literal8) },
    Definition { pattern: [C(0x7), A(1|2), A(3),   A(3)  ], op: Add(DestKind::Register, SrcKind::Register, SrcKind::Literal8) },
    Definition { pattern: [C(0x8), A(1),   A(2),   C(0x0)], op: Load(DestKind::Register, SrcKind::Register) },
    Definition { pattern: [C(0x8), A(1|2), A(4),   C(0x1)], op: Or(DestKind::Register, SrcKind::Register, SrcKind::Register) },
    Definition { pattern: [C(0x8), A(1|2), A(4),   C(0x2)], op: And(DestKind::Register, SrcKind::Register, SrcKind::Register) },
    Definition { pattern: [C(0x8), A(1|2), A(4),   C(0x3)], op: Xor(DestKind::Register, SrcKind::Register, SrcKind::Register) },
    Definition { pattern: [C(0x8), A(1|2), A(4),   C(0x4)], op: Add(DestKind::Register, SrcKind::Register, SrcKind::Register) },
    Definition { pattern: [C(0x8), A(1|2), A(4),   C(0x5)], op: Sub(DestKind::Register, SrcKind::Register, SrcKind::Register) },
    Definition { pattern: [C(0x8), A(1),   A(2),   C(0x6)], op: Shr(DestKind::Register, SrcKind::Register) },
    Definition { pattern: [C(0x8), A(1),   A(2|4), C(0x7)], op: Sub(DestKind::Register, SrcKind::Register, SrcKind::Register) },
    Definition { pattern: [C(0x8), A(1),   A(2),   C(0xE)], op: Shl(DestKind::Register, SrcKind::Register) },
    Definition { pattern: [C(0x9), A(1),   A(2),   C(0x0)], op: SkipNotEq(SrcKind::Register, SrcKind::Register) },
    Definition { pattern: [C(0xA), A(1),   A(1),   A(1)  ], op: Load(DestKind::I, SrcKind::Literal12 ) },
    Definition { pattern: [C(0xB), A(1),   A(1),   A(1)  ], op: JumpV0(SrcKind::Literal12 ) },
    Definition { pattern: [C(0xC), A(1),   A(4),   A(4)  ], op: Rand(DestKind::Register, SrcKind::Random, SrcKind::Literal8) },
    Definition { pattern: [C(0xD), A(1),   A(2),   A(3)  ], op: Sprite(SrcKind::Register, SrcKind::Register, SrcKind::Literal4) },
    Definition { pattern: [C(0xE), A(1),   C(0x9), C(0xE)], op: SkipKey(SrcKind::Register) },
    Definition { pattern: [C(0xE), A(1),   C(0xA), C(0x1)], op: SkipNotKey(SrcKind::Register) },
    Definition { pattern: [C(0xF), A(1),   C(0x0), C(0x7)], op: Load(DestKind::Register, SrcKind::DelayTimer) },
    Definition { pattern: [C(0xF), A(1),   C(0x0), C(0xA)], op: WaitKey(DestKind::Register, SrcKind::Literal4) },
    Definition { pattern: [C(0xF), A(2),   C(0x1), C(0x5)], op: Load(DestKind::DelayTimer, SrcKind::Register) },
    Definition { pattern: [C(0xF), A(2),   C(0x1), C(0x8)], op: Load(DestKind::SoundTimer, SrcKind::Register) },
    Definition { pattern: [C(0xF), A(4),   C(0x1), C(0xE)], op: Add(DestKind::I, SrcKind::I, SrcKind::Register) },
    Definition { pattern: [C(0xF), A(1),   C(0x2), C(0x9)], op: Font(SrcKind::Register) },
    Definition { pattern: [C(0xF), A(1),   C(0x3), C(0x3)], op: Bcd(SrcKind::Register) },
    Definition { pattern: [C(0xF), A(1),   C(0x5), C(0x5)], op: Stash(SrcKind::Register) },
    Definition { pattern: [C(0xF), A(1),   C(0x6), C(0x5)], op: Fetch(SrcKind::Register) },
];

pub const SUPERCHIP: &'static [Definition] = &[
    Definition { pattern: [C(0x0), C(0x0), C(0xC), A(1)],   op: NoOp /*ScrollDown(SrcKind::Literal4)*/ },
    Definition { pattern: [C(0x0), C(0x0), C(0xF), C(0xB)], op: NoOp /*ScrollRight*/ },
    Definition { pattern: [C(0x0), C(0x0), C(0xF), C(0xC)], op: NoOp /*ScrollLeft*/ },
    Definition { pattern: [C(0x0), C(0x0), C(0xF), C(0xD)], op: NoOp /*Exit*/ },
    Definition { pattern: [C(0x0), C(0x0), C(0xF), C(0xE)], op: NoOp /*LowRes*/ },
    Definition { pattern: [C(0x0), C(0x0), C(0xF), C(0xF)], op: NoOp /*HighRes*/ },
    Definition { pattern: [C(0xD), A(1),   C(0x3), C(0x0)], op: NoOp /*BigFont*/ },
    Definition { pattern: [C(0xF), A(1),   C(0x7), C(0x5)], op: NoOp /*SaveFlags*/},
    Definition { pattern: [C(0xF), A(1),   C(0x8), C(0x5)], op: NoOp /*LoadFlags*/},
];

pub const XOCHIP: &'static [Definition] = &[
    Definition { pattern: [C(0x5), A(1),   A(2),   C(0x2)], op: NoOp /*StashRange*/ },
    Definition { pattern: [C(0x5), A(1),   A(2),   C(0x3)], op: NoOp /*FetchRange*/ },
    Definition { pattern: [C(0xF), C(0x0), C(0x0), C(0x0)], op: NoOp /*LoadI16*/ },
    Definition { pattern: [C(0xF), A(1),   C(0x0), C(0x1)], op: NoOp /*SelectDrawPlane*/ },
    Definition { pattern: [C(0xF), A(1),   C(0x0), C(0x2)], op: NoOp /*StoreAudio*/ },
    Definition { pattern: [C(0x0), C(0x0), C(0xD), A(1)],   op: NoOp /*ScrollUp*/ },
];
<commit_msg>Added list of possible ISA extensions<commit_after>use instruction::{Definition, SrcKind, DestKind};
use instruction::Coding::*;
use instruction::OperationKind::*;

// Possible instruction set extensions to add:
//  http://www.mattmik.com/files/chip8/extensions/CHIP8ExtensionsReference.pdf
// Chip-8C, Chip-8I, Chip-10, Chip-8 II, Hi-Res Chip-8, Chip-8III, Chip-8E, Chip-8X, Chip-8Y,
// Chip-8M, Mega-Chip8

// Already added:
//  Original Chip8, SuperChip, XOChip

pub const CHIP8: &'static [Definition] = &[
    Definition { pattern: [C(0x0), C(0x0), C(0x0), C(0x0)], op: NoOp },
    Definition { pattern: [C(0x0), C(0x0), C(0xE), C(0x0)], op: Cls },
    Definition { pattern: [C(0x0), C(0x0), C(0xE), C(0xE)], op: Ret },
    Definition { pattern: [C(0x1), A(1),   A(1),   A(1)  ], op: Jump(SrcKind::Address12) },
    Definition { pattern: [C(0x2), A(1),   A(1),   A(1)  ], op: Call(SrcKind::Address12) },
    Definition { pattern: [C(0x3), A(1),   A(2),   A(2)  ], op: SkipEq(SrcKind::Register, SrcKind::Literal8) },
    Definition { pattern: [C(0x4), A(1),   A(2),   A(3)  ], op: SkipNotEq(SrcKind::Register, SrcKind::Literal8) },
    Definition { pattern: [C(0x5), A(1),   A(2),   C(0x0)], op: SkipEq(SrcKind::Register, SrcKind::Register) },
    Definition { pattern: [C(0x6), A(1),   A(2),   A(2)  ], op: Load(DestKind::Register, SrcKind::Literal8) },
    Definition { pattern: [C(0x7), A(1|2), A(3),   A(3)  ], op: Add(DestKind::Register, SrcKind::Register, SrcKind::Literal8) },
    Definition { pattern: [C(0x8), A(1),   A(2),   C(0x0)], op: Load(DestKind::Register, SrcKind::Register) },
    Definition { pattern: [C(0x8), A(1|2), A(4),   C(0x1)], op: Or(DestKind::Register, SrcKind::Register, SrcKind::Register) },
    Definition { pattern: [C(0x8), A(1|2), A(4),   C(0x2)], op: And(DestKind::Register, SrcKind::Register, SrcKind::Register) },
    Definition { pattern: [C(0x8), A(1|2), A(4),   C(0x3)], op: Xor(DestKind::Register, SrcKind::Register, SrcKind::Register) },
    Definition { pattern: [C(0x8), A(1|2), A(4),   C(0x4)], op: Add(DestKind::Register, SrcKind::Register, SrcKind::Register) },
    Definition { pattern: [C(0x8), A(1|2), A(4),   C(0x5)], op: Sub(DestKind::Register, SrcKind::Register, SrcKind::Register) },
    Definition { pattern: [C(0x8), A(1),   A(2),   C(0x6)], op: Shr(DestKind::Register, SrcKind::Register) },
    Definition { pattern: [C(0x8), A(1),   A(2|4), C(0x7)], op: Sub(DestKind::Register, SrcKind::Register, SrcKind::Register) },
    Definition { pattern: [C(0x8), A(1),   A(2),   C(0xE)], op: Shl(DestKind::Register, SrcKind::Register) },
    Definition { pattern: [C(0x9), A(1),   A(2),   C(0x0)], op: SkipNotEq(SrcKind::Register, SrcKind::Register) },
    Definition { pattern: [C(0xA), A(1),   A(1),   A(1)  ], op: Load(DestKind::I, SrcKind::Literal12 ) },
    Definition { pattern: [C(0xB), A(1),   A(1),   A(1)  ], op: JumpV0(SrcKind::Literal12 ) },
    Definition { pattern: [C(0xC), A(1),   A(4),   A(4)  ], op: Rand(DestKind::Register, SrcKind::Random, SrcKind::Literal8) },
    Definition { pattern: [C(0xD), A(1),   A(2),   A(3)  ], op: Sprite(SrcKind::Register, SrcKind::Register, SrcKind::Literal4) },
    Definition { pattern: [C(0xE), A(1),   C(0x9), C(0xE)], op: SkipKey(SrcKind::Register) },
    Definition { pattern: [C(0xE), A(1),   C(0xA), C(0x1)], op: SkipNotKey(SrcKind::Register) },
    Definition { pattern: [C(0xF), A(1),   C(0x0), C(0x7)], op: Load(DestKind::Register, SrcKind::DelayTimer) },
    Definition { pattern: [C(0xF), A(1),   C(0x0), C(0xA)], op: WaitKey(DestKind::Register, SrcKind::Literal4) },
    Definition { pattern: [C(0xF), A(2),   C(0x1), C(0x5)], op: Load(DestKind::DelayTimer, SrcKind::Register) },
    Definition { pattern: [C(0xF), A(2),   C(0x1), C(0x8)], op: Load(DestKind::SoundTimer, SrcKind::Register) },
    Definition { pattern: [C(0xF), A(4),   C(0x1), C(0xE)], op: Add(DestKind::I, SrcKind::I, SrcKind::Register) },
    Definition { pattern: [C(0xF), A(1),   C(0x2), C(0x9)], op: Font(SrcKind::Register) },
    Definition { pattern: [C(0xF), A(1),   C(0x3), C(0x3)], op: Bcd(SrcKind::Register) },
    Definition { pattern: [C(0xF), A(1),   C(0x5), C(0x5)], op: Stash(SrcKind::Register) },
    Definition { pattern: [C(0xF), A(1),   C(0x6), C(0x5)], op: Fetch(SrcKind::Register) },
];

pub const SUPERCHIP: &'static [Definition] = &[
    Definition { pattern: [C(0x0), C(0x0), C(0xC), A(1)],   op: NoOp /*ScrollDown(SrcKind::Literal4)*/ },
    Definition { pattern: [C(0x0), C(0x0), C(0xF), C(0xB)], op: NoOp /*ScrollRight*/ },
    Definition { pattern: [C(0x0), C(0x0), C(0xF), C(0xC)], op: NoOp /*ScrollLeft*/ },
    Definition { pattern: [C(0x0), C(0x0), C(0xF), C(0xD)], op: NoOp /*Exit*/ },
    Definition { pattern: [C(0x0), C(0x0), C(0xF), C(0xE)], op: NoOp /*LowRes*/ },
    Definition { pattern: [C(0x0), C(0x0), C(0xF), C(0xF)], op: NoOp /*HighRes*/ },
    Definition { pattern: [C(0xD), A(1),   C(0x3), C(0x0)], op: NoOp /*BigFont*/ },
    Definition { pattern: [C(0xF), A(1),   C(0x7), C(0x5)], op: NoOp /*SaveFlags*/},
    Definition { pattern: [C(0xF), A(1),   C(0x8), C(0x5)], op: NoOp /*LoadFlags*/},
];

pub const XOCHIP: &'static [Definition] = &[
    Definition { pattern: [C(0x5), A(1),   A(2),   C(0x2)], op: NoOp /*StashRange*/ },
    Definition { pattern: [C(0x5), A(1),   A(2),   C(0x3)], op: NoOp /*FetchRange*/ },
    Definition { pattern: [C(0xF), C(0x0), C(0x0), C(0x0)], op: NoOp /*LoadI16*/ },
    Definition { pattern: [C(0xF), A(1),   C(0x0), C(0x1)], op: NoOp /*SelectDrawPlane*/ },
    Definition { pattern: [C(0xF), A(1),   C(0x0), C(0x2)], op: NoOp /*StoreAudio*/ },
    Definition { pattern: [C(0x0), C(0x0), C(0xD), A(1)],   op: NoOp /*ScrollUp*/ },
];

pub const : &'static [Definition] = &[];
<|endoftext|>