<commit_before>#![crate_id = "regexp_re#0.1.0"]
#![crate_type = "dylib"]
#![license = "UNLICENSE"]
#![doc(html_root_url = "http://burntsushi.net/rustdoc/regexp_re")]

#![feature(macro_rules, phase, macro_registrar, managed_boxes, quote)]

//! This crate provides the `re!` macro. Its use is documented in the
//! [`regexp` crate](http://burntsushi.net/rustdoc/regexp/).

extern crate regexp;
extern crate syntax;

use syntax::ast::{Name, TokenTree, TTTok, DUMMY_NODE_ID};
use syntax::ast::{Expr, Expr_, ExprLit, LitStr, ExprVec};
use syntax::codemap::{Span, DUMMY_SP};
use syntax::ext::base::{SyntaxExtension,
                        ExtCtxt,
                        MacResult,
                        MRExpr,
                        NormalTT,
                        BasicMacroExpander};
use syntax::parse;
use syntax::parse::token;
use syntax::parse::token::{EOF, LIT_CHAR, IDENT};

use regexp::Regexp;
use regexp::program::{
    MaybeStatic, Flags,
    Inst, OneChar, CharClass, Any, Save, Jump, Split,
    Match, EmptyBegin, EmptyEnd, EmptyWordBoundary,
};

/// For the `re!` syntax extension. Do not use.
#[macro_registrar]
pub fn macro_registrar(reg: |Name, SyntaxExtension|) {
    reg(token::intern("re"),
        NormalTT(~BasicMacroExpander {
            expander: re_static,
            span: None,
        },
        None));
}

fn re_static(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> MacResult {
    let restr = match parse_one_str_lit(cx, tts) {
        Some(re) => re,
        None => return MacResult::dummy_expr(sp),
    };
    let re = match Regexp::new(restr.to_owned()) {
        Ok(re) => re,
        Err(err) => {
            cx.span_err(sp, err.to_str());
            return MacResult::dummy_expr(sp)
        }
    };

    let insts = as_expr_vec_static(cx, sp, re.p.insts.as_slice(),
        |cx, sp, inst| inst_to_expr(cx, sp, inst));
    let names = as_expr_vec_static(cx, sp, re.p.names.as_slice(),
        |cx, _, name| match name {
            &Some(ref name) => {
                let name = name.as_slice();
                quote_expr!(cx, Some(::std::str::Slice(&'static $name)))
            }
            &None => quote_expr!(cx, None),
        }
    );
    let prefix = as_expr_vec_static(cx, sp, re.p.prefix.as_slice(),
        |cx, _, &c| quote_expr!(cx, $c));
    MRExpr(quote_expr!(&*cx,
        regexp::Regexp {
            p: regexp::program::Program {
                regex: ::std::str::Slice($restr),
                insts: regexp::program::Static($insts),
                names: regexp::program::Static($names),
                prefix: regexp::program::Static($prefix),
            },
        }
    ))
}

#[doc(hidden)]
trait ToTokens {
    fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree>;
}

impl ToTokens for char {
    fn to_tokens(&self, _: &ExtCtxt) -> Vec<TokenTree> {
        vec!(TTTok(DUMMY_SP, LIT_CHAR((*self) as u32)))
    }
}

impl ToTokens for bool {
    fn to_tokens(&self, _: &ExtCtxt) -> Vec<TokenTree> {
        vec!(TTTok(DUMMY_SP, IDENT(token::str_to_ident(self.to_str()), false)))
    }
}

fn inst_to_expr(cx: &mut ExtCtxt, sp: Span, inst: &Inst) -> @Expr {
    match inst {
        &Match => quote_expr!(&*cx, regexp::program::Match),
        &OneChar(c, casei) =>
            quote_expr!(&*cx, regexp::program::OneChar($c, $casei)),
        &CharClass(ref ranges, flags) => {
            char_class_to_expr(cx, sp, ranges, flags)
        }
        &Any(multi) =>
            quote_expr!(&*cx, regexp::program::Any($multi)),
        &EmptyBegin(multi) =>
            quote_expr!(&*cx, regexp::program::EmptyBegin($multi)),
        &EmptyEnd(multi) =>
            quote_expr!(&*cx, regexp::program::EmptyEnd($multi)),
        &EmptyWordBoundary(multi) =>
            quote_expr!(&*cx, regexp::program::EmptyWordBoundary($multi)),
        &Save(slot) =>
            quote_expr!(&*cx, regexp::program::Save($slot)),
        &Jump(pc) =>
            quote_expr!(&*cx, regexp::program::Jump($pc)),
        &Split(x, y) =>
            quote_expr!(&*cx, regexp::program::Split($x, $y)),
    }
}

fn char_class_to_expr(cx: &mut ExtCtxt, sp: Span,
                      ranges: &MaybeStatic<(char, char)>,
                      flags: Flags) -> @Expr {
    let ranges = as_expr_vec_static(cx, sp, ranges.as_slice(),
        |cx, _, &(x, y)| quote_expr!(&*cx, ($x, $y)));
    quote_expr!(&*cx,
        regexp::program::CharClass(regexp::program::Static($ranges), $flags))
}

fn as_expr_vec_static<T>(cx: &mut ExtCtxt, sp: Span, xs: &[T],
                         to_expr: |&mut ExtCtxt, Span, &T| -> @Expr) -> @Expr {
    let mut exprs = vec!();
    for x in xs.iter() {
        exprs.push(to_expr(&mut *cx, sp, x))
    }
    let vec_exprs = as_expr(sp, ExprVec(exprs));
    quote_expr!(&*cx, &'static $vec_exprs)
}

fn as_expr(sp: Span, e: Expr_) -> @Expr {
    @Expr {
        id: DUMMY_NODE_ID,
        node: e,
        span: sp,
    }
}

fn parse_one_str_lit(cx: &mut ExtCtxt, tts: &[TokenTree]) -> Option<~str> {
    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(),
                                                Vec::from_slice(tts));
    let entry = parser.parse_expr();

    let lit = match entry.node {
        ExprLit(lit) => {
            match lit.node {
                LitStr(ref s, _) => s.clone(),
                _ => {
                    cx.span_err(entry.span, "expected string literal");
                    return None
                }
            }
        }
        _ => {
            cx.span_err(entry.span, "expected string literal");
            return None
        }
    };
    if !parser.eat(&EOF) {
        cx.span_err(parser.span, "only one string literal allowed");
        return None;
    }
    Some(lit.to_str().to_owned())
}
<commit_msg>some explanation for the ToTokens trait<commit_after>#![crate_id = "regexp_re#0.1.0"]
#![crate_type = "dylib"]
#![license = "UNLICENSE"]
#![doc(html_root_url = "http://burntsushi.net/rustdoc/regexp_re")]

#![feature(macro_rules, phase, macro_registrar, managed_boxes, quote)]

//! This crate provides the `re!` macro. Its use is documented in the
//! [`regexp` crate](http://burntsushi.net/rustdoc/regexp/).

extern crate regexp;
extern crate syntax;

use syntax::ast::{Name, TokenTree, TTTok, DUMMY_NODE_ID};
use syntax::ast::{Expr, Expr_, ExprLit, LitStr, ExprVec};
use syntax::codemap::{Span, DUMMY_SP};
use syntax::ext::base::{
    SyntaxExtension, ExtCtxt, MacResult, MRExpr, NormalTT, BasicMacroExpander,
};
use syntax::parse;
use syntax::parse::token;
use syntax::parse::token::{EOF, LIT_CHAR, IDENT};

use regexp::Regexp;
use regexp::program::{
    MaybeStatic, Flags,
    Inst, OneChar, CharClass, Any, Save, Jump, Split,
    Match, EmptyBegin, EmptyEnd, EmptyWordBoundary,
};

/// For the `re!` syntax extension. Do not use.
#[macro_registrar]
pub fn macro_registrar(reg: |Name, SyntaxExtension|) {
    reg(token::intern("re"),
        NormalTT(~BasicMacroExpander {
            expander: re_static,
            span: None,
        },
        None));
}

fn re_static(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> MacResult {
    let restr = match parse_one_str_lit(cx, tts) {
        Some(re) => re,
        None => return MacResult::dummy_expr(sp),
    };
    let re = match Regexp::new(restr.to_owned()) {
        Ok(re) => re,
        Err(err) => {
            cx.span_err(sp, err.to_str());
            return MacResult::dummy_expr(sp)
        }
    };

    let insts = as_expr_vec_static(cx, sp, re.p.insts.as_slice(),
        |cx, sp, inst| inst_to_expr(cx, sp, inst));
    let names = as_expr_vec_static(cx, sp, re.p.names.as_slice(),
        |cx, _, name| match name {
            &Some(ref name) => {
                let name = name.as_slice();
                quote_expr!(cx, Some(::std::str::Slice(&'static $name)))
            }
            &None => quote_expr!(cx, None),
        }
    );
    let prefix = as_expr_vec_static(cx, sp, re.p.prefix.as_slice(),
        |cx, _, &c| quote_expr!(cx, $c));
    MRExpr(quote_expr!(&*cx,
        regexp::Regexp {
            p: regexp::program::Program {
                regex: ::std::str::Slice($restr),
                insts: regexp::program::Static($insts),
                names: regexp::program::Static($names),
                prefix: regexp::program::Static($prefix),
            },
        }
    ))
}

// This trait is defined in the quote module in the syntax crate, but I
// don't think it's exported.
// Interestingly, quote_expr! only requires that a 'to_tokens' method be
// defined rather than satisfying a particular trait.
// I think these should be included in the `syntax` crate anyway.
#[doc(hidden)]
trait ToTokens {
    fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree>;
}

impl ToTokens for char {
    fn to_tokens(&self, _: &ExtCtxt) -> Vec<TokenTree> {
        vec!(TTTok(DUMMY_SP, LIT_CHAR((*self) as u32)))
    }
}

impl ToTokens for bool {
    fn to_tokens(&self, _: &ExtCtxt) -> Vec<TokenTree> {
        vec!(TTTok(DUMMY_SP, IDENT(token::str_to_ident(self.to_str()), false)))
    }
}

fn inst_to_expr(cx: &mut ExtCtxt, sp: Span, inst: &Inst) -> @Expr {
    match inst {
        &Match => quote_expr!(&*cx, regexp::program::Match),
        &OneChar(c, casei) =>
            quote_expr!(&*cx, regexp::program::OneChar($c, $casei)),
        &CharClass(ref ranges, flags) => {
            char_class_to_expr(cx, sp, ranges, flags)
        }
        &Any(multi) =>
            quote_expr!(&*cx, regexp::program::Any($multi)),
        &EmptyBegin(multi) =>
            quote_expr!(&*cx, regexp::program::EmptyBegin($multi)),
        &EmptyEnd(multi) =>
            quote_expr!(&*cx, regexp::program::EmptyEnd($multi)),
        &EmptyWordBoundary(multi) =>
            quote_expr!(&*cx, regexp::program::EmptyWordBoundary($multi)),
        &Save(slot) =>
            quote_expr!(&*cx, regexp::program::Save($slot)),
        &Jump(pc) =>
            quote_expr!(&*cx, regexp::program::Jump($pc)),
        &Split(x, y) =>
            quote_expr!(&*cx, regexp::program::Split($x, $y)),
    }
}

fn char_class_to_expr(cx: &mut ExtCtxt, sp: Span,
                      ranges: &MaybeStatic<(char, char)>,
                      flags: Flags) -> @Expr {
    let ranges = as_expr_vec_static(cx, sp, ranges.as_slice(),
        |cx, _, &(x, y)| quote_expr!(&*cx, ($x, $y)));
    quote_expr!(&*cx,
        regexp::program::CharClass(regexp::program::Static($ranges), $flags))
}

fn as_expr_vec_static<T>(cx: &mut ExtCtxt, sp: Span, xs: &[T],
                         to_expr: |&mut ExtCtxt, Span, &T| -> @Expr) -> @Expr {
    let mut exprs = vec!();
    for x in xs.iter() {
        exprs.push(to_expr(&mut *cx, sp, x))
    }
    let vec_exprs = as_expr(sp, ExprVec(exprs));
    quote_expr!(&*cx, &'static $vec_exprs)
}

fn as_expr(sp: Span, e: Expr_) -> @Expr {
    @Expr {
        id: DUMMY_NODE_ID,
        node: e,
        span: sp,
    }
}

fn parse_one_str_lit(cx: &mut ExtCtxt, tts: &[TokenTree]) -> Option<~str> {
    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(),
                                                Vec::from_slice(tts));
    let entry = parser.parse_expr();

    let lit = match entry.node {
        ExprLit(lit) => {
            match lit.node {
                LitStr(ref s, _) => s.clone(),
                _ => {
                    cx.span_err(entry.span, "expected string literal");
                    return None
                }
            }
        }
        _ => {
            cx.span_err(entry.span, "expected string literal");
            return None
        }
    };
    if !parser.eat(&EOF) {
        cx.span_err(parser.span, "only one string literal allowed");
        return None;
    }
    Some(lit.to_str().to_owned())
}
<|endoftext|>


<commit_before>import std::map;
import std::map::hashmap;
import std::uint;
import std::int;
import std::vec;
import std::option::none;
import front::ast;
import front::ast::ty;
import front::ast::pat;
import middle::tstate::ann::ts_ann;

import middle::fold;
import middle::fold::respan;

import std::io::stdout;
import std::io::str_writer;
import std::io::string_writer;
import pretty::pprust::print_block;
import pretty::pprust::print_expr;
import pretty::pprust::print_decl;
import pretty::pprust::print_fn;
import pretty::pprust::print_type;
import pretty::pprust::mo_untyped;
import pretty::pp::mkstate;

type filename = str;
type span = rec(uint lo, uint hi);
type spanned[T] = rec(T node, span span);
type flag = hashmap[str, ()];

tag ty_mach {
    ty_i8;
    ty_i16;
    ty_i32;
    ty_i64;

    ty_u8;
    ty_u16;
    ty_u32;
    ty_u64;

    ty_f32;
    ty_f64;
}

fn ty_mach_to_str(ty_mach tm) -> str {
    alt (tm) {
        case (ty_u8) { ret "u8"; }
        case (ty_u16) { ret "u16"; }
        case (ty_u32) { ret "u32"; }
        case (ty_u64) { ret "u64"; }

        case (ty_i8) { ret "i8"; }
        case (ty_i16) { ret "i16"; }
        case (ty_i32) { ret "i32"; }
        case (ty_i64) { ret "i64"; }

        case (ty_f32) { ret "f32"; }
        case (ty_f64) { ret "f64"; }
    }
}

fn new_str_hash[V]() -> std::map::hashmap[str,V] {
    let std::map::hashfn[str] hasher = std::str::hash;
    let std::map::eqfn[str] eqer = std::str::eq;
    ret std::map::mk_hashmap[str,V](hasher, eqer);
}

fn def_eq(&ast::def_id a, &ast::def_id b) -> bool {
    ret a._0 == b._0 && a._1 == b._1;
}

fn hash_def(&ast::def_id d) -> uint {
    auto h = 5381u;
    h = ((h << 5u) + h) ^ (d._0 as uint);
    h = ((h << 5u) + h) ^ (d._1 as uint);
    ret h;
}

fn new_def_hash[V]() -> std::map::hashmap[ast::def_id,V] {
    let std::map::hashfn[ast::def_id] hasher = hash_def;
    let std::map::eqfn[ast::def_id] eqer = def_eq;
    ret std::map::mk_hashmap[ast::def_id,V](hasher, eqer);
}

fn new_int_hash[V]() -> std::map::hashmap[int,V] {
    fn hash_int(&int x) -> uint { ret x as uint; }
    fn eq_int(&int a, &int b) -> bool { ret a == b; }
    auto hasher = hash_int;
    auto eqer = eq_int;
    ret std::map::mk_hashmap[int,V](hasher, eqer);
}

fn new_uint_hash[V]() -> std::map::hashmap[uint,V] {
    fn hash_uint(&uint x) -> uint { ret x; }
    fn eq_uint(&uint a, &uint b) -> bool { ret a == b; }
    auto hasher = hash_uint;
    auto eqer = eq_uint;
    ret std::map::mk_hashmap[uint,V](hasher, eqer);
}

fn istr(int i) -> str {
    ret int::to_str(i, 10u);
}

fn uistr(uint i) -> str {
    ret uint::to_str(i, 10u);
}

fn elt_expr(&ast::elt e) -> @ast::expr { ret e.expr; }

fn elt_exprs(&vec[ast::elt] elts) -> vec[@ast::expr] {
    auto f = elt_expr;
    ret vec::map[ast::elt, @ast::expr](f, elts);
}

fn field_expr(&ast::field f) -> @ast::expr { ret f.expr; }

fn field_exprs(vec[ast::field] fields) -> vec [@ast::expr] {
    auto f = field_expr;
    ret vec::map[ast::field, @ast::expr](f, fields);
}

fn expr_to_str(&@ast::expr e) -> str {
  let str_writer s = string_writer();
  auto out_ = mkstate(s.get_writer(), 80u);
  auto out = @rec(s=out_,
                  comments=none[vec[front::lexer::cmnt]],
                  mutable cur_cmnt=0u,
                  mode=mo_untyped);
  print_expr(out, e);
  ret s.get_str();
}

fn ty_to_str(&ty t) -> str {
  let str_writer s = string_writer();
  auto out_ = mkstate(s.get_writer(), 80u);
  auto out = @rec(s=out_,
                  comments=none[vec[front::lexer::cmnt]],
                  mutable cur_cmnt=0u,
                  mode=mo_untyped);
  print_type(out, @t);
  ret s.get_str();
}

fn log_expr(&ast::expr e) -> () {
    log(expr_to_str(@e));
}

fn log_expr_err(&ast::expr e) -> () {
    log_err(expr_to_str(@e));
}

fn log_ty_err(&ty t) -> () {
    log_err(ty_to_str(t));
}

fn log_pat_err(&@pat p) -> () {
    log_err(pretty::pprust::pat_to_str(p));
}

fn block_to_str(&ast::block b) -> str {
  let str_writer s = string_writer();
  auto out_ = mkstate(s.get_writer(), 80u);
  auto out = @rec(s=out_,
                  comments=none[vec[front::lexer::cmnt]],
                  mutable cur_cmnt=0u,
                  mode=mo_untyped);

  print_block(out, b);
  ret s.get_str();
}

fn log_block(&ast::block b) -> () {
    log(block_to_str(b));
}

fn log_block_err(&ast::block b) -> () {
    log_err(block_to_str(b));
}

fn fun_to_str(&ast::_fn f, str name, vec[ast::ty_param] params) -> str {
 let str_writer s = string_writer();
  auto out_ = mkstate(s.get_writer(), 80u);
  auto out = @rec(s=out_,
                  comments=none[vec[front::lexer::cmnt]],
                  mutable cur_cmnt=0u,
                  mode=mo_untyped);

  print_fn(out, f.decl, name, params);
  ret s.get_str();
}

fn log_fn(&ast::_fn f, str name, vec[ast::ty_param] params) -> () {
    log(fun_to_str(f, name, params));
}

fn log_fn_err(&ast::_fn f, str name, vec[ast::ty_param] params) -> () {
    log_err(fun_to_str(f, name, params));
}

fn stmt_to_str(&ast::stmt st) -> str {
  let str_writer s = string_writer();
  auto out_ = mkstate(s.get_writer(), 80u);
  auto out = @rec(s=out_,
                  comments=none[vec[front::lexer::cmnt]],
                  mutable cur_cmnt=0u,
                  mode=mo_untyped);
  alt (st.node) {
    case (ast::stmt_decl(?decl,_)) {
      print_decl(out, decl);
    }
    case (ast::stmt_expr(?ex,_)) {
      print_expr(out, ex);
    }
    case (_) { /* do nothing */ }
  }
  ret s.get_str();
}

fn log_stmt(&ast::stmt st) -> () {
    log(stmt_to_str(st));
}

fn log_stmt_err(&ast::stmt st) -> () {
    log_err(stmt_to_str(st));
}

fn decl_lhs(@ast::decl d) -> ast::def_id {
    alt (d.node) {
        case (ast::decl_local(?l)) {
            ret l.id;
        }
        case (ast::decl_item(?an_item)) {
            alt (an_item.node) {
                case (ast::item_const(_,_,_,?d,_)) {
                    ret d;
                }
                case (ast::item_fn(_,_,_,?d,_)) {
                    ret d;
                }
                case (ast::item_mod(_,_,?d)) {
                    ret d;
                }
                case (ast::item_native_mod(_,_,?d)) {
                    ret d;
                }
                case (ast::item_ty(_,_,_,?d,_)) {
                    ret d;
                }
                case (ast::item_tag(_,_,_,?d,_)) {
                    ret d;
                }
                case (ast::item_obj(_,_,_,?d,_)) {
                    ret d.ctor; /* This doesn't really make sense */
                }
            }
        }
    }
}

fn has_nonlocal_exits(&ast::block b) -> bool {
    /* overkill, but just passing around a mutable bool doesn't seem
       to work in rustboot */
    auto has_exits = new_str_hash[()]();

   fn set_break(&flag f, &span sp, &ast::ann a) -> @ast::expr {
        f.insert("foo", ());
        ret @respan(sp, ast::expr_break(a));
    }
    fn set_cont(&flag f, &span sp, &ast::ann a) -> @ast::expr {
        f.insert("foo", ());
        ret @respan(sp, ast::expr_cont(a));
    }
    fn check_b(&flag f) -> bool {
        ret (f.size() == 0u);
    }

    auto fld0 = fold::new_identity_fold[flag]();

    fld0 = @rec(fold_expr_break = bind set_break(_,_,_),
                fold_expr_cont  = bind set_cont(_,_,_),
                keep_going      = bind check_b(_) with *fld0);
    fold::fold_block[flag](has_exits, fld0, b);

    ret (has_exits.size() > 0u);
}

//
// 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 $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//
<commit_msg>add a bunch more logging things<commit_after>import std::map;
import std::map::hashmap;
import std::uint;
import std::int;
import std::vec;
import std::option::none;
import std::option::some;
import front::ast;
import front::ast::ty;
import front::ast::pat;
import middle::tstate::ann::ts_ann;

import middle::fold;
import middle::fold::respan;

import std::io::stdout;
import std::io::str_writer;
import std::io::string_writer;
import pretty::pprust::print_block;
import pretty::pprust::print_item;
import pretty::pprust::print_expr;
import pretty::pprust::print_decl;
import pretty::pprust::print_fn;
import pretty::pprust::print_type;
import pretty::pprust::mo_untyped;
import pretty::pp::mkstate;

type filename = str;
type span = rec(uint lo, uint hi);
type spanned[T] = rec(T node, span span);
type flag = hashmap[str, ()];

tag ty_mach {
    ty_i8;
    ty_i16;
    ty_i32;
    ty_i64;

    ty_u8;
    ty_u16;
    ty_u32;
    ty_u64;

    ty_f32;
    ty_f64;
}

fn ty_mach_to_str(ty_mach tm) -> str {
    alt (tm) {
        case (ty_u8) { ret "u8"; }
        case (ty_u16) { ret "u16"; }
        case (ty_u32) { ret "u32"; }
        case (ty_u64) { ret "u64"; }

        case (ty_i8) { ret "i8"; }
        case (ty_i16) { ret "i16"; }
        case (ty_i32) { ret "i32"; }
        case (ty_i64) { ret "i64"; }

        case (ty_f32) { ret "f32"; }
        case (ty_f64) { ret "f64"; }
    }
}

fn new_str_hash[V]() -> std::map::hashmap[str,V] {
    let std::map::hashfn[str] hasher = std::str::hash;
    let std::map::eqfn[str] eqer = std::str::eq;
    ret std::map::mk_hashmap[str,V](hasher, eqer);
}

fn def_eq(&ast::def_id a, &ast::def_id b) -> bool {
    ret a._0 == b._0 && a._1 == b._1;
}

fn hash_def(&ast::def_id d) -> uint {
    auto h = 5381u;
    h = ((h << 5u) + h) ^ (d._0 as uint);
    h = ((h << 5u) + h) ^ (d._1 as uint);
    ret h;
}

fn new_def_hash[V]() -> std::map::hashmap[ast::def_id,V] {
    let std::map::hashfn[ast::def_id] hasher = hash_def;
    let std::map::eqfn[ast::def_id] eqer = def_eq;
    ret std::map::mk_hashmap[ast::def_id,V](hasher, eqer);
}

fn new_int_hash[V]() -> std::map::hashmap[int,V] {
    fn hash_int(&int x) -> uint { ret x as uint; }
    fn eq_int(&int a, &int b) -> bool { ret a == b; }
    auto hasher = hash_int;
    auto eqer = eq_int;
    ret std::map::mk_hashmap[int,V](hasher, eqer);
}

fn new_uint_hash[V]() -> std::map::hashmap[uint,V] {
    fn hash_uint(&uint x) -> uint { ret x; }
    fn eq_uint(&uint a, &uint b) -> bool { ret a == b; }
    auto hasher = hash_uint;
    auto eqer = eq_uint;
    ret std::map::mk_hashmap[uint,V](hasher, eqer);
}

fn istr(int i) -> str {
    ret int::to_str(i, 10u);
}

fn uistr(uint i) -> str {
    ret uint::to_str(i, 10u);
}

fn elt_expr(&ast::elt e) -> @ast::expr { ret e.expr; }

fn elt_exprs(&vec[ast::elt] elts) -> vec[@ast::expr] {
    auto f = elt_expr;
    ret vec::map[ast::elt, @ast::expr](f, elts);
}

fn field_expr(&ast::field f) -> @ast::expr { ret f.expr; }

fn field_exprs(vec[ast::field] fields) -> vec [@ast::expr] {
    auto f = field_expr;
    ret vec::map[ast::field, @ast::expr](f, fields);
}

fn expr_to_str(&@ast::expr e) -> str {
  let str_writer s = string_writer();
  auto out_ = mkstate(s.get_writer(), 80u);
  auto out = @rec(s=out_,
                  comments=none[vec[front::lexer::cmnt]],
                  mutable cur_cmnt=0u,
                  mode=mo_untyped);
  print_expr(out, e);
  ret s.get_str();
}

fn ty_to_str(&ty t) -> str {
  let str_writer s = string_writer();
  auto out_ = mkstate(s.get_writer(), 80u);
  auto out = @rec(s=out_,
                  comments=none[vec[front::lexer::cmnt]],
                  mutable cur_cmnt=0u,
                  mode=mo_untyped);
  print_type(out, @t);
  ret s.get_str();
}

fn log_expr(&ast::expr e) -> () {
    log(expr_to_str(@e));
}

fn log_expr_err(&ast::expr e) -> () {
    log_err(expr_to_str(@e));
}

fn log_ty_err(&ty t) -> () {
    log_err(ty_to_str(t));
}

fn log_pat_err(&@pat p) -> () {
    log_err(pretty::pprust::pat_to_str(p));
}

fn block_to_str(&ast::block b) -> str {
  let str_writer s = string_writer();
  auto out_ = mkstate(s.get_writer(), 80u);
  auto out = @rec(s=out_,
                  comments=none[vec[front::lexer::cmnt]],
                  mutable cur_cmnt=0u,
                  mode=mo_untyped);

  print_block(out, b);
  ret s.get_str();
}

fn item_to_str(&@ast::item i) -> str {
  let str_writer s = string_writer();
  auto out_ = mkstate(s.get_writer(), 80u);
  auto out = @rec(s=out_,
                  comments=none[vec[front::lexer::cmnt]],
                  mutable cur_cmnt=0u);

  print_item(out, i);
  ret s.get_str();
}

fn log_block(&ast::block b) -> () {
    log(block_to_str(b));
}

fn log_block_err(&ast::block b) -> () {
    log_err(block_to_str(b));
}

fn log_item_err(&@ast::item i) -> () {
    log_err(item_to_str(i));
}

fn log_ann(&ast::ann a) -> () {
    alt (a) {
        case (ast::ann_none(_)) {
            log("ann_none");
        }
        case (ast::ann_type(_,_,_,_)) {
            log("ann_type");
        }
    }
}

fn fun_to_str(&ast::_fn f, str name, vec[ast::ty_param] params) -> str {
 let str_writer s = string_writer();
  auto out_ = mkstate(s.get_writer(), 80u);
  auto out = @rec(s=out_,
                  comments=none[vec[front::lexer::cmnt]],
                  mutable cur_cmnt=0u,
                  mode=mo_untyped);

  print_fn(out, f.decl, name, params);
  ret s.get_str();
}

fn log_fn(&ast::_fn f, str name, vec[ast::ty_param] params) -> () {
    log(fun_to_str(f, name, params));
}

fn log_fn_err(&ast::_fn f, str name, vec[ast::ty_param] params) -> () {
    log_err(fun_to_str(f, name, params));
}

fn stmt_to_str(&ast::stmt st) -> str {
  let str_writer s = string_writer();
  auto out_ = mkstate(s.get_writer(), 80u);
  auto out = @rec(s=out_,
                  comments=none[vec[front::lexer::cmnt]],
                  mutable cur_cmnt=0u,
                  mode=mo_untyped);
  alt (st.node) {
    case (ast::stmt_decl(?decl,_)) {
      print_decl(out, decl);
    }
    case (ast::stmt_expr(?ex,_)) {
      print_expr(out, ex);
    }
    case (_) { /* do nothing */ }
  }
  ret s.get_str();
}

fn log_stmt(&ast::stmt st) -> () {
    log(stmt_to_str(st));
}

fn log_stmt_err(&ast::stmt st) -> () {
    log_err(stmt_to_str(st));
}

fn decl_lhs(@ast::decl d) -> ast::def_id {
    alt (d.node) {
        case (ast::decl_local(?l)) {
            ret l.id;
        }
        case (ast::decl_item(?an_item)) {
            alt (an_item.node) {
                case (ast::item_const(_,_,_,?d,_)) {
                    ret d;
                }
                case (ast::item_fn(_,_,_,?d,_)) {
                    ret d;
                }
                case (ast::item_mod(_,_,?d)) {
                    ret d;
                }
                case (ast::item_native_mod(_,_,?d)) {
                    ret d;
                }
                case (ast::item_ty(_,_,_,?d,_)) {
                    ret d;
                }
                case (ast::item_tag(_,_,_,?d,_)) {
                    ret d;
                }
                case (ast::item_obj(_,_,_,?d,_)) {
                    ret d.ctor; /* This doesn't really make sense */
                }
            }
        }
    }
}

fn has_nonlocal_exits(&ast::block b) -> bool {
    /* overkill, but just passing around a mutable bool doesn't seem
       to work in rustboot */
    auto has_exits = new_str_hash[()]();

   fn set_break(&flag f, &span sp, &ast::ann a) -> @ast::expr {
        f.insert("foo", ());
        ret @respan(sp, ast::expr_break(a));
    }
    fn set_cont(&flag f, &span sp, &ast::ann a) -> @ast::expr {
        f.insert("foo", ());
        ret @respan(sp, ast::expr_cont(a));
    }
    fn check_b(&flag f) -> bool {
        ret (f.size() == 0u);
    }

    auto fld0 = fold::new_identity_fold[flag]();

    fld0 = @rec(fold_expr_break = bind set_break(_,_,_),
                fold_expr_cont  = bind set_cont(_,_,_),
                keep_going      = bind check_b(_) with *fld0);
    fold::fold_block[flag](has_exits, fld0, b);

    ret (has_exits.size() > 0u);
}

fn local_rhs_span(&@ast::local l, &ast::span def) -> ast::span {
    alt (l.init) {
        case (some[ast::initializer](?i)) { ret i.expr.span; }
        case (_) { ret def; }
    }
}

//
// 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 $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//
<|endoftext|>


<commit_before>use cairo;
use markup5ever::{local_name, LocalName};

use crate::drawing_ctx::DrawingCtx;
use crate::error::NodeError;
use crate::node::{NodeResult, NodeTrait, RsvgNode};
use crate::parsers::ParseError;
use crate::property_bag::PropertyBag;
use crate::surface_utils::shared_surface::SharedImageSurface;

use super::context::{FilterContext, FilterOutput, FilterResult};
use super::input::Input;
use super::{Filter, FilterError, PrimitiveWithInput};

/// Enumeration of the possible blending modes.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
enum Mode {
    Normal,
    Multiply,
    Screen,
    Darken,
    Lighten,
}

/// The `feBlend` filter primitive.
pub struct Blend {
    base: PrimitiveWithInput,
    in2: Option<Input>,
    mode: Mode,
}

impl Default for Blend {
    /// Constructs a new `Blend` with empty properties.
    #[inline]
    fn default() -> Blend {
        Blend {
            base: PrimitiveWithInput::new::<Self>(),
            in2: None,
            mode: Mode::Normal,
        }
    }
}

impl NodeTrait for Blend {
    impl_node_as_filter!();

    fn set_atts(&mut self, parent: Option<&RsvgNode>, pbag: &PropertyBag<'_>) -> NodeResult {
        self.base.set_atts(parent, pbag)?;

        for (attr, value) in pbag.iter() {
            match attr {
                local_name!("in2") => {
                    self.in2 = Some(Input::parse(attr, value)?);
                }
                local_name!("mode") => self.mode = Mode::parse(attr, value)?,
                _ => (),
            }
        }

        Ok(())
    }
}

impl Filter for Blend {
    fn render(
        &self,
        _node: &RsvgNode,
        ctx: &FilterContext,
        draw_ctx: &mut DrawingCtx,
    ) -> Result<FilterResult, FilterError> {
        let input = self.base.get_input(ctx, draw_ctx)?;
        let input_2 = ctx.get_input(draw_ctx, self.in2.as_ref())?;
        let bounds = self
            .base
            .get_bounds(ctx)
            .add_input(&input)
            .add_input(&input_2)
            .into_irect(draw_ctx);

        // If we're combining two alpha-only surfaces, the result is alpha-only. Otherwise the
        // result is whatever the non-alpha-only type we're working on (which can be either sRGB or
        // linear sRGB depending on color-interpolation-filters).
        let surface_type = if input.surface().is_alpha_only() {
            input_2.surface().surface_type()
        } else {
            if !input_2.surface().is_alpha_only() {
                // All surface types should match (this is enforced by get_input()).
                assert_eq!(
                    input_2.surface().surface_type(),
                    input.surface().surface_type()
                );
            }

            input.surface().surface_type()
        };

        let output_surface = input_2.surface().copy_surface(bounds)?;
        {
            let cr = cairo::Context::new(&output_surface);
            cr.rectangle(
                bounds.x0 as f64,
                bounds.y0 as f64,
                (bounds.x1 - bounds.x0) as f64,
                (bounds.y1 - bounds.y0) as f64,
            );
            cr.clip();

            input.surface().set_as_source_surface(&cr, 0f64, 0f64);
            cr.set_operator(self.mode.into());
            cr.paint();
        }

        Ok(FilterResult {
            name: self.base.result.clone(),
            output: FilterOutput {
                surface: SharedImageSurface::new(output_surface, surface_type)?,
                bounds,
            },
        })
    }

    #[inline]
    fn is_affected_by_color_interpolation_filters(&self) -> bool {
        true
    }
}

impl Mode {
    fn parse(attr: LocalName, s: &str) -> Result<Self, NodeError> {
        match s {
            "normal" => Ok(Mode::Normal),
            "multiply" => Ok(Mode::Multiply),
            "screen" => Ok(Mode::Screen),
            "darken" => Ok(Mode::Darken),
            "lighten" => Ok(Mode::Lighten),
            _ => Err(NodeError::parse_error(
                attr,
                ParseError::new("invalid value"),
            )),
        }
    }
}

impl From<Mode> for cairo::Operator {
    #[inline]
    fn from(x: Mode) -> Self {
        match x {
            Mode::Normal => cairo::Operator::Over,
            Mode::Multiply => cairo::Operator::Multiply,
            Mode::Screen => cairo::Operator::Screen,
            Mode::Darken => cairo::Operator::Darken,
            Mode::Lighten => cairo::Operator::Lighten,
        }
    }
}
<commit_msg>(#500) Added additional SVG blend-modes for feBlend<commit_after>use cairo;
use markup5ever::{local_name, LocalName};

use crate::drawing_ctx::DrawingCtx;
use crate::error::NodeError;
use crate::node::{NodeResult, NodeTrait, RsvgNode};
use crate::parsers::ParseError;
use crate::property_bag::PropertyBag;
use crate::surface_utils::shared_surface::SharedImageSurface;

use super::context::{FilterContext, FilterOutput, FilterResult};
use super::input::Input;
use super::{Filter, FilterError, PrimitiveWithInput};

/// Enumeration of the possible blending modes.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
enum Mode {
    Normal,
    Multiply,
    Screen,
    Darken,
    Lighten,
    Overlay,
    ColorDodge,
    ColorBurn,
    HardLight,
    SoftLight,
    Difference,
    Exclusion,
    HslHue,
    HslSaturation,
    HslColor,
    HslLuminosity,
}

/// The `feBlend` filter primitive.
pub struct Blend {
    base: PrimitiveWithInput,
    in2: Option<Input>,
    mode: Mode,
}

impl Default for Blend {
    /// Constructs a new `Blend` with empty properties.
    #[inline]
    fn default() -> Blend {
        Blend {
            base: PrimitiveWithInput::new::<Self>(),
            in2: None,
            mode: Mode::Normal,
        }
    }
}

impl NodeTrait for Blend {
    impl_node_as_filter!();

    fn set_atts(&mut self, parent: Option<&RsvgNode>, pbag: &PropertyBag<'_>) -> NodeResult {
        self.base.set_atts(parent, pbag)?;

        for (attr, value) in pbag.iter() {
            match attr {
                local_name!("in2") => {
                    self.in2 = Some(Input::parse(attr, value)?);
                }
                local_name!("mode") => self.mode = Mode::parse(attr, value)?,
                _ => (),
            }
        }

        Ok(())
    }
}

impl Filter for Blend {
    fn render(
        &self,
        _node: &RsvgNode,
        ctx: &FilterContext,
        draw_ctx: &mut DrawingCtx,
    ) -> Result<FilterResult, FilterError> {
        let input = self.base.get_input(ctx, draw_ctx)?;
        let input_2 = ctx.get_input(draw_ctx, self.in2.as_ref())?;
        let bounds = self
            .base
            .get_bounds(ctx)
            .add_input(&input)
            .add_input(&input_2)
            .into_irect(draw_ctx);

        // If we're combining two alpha-only surfaces, the result is alpha-only. Otherwise the
        // result is whatever the non-alpha-only type we're working on (which can be either sRGB or
        // linear sRGB depending on color-interpolation-filters).
        let surface_type = if input.surface().is_alpha_only() {
            input_2.surface().surface_type()
        } else {
            if !input_2.surface().is_alpha_only() {
                // All surface types should match (this is enforced by get_input()).
                assert_eq!(
                    input_2.surface().surface_type(),
                    input.surface().surface_type()
                );
            }

            input.surface().surface_type()
        };

        let output_surface = input_2.surface().copy_surface(bounds)?;
        {
            let cr = cairo::Context::new(&output_surface);
            cr.rectangle(
                bounds.x0 as f64,
                bounds.y0 as f64,
                (bounds.x1 - bounds.x0) as f64,
                (bounds.y1 - bounds.y0) as f64,
            );
            cr.clip();

            input.surface().set_as_source_surface(&cr, 0f64, 0f64);
            cr.set_operator(self.mode.into());
            cr.paint();
        }

        Ok(FilterResult {
            name: self.base.result.clone(),
            output: FilterOutput {
                surface: SharedImageSurface::new(output_surface, surface_type)?,
                bounds,
            },
        })
    }

    #[inline]
    fn is_affected_by_color_interpolation_filters(&self) -> bool {
        true
    }
}

impl Mode {
    fn parse(attr: LocalName, s: &str) -> Result<Self, NodeError> {
        match s {
            "normal" => Ok(Mode::Normal),
            "multiply" => Ok(Mode::Multiply),
            "screen" => Ok(Mode::Screen),
            "darken" => Ok(Mode::Darken),
            "lighten" => Ok(Mode::Lighten),
            "overlay" => Ok(Mode::Overlay),
            "color-dodge" => Ok(Mode::ColorDodge),
            "color-burn" => Ok(Mode::ColorBurn),
            "hard-light" => Ok(Mode::HardLight),
            "soft-light" => Ok(Mode::SoftLight),
            "difference" => Ok(Mode::Difference),
            "exclusion" => Ok(Mode::Exclusion),
            "hue" => Ok(Mode::HslHue),
            "saturation" => Ok(Mode::HslSaturation),
            "color" => Ok(Mode::HslColor),
            "luminosity" => Ok(Mode::HslLuminosity),
            _ => Err(NodeError::parse_error(
                attr,
                ParseError::new("invalid value"),
            )),
        }
    }
}

impl From<Mode> for cairo::Operator {
    #[inline]
    fn from(x: Mode) -> Self {
        match x {
            Mode::Normal => cairo::Operator::Over,
            Mode::Multiply => cairo::Operator::Multiply,
            Mode::Screen => cairo::Operator::Screen,
            Mode::Darken => cairo::Operator::Darken,
            Mode::Lighten => cairo::Operator::Lighten,
            Mode::Overlay => cairo::Operator::Overlay,
            Mode::ColorDodge => cairo::Operator::ColorDodge,
            Mode::ColorBurn => cairo::Operator::ColorBurn,
            Mode::HardLight => cairo::Operator::HardLight,
            Mode::SoftLight => cairo::Operator::SoftLight,
            Mode::Difference => cairo::Operator::Difference,
            Mode::Exclusion => cairo::Operator::Exclusion,
            Mode::HslHue => cairo::Operator::HslHue,
            Mode::HslSaturation => cairo::Operator::HslSaturation,
            Mode::HslColor => cairo::Operator::HslColor,
            Mode::HslLuminosity => cairo::Operator::HslLuminosity,
        }
    }
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::fmt::{Formatter, Result as FmtResult};

use rustc_serialize::base64::{FromBase64, STANDARD, ToBase64};
use serde::{Deserializer, Serializer};
use serde::de::{Error as SerdeError, Visitor};

pub trait SerdeBlob: Sized {
    fn deserialize_blob<'de, D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>;

    fn serialize_blob<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer;
}

struct BlobVisitor;

impl<'de> Visitor<'de> for BlobVisitor {
    type Value = Vec<u8>;

    fn expecting(&self, formatter: &mut Formatter) -> FmtResult {
        write!(formatter, "a blob")
    }

    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
        where E: SerdeError {
        v.from_base64().map_err(|err| SerdeError::custom(err.description()))
    }
}

impl SerdeBlob for Vec<u8> {
    fn deserialize_blob<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
        where D: Deserializer<'de> {
        deserializer.deserialize_any(BlobVisitor)
    }

    fn serialize_blob<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer {
        serializer.serialize_str(&self.as_slice().to_base64(STANDARD))
    }
}

struct OptionalBlobVisitor;

impl<'de> Visitor<'de> for OptionalBlobVisitor {
    type Value = Option<Vec<u8>>;

    fn expecting(&self, formatter: &mut Formatter) -> FmtResult {
        write!(formatter, "a blob")
    }

    fn visit_none<E>(self) -> Result<Self::Value, E>
        where E: SerdeError {
        Ok(None)
    }

    fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
        where D: Deserializer<'de> {
        Ok(Some(try!(SerdeBlob::deserialize_blob(deserializer))))
    }
}

impl SerdeBlob for Option<Vec<u8>> {
    fn deserialize_blob<'de, D>(deserializer: D) -> Result<Option<Vec<u8>>, D::Error>
        where D: Deserializer<'de> {
        deserializer.deserialize_option(OptionalBlobVisitor)
    }

    fn serialize_blob<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer {
        match *self {
            Some(ref vec) => SerdeBlob::serialize_blob(vec, serializer),
            None => serializer.serialize_none(),
        }
    }
}

#[cfg(test)]
mod tests {
    extern crate serde;
    extern crate serde_json;

    use super::SerdeBlob;

    #[test]
    fn serialize_optional_blob_when_none() {
        let blob: Option<Vec<u8>> = None;
        let serialized = serialize_blob_helper(blob);

        assert_eq!("null", serialized);
    }

    #[test]
    fn serialize_optional_blob_when_empty() {
        let blob = Some(vec![]);
        let serialized = serialize_blob_helper(blob);

        assert_eq!("\"\"", serialized);
    }

    #[test]
    fn serialize_optional_blob_when_has_content() {
        let blob = Some("hello world!".as_bytes().to_vec());
        let serialized = serialize_blob_helper(blob);

        assert_eq!("\"aGVsbG8gd29ybGQh\"", serialized);
    }

    #[test]
    fn deserialize_optional_blob_when_null() {
        let deserialized: Option<Vec<u8>> = deserialize_blob_helper("null").unwrap();

        assert!(deserialized.is_none());
    }

    #[test]
    fn deserialize_optional_blob_when_empty() {
        let deserialized: Option<Vec<u8>> = deserialize_blob_helper("\"\"").unwrap();

        assert_eq!(Some(vec![]), deserialized);
    }

    #[test]
    fn deserialize_optional_blob_when_has_content() {
        let deserialized: Option<Vec<u8>> = deserialize_blob_helper("\"aGVsbG8gd29ybGQh\"").unwrap();

        assert_eq!(Some("hello world!".as_bytes().to_vec()), deserialized);
    }

    #[test]
    fn serialize_blob_when_empty() {
        let blob = vec![];
        let serialized = serialize_blob_helper(blob);

        assert_eq!("\"\"", serialized);
    }

    #[test]
    fn serialize_blob_when_has_content() {
        let blob = "hello world!".as_bytes().to_vec();
        let serialized = serialize_blob_helper(blob);

        assert_eq!("\"aGVsbG8gd29ybGQh\"", serialized);
    }

    #[test]
    fn deserialize_blob_when_null() {
        let deserialized: Result<Vec<u8>, _> = deserialize_blob_helper("null");

        assert!(deserialized.is_err());
    }

    #[test]
    fn deserialize_blob_when_empty() {
        let deserialized: Vec<u8> = deserialize_blob_helper("\"\"").unwrap();

        assert_eq!(Vec::<u8>::new(), deserialized);
    }

    #[test]
    fn deserialize_blob_when_has_content() {
        let deserialized: Vec<u8> = deserialize_blob_helper("\"aGVsbG8gd29ybGQh\"").unwrap();

        assert_eq!("hello world!".as_bytes().to_vec(), deserialized);
    }

    fn serialize_blob_helper<B: SerdeBlob>(blob: B) -> String {
        let mut serialized_data = Vec::new();
        {
            let mut json_serializer = serde_json::Serializer::new(&mut serialized_data);
            blob.serialize_blob(&mut json_serializer).unwrap();
        }
        String::from_utf8_lossy(&serialized_data).into_owned()
    }

    fn deserialize_blob_helper<B: SerdeBlob>(s: &str) -> Result<B, <&mut serde_json::de::Deserializer<serde_json::de::StrRead> as serde::Deserializer>::Error> {
        let reader = serde_json::de::StrRead::new(s);
        let mut deserializer = serde_json::de::Deserializer::new(reader);
        B::deserialize_blob(&mut deserializer)
    }
}<commit_msg>Revert SerdeBlob lifetime change<commit_after>use std::error::Error;
use std::fmt::{Formatter, Result as FmtResult};

use rustc_serialize::base64::{FromBase64, STANDARD, ToBase64};
use serde::{Deserializer, Serializer};
use serde::de::{Error as SerdeError, Visitor};

pub trait SerdeBlob<'de>: Sized {
    fn deserialize_blob<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>;

    fn serialize_blob<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer;
}

struct BlobVisitor;

impl<'de> Visitor<'de> for BlobVisitor {
    type Value = Vec<u8>;

    fn expecting(&self, formatter: &mut Formatter) -> FmtResult {
        write!(formatter, "a blob")
    }

    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
        where E: SerdeError {
        v.from_base64().map_err(|err| SerdeError::custom(err.description()))
    }
}

impl<'de> SerdeBlob<'de> for Vec<u8> {
    fn deserialize_blob<D>(deserializer: D) -> Result<Vec<u8>, D::Error>
        where D: Deserializer<'de> {
        deserializer.deserialize_any(BlobVisitor)
    }

    fn serialize_blob<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer {
        serializer.serialize_str(&self.as_slice().to_base64(STANDARD))
    }
}

struct OptionalBlobVisitor;

impl<'de> Visitor<'de> for OptionalBlobVisitor {
    type Value = Option<Vec<u8>>;

    fn expecting(&self, formatter: &mut Formatter) -> FmtResult {
        write!(formatter, "a blob")
    }

    fn visit_none<E>(self) -> Result<Self::Value, E>
        where E: SerdeError {
        Ok(None)
    }

    fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
        where D: Deserializer<'de> {
        Ok(Some(try!(SerdeBlob::deserialize_blob(deserializer))))
    }
}

impl<'de> SerdeBlob<'de> for Option<Vec<u8>> {
    fn deserialize_blob<D>(deserializer: D) -> Result<Option<Vec<u8>>, D::Error>
        where D: Deserializer<'de> {
        deserializer.deserialize_option(OptionalBlobVisitor)
    }

    fn serialize_blob<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer {
        match *self {
            Some(ref vec) => SerdeBlob::serialize_blob(vec, serializer),
            None => serializer.serialize_none(),
        }
    }
}

#[cfg(test)]
mod tests {
    extern crate serde;
    extern crate serde_json;

    use super::SerdeBlob;

    #[test]
    fn serialize_optional_blob_when_none() {
        let blob: Option<Vec<u8>> = None;
        let serialized = serialize_blob_helper(blob);

        assert_eq!("null", serialized);
    }

    #[test]
    fn serialize_optional_blob_when_empty() {
        let blob = Some(vec![]);
        let serialized = serialize_blob_helper(blob);

        assert_eq!("\"\"", serialized);
    }

    #[test]
    fn serialize_optional_blob_when_has_content() {
        let blob = Some("hello world!".as_bytes().to_vec());
        let serialized = serialize_blob_helper(blob);

        assert_eq!("\"aGVsbG8gd29ybGQh\"", serialized);
    }

    #[test]
    fn deserialize_optional_blob_when_null() {
        let deserialized: Option<Vec<u8>> = deserialize_blob_helper("null").unwrap();

        assert!(deserialized.is_none());
    }

    #[test]
    fn deserialize_optional_blob_when_empty() {
        let deserialized: Option<Vec<u8>> = deserialize_blob_helper("\"\"").unwrap();

        assert_eq!(Some(vec![]), deserialized);
    }

    #[test]
    fn deserialize_optional_blob_when_has_content() {
        let deserialized: Option<Vec<u8>> = deserialize_blob_helper("\"aGVsbG8gd29ybGQh\"").unwrap();

        assert_eq!(Some("hello world!".as_bytes().to_vec()), deserialized);
    }

    #[test]
    fn serialize_blob_when_empty() {
        let blob = vec![];
        let serialized = serialize_blob_helper(blob);

        assert_eq!("\"\"", serialized);
    }

    #[test]
    fn serialize_blob_when_has_content() {
        let blob = "hello world!".as_bytes().to_vec();
        let serialized = serialize_blob_helper(blob);

        assert_eq!("\"aGVsbG8gd29ybGQh\"", serialized);
    }

    #[test]
    fn deserialize_blob_when_null() {
        let deserialized: Result<Vec<u8>, _> = deserialize_blob_helper("null");

        assert!(deserialized.is_err());
    }

    #[test]
    fn deserialize_blob_when_empty() {
        let deserialized: Vec<u8> = deserialize_blob_helper("\"\"").unwrap();

        assert_eq!(Vec::<u8>::new(), deserialized);
    }

    #[test]
    fn deserialize_blob_when_has_content() {
        let deserialized: Vec<u8> = deserialize_blob_helper("\"aGVsbG8gd29ybGQh\"").unwrap();

        assert_eq!("hello world!".as_bytes().to_vec(), deserialized);
    }

    fn serialize_blob_helper<'de, B: SerdeBlob<'de>>(blob: B) -> String {
        let mut serialized_data = Vec::new();
        {
            let mut json_serializer = serde_json::Serializer::new(&mut serialized_data);
            blob.serialize_blob(&mut json_serializer).unwrap();
        }
        String::from_utf8_lossy(&serialized_data).into_owned()
    }

    fn deserialize_blob_helper<'de, B: SerdeBlob<'de>>(s: &'de str) -> Result<B, <&mut serde_json::de::Deserializer<serde_json::de::StrRead> as serde::Deserializer>::Error> {
        let reader = serde_json::de::StrRead::new(s);
        let mut deserializer = serde_json::de::Deserializer::new(reader);
        B::deserialize_blob(&mut deserializer)
    }
}<|endoftext|>


<commit_before>use super::tree;
use std::rc::Rc;

pub fn create_tree<C:PartialEq, T>(dataset:&Vec<Rc<(T, C)>>,
                         rules:&Vec<Rc<Fn(&T)->bool>>,
                         gain:Box<Fn(&Vec<Rc<(T,C)>>, &C)->f64>)
                         -> Option<Box<tree::Node<T>>> {

    let classes: Vec<&C> = dataset.iter().map(|x| {&x.1}).collect();
    let mut score = Vec::new();

    for r in rules {
        let mut right = Rc::new(Vec::new());
        let mut left = Rc::new(Vec::new());
        for d in dataset {
            if r(&d.0) {
                Rc::get_mut(&mut left).unwrap().push(d.clone())
            }
            else {
                Rc::get_mut(&mut right).unwrap().push(d.clone());
            }
        }
        for &c in &classes {
            score.push((Rc::new(r), Rc::new(c), gain(&left, &c), left.clone(), gain(&right, &c), right.clone()));
        }
    }

    None
}
<commit_msg>scorring<commit_after>use super::tree;
use std::rc::Rc;
use std::cmp::Ordering;

pub fn create_tree<C:PartialEq, T>(dataset:&Vec<Rc<(T, C)>>,
                         rules:&Vec<Rc<Fn(&T)->bool>>,
                         gain:Box<Fn(&Vec<Rc<(T,C)>>, &C)->f64>)
                         -> Option<Box<tree::Node<T>>> {

    let classes: Vec<&C> = dataset.iter().map(|x| {&x.1}).collect();
    let mut score = Vec::new();

    for r in rules {
        let mut right = Rc::new(Vec::new());
        let mut left = Rc::new(Vec::new());
        for d in dataset {
            if r(&d.0) {
                Rc::get_mut(&mut left).unwrap().push(d.clone())
            }
            else {
                Rc::get_mut(&mut right).unwrap().push(d.clone());
            }
        }
        for &c in &classes {
            score.push((Rc::new(r),
                        Rc::new(c),
                        gain(&left, &c),
                        left.clone(),
                        gain(&right, &c),
                        right.clone()));
        }
        score.sort_by(|x, y| {
            if x.2 < y.2 && x.4 < y.4 {
                return Ordering::Less
            }
            if x.2 == y.2 && x.4 == y.4 {
                return Ordering::Equal
            }
            return Ordering::Greater
        })
    }

    None
}
<|endoftext|>


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

#![allow(non_snake_case)]

register_long_diagnostics! {

E0373: r##"
This error occurs when an attempt is made to use data captured by a closure,
when that data may no longer exist. It's most commonly seen when attempting to
return a closure:

```
fn foo() -> Box<Fn(u32) -> u32> {
    let x = 0u32;
    Box::new(|y| x + y)
}
```

Notice that `x` is stack-allocated by `foo()`. By default, Rust captures
closed-over data by reference. This means that once `foo()` returns, `x` no
longer exists. An attempt to access `x` within the closure would thus be unsafe.

Another situation where this might be encountered is when spawning threads:

```
fn foo() {
    let x = 0u32;
    let y = 1u32;

    let thr = std::thread::spawn(|| {
        x + y
    });
}
```

Since our new thread runs in parallel, the stack frame containing `x` and `y`
may well have disappeared by the time we try to use them. Even if we call
`thr.join()` within foo (which blocks until `thr` has completed, ensuring the
stack frame won't disappear), we will not succeed: the compiler cannot prove
that this behaviour is safe, and so won't let us do it.

The solution to this problem is usually to switch to using a `move` closure.
This approach moves (or copies, where possible) data into the closure, rather
than taking references to it. For example:

```
fn foo() -> Box<Fn(u32) -> u32> {
    let x = 0u32;
    Box::new(move |y| x + y)
}
```

Now that the closure has its own copy of the data, there's no need to worry
about safety.
"##,

E0381: r##"
It is not allowed to use or capture an uninitialized variable. For example:

```
fn main() {
    let x: i32;
    let y = x; // error, use of possibly uninitialized variable
```

To fix this, ensure that any declared variables are initialized before being
used.
"##,

E0382: r##"
This error occurs when an attempt is made to use a variable after its contents
have been moved elsewhere. For example:

```
struct MyStruct { s: u32 }

fn main() {
    let mut x = MyStruct{ s: 5u32 };
    let y = x;
    x.s = 6;
    println!("{}", x.s);
}
```

Since `MyStruct` is a type that is not marked `Copy`, the data gets moved out
of `x` when we set `y`. This is fundamental to Rust's ownership system: outside
of workarounds like `Rc`, a value cannot be owned by more than one variable.

If we own the type, the easiest way to address this problem is to implement
`Copy` and `Clone` on it, as shown below. This allows `y` to copy the
information in `x`, while leaving the original version owned by `x`. Subsequent
changes to `x` will not be reflected when accessing `y`.

```
#[derive(Copy, Clone)]
struct MyStruct { s: u32 }

fn main() {
    let mut x = MyStruct{ s: 5u32 };
    let y = x;
    x.s = 6;
    println!("{}", x.s);
}
```

Alternatively, if we don't control the struct's definition, or mutable shared
ownership is truly required, we can use `Rc` and `RefCell`:

```
use std::cell::RefCell;
use std::rc::Rc;

struct MyStruct { s: u32 }

fn main() {
    let mut x = Rc::new(RefCell::new(MyStruct{ s: 5u32 }));
    let y = x.clone();
    x.borrow_mut().s = 6;
    println!("{}", x.borrow().s);
}
```

With this approach, x and y share ownership of the data via the `Rc` (reference
count type). `RefCell` essentially performs runtime borrow checking: ensuring
that at most one writer or multiple readers can access the data at any one time.

If you wish to learn more about ownership in Rust, start with the chapter in the
Book:

https://doc.rust-lang.org/book/ownership.html
"##,

E0383: r##"
This error occurs when an attempt is made to partially reinitialize a
structure that is currently uninitialized.

For example, this can happen when a drop has taken place:

```
let mut x = Foo { a: 1 };
drop(x); // `x` is now uninitialized
x.a = 2; // error, partial reinitialization of uninitialized structure `t`
```

This error can be fixed by fully reinitializing the structure in question:

```
let mut x = Foo { a: 1 };
drop(x);
x = Foo { a: 2 };
```
"##,

E0384: r##"
This error occurs when an attempt is made to reassign an immutable variable.
For example:

```
fn main(){
    let x = 3;
    x = 5; // error, reassignment of immutable variable
}
```

By default, variables in Rust are immutable. To fix this error, add the keyword
`mut` after the keyword `let` when declaring the variable. For example:

```
fn main(){
    let mut x = 3;
    x = 5;
}
```
"##,

E0386: r##"
This error occurs when an attempt is made to mutate the target of a mutable
reference stored inside an immutable container.

For example, this can happen when storing a `&mut` inside an immutable `Box`:

```
let mut x: i64 = 1;
let y: Box<_> = Box::new(&mut x);
**y = 2; // error, cannot assign to data in an immutable container
```

This error can be fixed by making the container mutable:

```
let mut x: i64 = 1;
let mut y: Box<_> = Box::new(&mut x);
**y = 2;
```

It can also be fixed by using a type with interior mutability, such as `Cell` or
`RefCell`:

```
let x: i64 = 1;
let y: Box<Cell<_>> = Box::new(Cell::new(x));
y.set(2);
```
"##,

E0387: r##"
This error occurs when an attempt is made to mutate or mutably reference data
that a closure has captured immutably. Examples of this error are shown below:

```
// Accepts a function or a closure that captures its environment immutably.
// Closures passed to foo will not be able to mutate their closed-over state.
fn foo<F: Fn()>(f: F) { }

// Attempts to mutate closed-over data.  Error message reads:
// `cannot assign to data in a captured outer variable...`
fn mutable() {
    let mut x = 0u32;
    foo(|| x = 2);
}

// Attempts to take a mutable reference to closed-over data.  Error message
// reads: `cannot borrow data mutably in a captured outer variable...`
fn mut_addr() {
    let mut x = 0u32;
    foo(|| { let y = &mut x; });
}
```

The problem here is that foo is defined as accepting a parameter of type `Fn`.
Closures passed into foo will thus be inferred to be of type `Fn`, meaning that
they capture their context immutably.

If the definition of `foo` is under your control, the simplest solution is to
capture the data mutably. This can be done by defining `foo` to take FnMut
rather than Fn:

```
fn foo<F: FnMut()>(f: F) { }
```

Alternatively, we can consider using the `Cell` and `RefCell` types to achieve
interior mutability through a shared reference. Our example's `mutable` function
could be redefined as below:

```
use std::cell::Cell;

fn mutable() {
    let x = Cell::new(0u32);
    foo(|| x.set(2));
}
```

You can read more about cell types in the API documentation:

https://doc.rust-lang.org/std/cell/
"##,

E0499: r##"
A variable was borrowed as mutable more than once. Erroneous code example:

```
let mut i = 0;
let mut x = &mut i;
let mut a = &mut i;
// error: cannot borrow `i` as mutable more than once at a time
```

Please note that in rust, you can either have many immutable references, or one
mutable reference. Take a look at
https://doc.rust-lang.org/stable/book/references-and-borrowing.html for more
information. Example:

```
let mut i = 0;
let mut x = &mut i; // ok!

// or:
let mut i = 0;
let a = &i; // ok!
let b = &i; // still ok!
let c = &i; // still ok!
```
"##,

E0507: r##"
You tried to move out of a value which was borrowed. Erroneous code example:

```
use std::cell::RefCell;

struct TheDarkKnight;

impl TheDarkKnight {
    fn nothing_is_true(self) {}
}

fn main() {
    let x = RefCell::new(TheDarkKnight);

    x.borrow().nothing_is_true(); // error: cannot move out of borrowed content
}
```

Here, the `nothing_is_true` method takes the ownership of `self`. However,
`self` cannot be moved because `.borrow()` only provides an `&TheDarkKnight`,
which is a borrow of the content owned by the `RefCell`. To fix this error,
you have three choices:

* Try to avoid moving the variable.
* Somehow reclaim the ownership.
* Implement the `Copy` trait on the type.

Examples:

```
use std::cell::RefCell;

struct TheDarkKnight;

impl TheDarkKnight {
    fn nothing_is_true(&self) {} // First case, we don't take ownership
}

fn main() {
    let x = RefCell::new(TheDarkKnight);

    x.borrow().nothing_is_true(); // ok!
}
```

Or:

```
use std::cell::RefCell;

struct TheDarkKnight;

impl TheDarkKnight {
    fn nothing_is_true(self) {}
}

fn main() {
    let x = RefCell::new(TheDarkKnight);
    let x = x.into_inner(); // we get back ownership

    x.nothing_is_true(); // ok!
}
```

Or:

```
use std::cell::RefCell;

#[derive(Clone, Copy)] // we implement the Copy trait
struct TheDarkKnight;

impl TheDarkKnight {
    fn nothing_is_true(self) {}
}

fn main() {
    let x = RefCell::new(TheDarkKnight);

    x.borrow().nothing_is_true(); // ok!
}
```

You can find more information about borrowing in the rust-book:
http://doc.rust-lang.org/stable/book/references-and-borrowing.html
"##,

}

register_diagnostics! {
    E0385, // {} in an aliasable location
    E0388, // {} in a static location
    E0389, // {} in a `&` reference
    E0500, // closure requires unique access to `..` but .. is already borrowed
    E0501, // cannot borrow `..`.. as .. because previous closure requires unique access
    E0502, // cannot borrow `..`.. as .. because .. is also borrowed as ...
    E0503, // cannot use `..` because it was mutably borrowed
    E0504, // cannot move `..` into closure because it is borrowed
    E0505, // cannot move out of `..` because it is borrowed
    E0506, // cannot assign to `..` because it is borrowed
    E0508, // cannot move out of type `..`, a non-copy fixed-size array
    E0509, // cannot move out of type `..`, which defines the `Drop` trait
}
<commit_msg>Rollup merge of #31270 - ruud-v-a:improve-e0507, r=steveklabnik<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(non_snake_case)]

register_long_diagnostics! {

E0373: r##"
This error occurs when an attempt is made to use data captured by a closure,
when that data may no longer exist. It's most commonly seen when attempting to
return a closure:

```
fn foo() -> Box<Fn(u32) -> u32> {
    let x = 0u32;
    Box::new(|y| x + y)
}
```

Notice that `x` is stack-allocated by `foo()`. By default, Rust captures
closed-over data by reference. This means that once `foo()` returns, `x` no
longer exists. An attempt to access `x` within the closure would thus be unsafe.

Another situation where this might be encountered is when spawning threads:

```
fn foo() {
    let x = 0u32;
    let y = 1u32;

    let thr = std::thread::spawn(|| {
        x + y
    });
}
```

Since our new thread runs in parallel, the stack frame containing `x` and `y`
may well have disappeared by the time we try to use them. Even if we call
`thr.join()` within foo (which blocks until `thr` has completed, ensuring the
stack frame won't disappear), we will not succeed: the compiler cannot prove
that this behaviour is safe, and so won't let us do it.

The solution to this problem is usually to switch to using a `move` closure.
This approach moves (or copies, where possible) data into the closure, rather
than taking references to it. For example:

```
fn foo() -> Box<Fn(u32) -> u32> {
    let x = 0u32;
    Box::new(move |y| x + y)
}
```

Now that the closure has its own copy of the data, there's no need to worry
about safety.
"##,

E0381: r##"
It is not allowed to use or capture an uninitialized variable. For example:

```
fn main() {
    let x: i32;
    let y = x; // error, use of possibly uninitialized variable
```

To fix this, ensure that any declared variables are initialized before being
used.
"##,

E0382: r##"
This error occurs when an attempt is made to use a variable after its contents
have been moved elsewhere. For example:

```
struct MyStruct { s: u32 }

fn main() {
    let mut x = MyStruct{ s: 5u32 };
    let y = x;
    x.s = 6;
    println!("{}", x.s);
}
```

Since `MyStruct` is a type that is not marked `Copy`, the data gets moved out
of `x` when we set `y`. This is fundamental to Rust's ownership system: outside
of workarounds like `Rc`, a value cannot be owned by more than one variable.

If we own the type, the easiest way to address this problem is to implement
`Copy` and `Clone` on it, as shown below. This allows `y` to copy the
information in `x`, while leaving the original version owned by `x`. Subsequent
changes to `x` will not be reflected when accessing `y`.

```
#[derive(Copy, Clone)]
struct MyStruct { s: u32 }

fn main() {
    let mut x = MyStruct{ s: 5u32 };
    let y = x;
    x.s = 6;
    println!("{}", x.s);
}
```

Alternatively, if we don't control the struct's definition, or mutable shared
ownership is truly required, we can use `Rc` and `RefCell`:

```
use std::cell::RefCell;
use std::rc::Rc;

struct MyStruct { s: u32 }

fn main() {
    let mut x = Rc::new(RefCell::new(MyStruct{ s: 5u32 }));
    let y = x.clone();
    x.borrow_mut().s = 6;
    println!("{}", x.borrow().s);
}
```

With this approach, x and y share ownership of the data via the `Rc` (reference
count type). `RefCell` essentially performs runtime borrow checking: ensuring
that at most one writer or multiple readers can access the data at any one time.

If you wish to learn more about ownership in Rust, start with the chapter in the
Book:

https://doc.rust-lang.org/book/ownership.html
"##,

E0383: r##"
This error occurs when an attempt is made to partially reinitialize a
structure that is currently uninitialized.

For example, this can happen when a drop has taken place:

```
let mut x = Foo { a: 1 };
drop(x); // `x` is now uninitialized
x.a = 2; // error, partial reinitialization of uninitialized structure `t`
```

This error can be fixed by fully reinitializing the structure in question:

```
let mut x = Foo { a: 1 };
drop(x);
x = Foo { a: 2 };
```
"##,

E0384: r##"
This error occurs when an attempt is made to reassign an immutable variable.
For example:

```
fn main(){
    let x = 3;
    x = 5; // error, reassignment of immutable variable
}
```

By default, variables in Rust are immutable. To fix this error, add the keyword
`mut` after the keyword `let` when declaring the variable. For example:

```
fn main(){
    let mut x = 3;
    x = 5;
}
```
"##,

E0386: r##"
This error occurs when an attempt is made to mutate the target of a mutable
reference stored inside an immutable container.

For example, this can happen when storing a `&mut` inside an immutable `Box`:

```
let mut x: i64 = 1;
let y: Box<_> = Box::new(&mut x);
**y = 2; // error, cannot assign to data in an immutable container
```

This error can be fixed by making the container mutable:

```
let mut x: i64 = 1;
let mut y: Box<_> = Box::new(&mut x);
**y = 2;
```

It can also be fixed by using a type with interior mutability, such as `Cell` or
`RefCell`:

```
let x: i64 = 1;
let y: Box<Cell<_>> = Box::new(Cell::new(x));
y.set(2);
```
"##,

E0387: r##"
This error occurs when an attempt is made to mutate or mutably reference data
that a closure has captured immutably. Examples of this error are shown below:

```
// Accepts a function or a closure that captures its environment immutably.
// Closures passed to foo will not be able to mutate their closed-over state.
fn foo<F: Fn()>(f: F) { }

// Attempts to mutate closed-over data.  Error message reads:
// `cannot assign to data in a captured outer variable...`
fn mutable() {
    let mut x = 0u32;
    foo(|| x = 2);
}

// Attempts to take a mutable reference to closed-over data.  Error message
// reads: `cannot borrow data mutably in a captured outer variable...`
fn mut_addr() {
    let mut x = 0u32;
    foo(|| { let y = &mut x; });
}
```

The problem here is that foo is defined as accepting a parameter of type `Fn`.
Closures passed into foo will thus be inferred to be of type `Fn`, meaning that
they capture their context immutably.

If the definition of `foo` is under your control, the simplest solution is to
capture the data mutably. This can be done by defining `foo` to take FnMut
rather than Fn:

```
fn foo<F: FnMut()>(f: F) { }
```

Alternatively, we can consider using the `Cell` and `RefCell` types to achieve
interior mutability through a shared reference. Our example's `mutable` function
could be redefined as below:

```
use std::cell::Cell;

fn mutable() {
    let x = Cell::new(0u32);
    foo(|| x.set(2));
}
```

You can read more about cell types in the API documentation:

https://doc.rust-lang.org/std/cell/
"##,

E0499: r##"
A variable was borrowed as mutable more than once. Erroneous code example:

```
let mut i = 0;
let mut x = &mut i;
let mut a = &mut i;
// error: cannot borrow `i` as mutable more than once at a time
```

Please note that in rust, you can either have many immutable references, or one
mutable reference. Take a look at
https://doc.rust-lang.org/stable/book/references-and-borrowing.html for more
information. Example:

```
let mut i = 0;
let mut x = &mut i; // ok!

// or:
let mut i = 0;
let a = &i; // ok!
let b = &i; // still ok!
let c = &i; // still ok!
```
"##,

E0507: r##"
You tried to move out of a value which was borrowed. Erroneous code example:

```
use std::cell::RefCell;

struct TheDarkKnight;

impl TheDarkKnight {
    fn nothing_is_true(self) {}
}

fn main() {
    let x = RefCell::new(TheDarkKnight);

    x.borrow().nothing_is_true(); // error: cannot move out of borrowed content
}
```

Here, the `nothing_is_true` method takes the ownership of `self`. However,
`self` cannot be moved because `.borrow()` only provides an `&TheDarkKnight`,
which is a borrow of the content owned by the `RefCell`. To fix this error,
you have three choices:

* Try to avoid moving the variable.
* Somehow reclaim the ownership.
* Implement the `Copy` trait on the type.

Examples:

```
use std::cell::RefCell;

struct TheDarkKnight;

impl TheDarkKnight {
    fn nothing_is_true(&self) {} // First case, we don't take ownership
}

fn main() {
    let x = RefCell::new(TheDarkKnight);

    x.borrow().nothing_is_true(); // ok!
}
```

Or:

```
use std::cell::RefCell;

struct TheDarkKnight;

impl TheDarkKnight {
    fn nothing_is_true(self) {}
}

fn main() {
    let x = RefCell::new(TheDarkKnight);
    let x = x.into_inner(); // we get back ownership

    x.nothing_is_true(); // ok!
}
```

Or:

```
use std::cell::RefCell;

#[derive(Clone, Copy)] // we implement the Copy trait
struct TheDarkKnight;

impl TheDarkKnight {
    fn nothing_is_true(self) {}
}

fn main() {
    let x = RefCell::new(TheDarkKnight);

    x.borrow().nothing_is_true(); // ok!
}
```

Moving out of a member of a mutably borrowed struct is fine if you put something
back. `mem::replace` can be used for that:

```
struct TheDarkKnight;

impl TheDarkKnight {
    fn nothing_is_true(self) {}
}

struct Batcave {
    knight: TheDarkKnight
}

fn main() {
    use std::mem;

    let mut cave = Batcave {
        knight: TheDarkKnight
    };
    let borrowed = &mut cave;

    borrowed.knight.nothing_is_true(); // E0507
    mem::replace(&mut borrowed.knight, TheDarkKnight).nothing_is_true(); // ok!
}
```

You can find more information about borrowing in the rust-book:
http://doc.rust-lang.org/stable/book/references-and-borrowing.html
"##,

}

register_diagnostics! {
    E0385, // {} in an aliasable location
    E0388, // {} in a static location
    E0389, // {} in a `&` reference
    E0500, // closure requires unique access to `..` but .. is already borrowed
    E0501, // cannot borrow `..`.. as .. because previous closure requires unique access
    E0502, // cannot borrow `..`.. as .. because .. is also borrowed as ...
    E0503, // cannot use `..` because it was mutably borrowed
    E0504, // cannot move `..` into closure because it is borrowed
    E0505, // cannot move out of `..` because it is borrowed
    E0506, // cannot assign to `..` because it is borrowed
    E0508, // cannot move out of type `..`, a non-copy fixed-size array
    E0509, // cannot move out of type `..`, which defines the `Drop` trait
}
<|endoftext|>


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

use common::Solution;

#[derive(Default)]
pub struct Day08 {}

fn total1(items: &[usize]) -> (usize, usize) {
    let children = items[0];
    let meta_entries = items[1];

    let mut total = 0;
    let mut start = 2;

    for _ in 0..children {
        let (ct, cl) = total1(&items[start..items.len()]);
        start += cl;
        total += ct;
    }

    total += items[start..(start + meta_entries)].iter().sum::<usize>();

    (total, start + meta_entries)
}

fn total2(items: &[usize]) -> (usize, usize) {
    let children = items[0];
    let meta_entries = items[1];

    if children == 0 {
        (items[2..(2 + meta_entries)].iter().sum(), meta_entries + 2)
    } else {
        let mut values = Vec::with_capacity(children);

        let mut start = 2;

        for _ in 0..children {
            let (ct, cl) = total2(&items[start..items.len()]);
            start += cl;
            values.push(ct);
        }

        let total = items[start..(start + meta_entries)].iter()
            .filter(|&&x| x <= values.len())
            .map(|&x| values[x - 1])
            .sum();

        (total, start + meta_entries)
    }
}

impl Day08 {
    pub fn new() -> Self {
        Default::default()
    }
}

impl Solution for Day08 {
    fn part1(&mut self, input: &mut Read) -> String {
        let mut data = String::new();
        input.read_to_string(&mut data).unwrap();

        let data: Vec<usize> = data.trim().split(" ").map(|x| x.parse().unwrap()).collect();
        let (result, _) = total1(&data);

        format!("{}", result)
    }

    fn part2(&mut self, input: &mut Read) -> String {
        let mut data = String::new();
        input.read_to_string(&mut data).unwrap();

        let data: Vec<usize> = data.trim().split(" ").map(|x| x.parse().unwrap()).collect();
        let (result, _) = total2(&data);

        format!("{}", result)
    }
}

#[cfg(test)]
mod tests {
    use common::Solution;
    use day08::Day08;

    const SAMPLE_INPUT: &[u8] = include_bytes!("samples/08.txt");

    #[test]
    fn sample_part1() {
        let mut instance = Day08::new();
        assert_eq!("138", instance.part1(&mut SAMPLE_INPUT));
    }

    #[test]
    fn sample_part2() {
        let mut instance = Day08::new();
        assert_eq!("66", instance.part2(&mut SAMPLE_INPUT));
    }
}
<commit_msg>Replace filter + map with filter_map.<commit_after>use std::io::Read;

use common::Solution;

#[derive(Default)]
pub struct Day08 {}

fn total1(items: &[usize]) -> (usize, usize) {
    let children = items[0];
    let meta_entries = items[1];

    let mut total = 0;
    let mut start = 2;

    for _ in 0..children {
        let (ct, cl) = total1(&items[start..items.len()]);
        start += cl;
        total += ct;
    }

    total += items[start..(start + meta_entries)].iter().sum::<usize>();

    (total, start + meta_entries)
}

fn total2(items: &[usize]) -> (usize, usize) {
    let children = items[0];
    let meta_entries = items[1];

    if children == 0 {
        (items[2..(2 + meta_entries)].iter().sum(), meta_entries + 2)
    } else {
        let mut values = Vec::with_capacity(children);

        let mut start = 2;

        for _ in 0..children {
            let (ct, cl) = total2(&items[start..items.len()]);
            start += cl;
            values.push(ct);
        }

        let total = items[start..(start + meta_entries)].iter()
            .filter_map(|&x| values.get(x - 1))
            .sum();

        (total, start + meta_entries)
    }
}

impl Day08 {
    pub fn new() -> Self {
        Default::default()
    }
}

impl Solution for Day08 {
    fn part1(&mut self, input: &mut Read) -> String {
        let mut data = String::new();
        input.read_to_string(&mut data).unwrap();

        let data: Vec<usize> = data.trim().split(" ").map(|x| x.parse().unwrap()).collect();
        let (result, _) = total1(&data);

        format!("{}", result)
    }

    fn part2(&mut self, input: &mut Read) -> String {
        let mut data = String::new();
        input.read_to_string(&mut data).unwrap();

        let data: Vec<usize> = data.trim().split(" ").map(|x| x.parse().unwrap()).collect();
        let (result, _) = total2(&data);

        format!("{}", result)
    }
}

#[cfg(test)]
mod tests {
    use common::Solution;
    use day08::Day08;

    const SAMPLE_INPUT: &[u8] = include_bytes!("samples/08.txt");

    #[test]
    fn sample_part1() {
        let mut instance = Day08::new();
        assert_eq!("138", instance.part1(&mut SAMPLE_INPUT));
    }

    #[test]
    fn sample_part2() {
        let mut instance = Day08::new();
        assert_eq!("66", instance.part2(&mut SAMPLE_INPUT));
    }
}
<|endoftext|>


<commit_before>//! Generic Tree Implementation for Plan

pub enum TreeNode<T> {
  Branch(T, Vec<Box<TreeNode<T>>>),
  Leaf(T)
}

/// Tree Builder in a bottom up approach.
pub struct TreeBuilder<T>
{
  stack: Vec<TreeNode<T>>
}

impl<T> TreeBuilder<T> {
  pub fn new() -> TreeBuilder<T> {
    TreeBuilder {
      stack: Vec::new()
    }
  }

  pub fn push(&mut self, node: TreeNode<T>) -> usize {
    self.stack.push(node);
    self.stack.len()
  }

  pub fn pop(&mut self) -> TreeNode<T> {
    debug_assert!(self.stack.len() > 0);

    self.stack.pop().unwrap()
  }

  pub fn build(&mut self) -> TreeNode<T> {
    debug_assert!(self.stack.len() == 1);

    self.stack.pop().unwrap()
  }
}<commit_msg>Change TreeBuilder::build() to return errorable result.<commit_after>//! Generic Tree Implementation for Plan

pub enum TreeBuildError {
  EmptyStack,
  StillRemainStackItem
}

pub enum TreeNode<T> {
  Branch(T, Vec<Box<TreeNode<T>>>),
  Leaf(T)
}

/// Tree Builder in a bottom up approach.
pub struct TreeBuilder<T>
{
  stack: Vec<TreeNode<T>>
}

impl<T> TreeBuilder<T> {
  pub fn new() -> TreeBuilder<T> {
    TreeBuilder {
      stack: Vec::new()
    }
  }

  pub fn push(&mut self, node: TreeNode<T>) -> usize {
    self.stack.push(node);
    self.stack.len()
  }

  pub fn pop(&mut self) -> TreeNode<T> {
    debug_assert!(self.stack.len() > 0);

    self.stack.pop().unwrap()
  }

  pub fn build(&mut self) -> Result<TreeNode<T>, TreeBuildError>  {
    match self.stack.len() {
      0 => { Err(TreeBuildError::EmptyStack) },
      1 => { Ok(self.stack.pop().unwrap()) },
      _ => { Err(TreeBuildError::StillRemainStackItem) }
   }
  }
}<|endoftext|>


<commit_before>// Copyright (c) 2017 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::error;
use std::fmt;

use command_buffer::DynamicState;
use descriptor::pipeline_layout::PipelineLayoutAbstract;

/// Checks whether push constants are compatible with the pipeline.
pub fn check_push_constants_validity<Pl, Pc>(pipeline: &Pl, push_constants: &Pc)
                                             -> Result<(), CheckPushConstantsValidityError>
    where Pl: ?Sized + PipelineLayoutAbstract,
          Pc: ?Sized,
{
    // FIXME:

    Ok(())
}

/// Error that can happen when validating dynamic states.
#[derive(Debug, Copy, Clone)]
pub enum CheckPushConstantsValidityError {
}

impl error::Error for CheckPushConstantsValidityError {
    #[inline]
    fn description(&self) -> &str {
        match *self {
        }
    }
}

impl fmt::Display for CheckPushConstantsValidityError {
    #[inline]
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{}", error::Error::description(self))
    }
}
<commit_msg>Correctly implement check_push_constants_validity<commit_after>// Copyright (c) 2017 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::error;
use std::fmt;

use command_buffer::DynamicState;
use descriptor::pipeline_layout::PipelineLayoutAbstract;
use descriptor::pipeline_layout::PipelineLayoutPushConstantsCompatible;

/// Checks whether push constants are compatible with the pipeline.
pub fn check_push_constants_validity<Pl, Pc>(pipeline: &Pl, push_constants: &Pc)
                                             -> Result<(), CheckPushConstantsValidityError>
    where Pl: ?Sized + PipelineLayoutAbstract + PipelineLayoutPushConstantsCompatible<Pc>,
          Pc: ?Sized,
{
    if !pipeline.is_compatible(push_constants) {
        return Err(CheckPushConstantsValidityError::IncompatiblePushConstants);
    }

    Ok(())
}

/// Error that can happen when checking push constants validity.
#[derive(Debug, Copy, Clone)]
pub enum CheckPushConstantsValidityError {
    /// The push constants are incompatible with the pipeline layout.
    IncompatiblePushConstants,
}

impl error::Error for CheckPushConstantsValidityError {
    #[inline]
    fn description(&self) -> &str {
        match *self {
            CheckPushConstantsValidityError::IncompatiblePushConstants => {
                "the push constants are incompatible with the pipeline layout"
            },
        }
    }
}

impl fmt::Display for CheckPushConstantsValidityError {
    #[inline]
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{}", error::Error::description(self))
    }
}
<|endoftext|>


<commit_before>use crate::types::{
    flags::*,
    generation::*,
    parsing::{traits::ParsableInput, *},
    *,
};
use nom::{
    combinator::{flat_map, map, map_opt},
    error::context,
};
use std::{convert::TryFrom, error, fmt, io::Write};

include!(concat!(env!("OUT_DIR"), "/protocol.rs"));

/// Type alias for AMQP BasicProperties
pub type BasicProperties = basic::AMQPProperties;

/// An AMQP Error
#[derive(Clone, Debug, PartialEq)]
pub struct AMQPError {
    kind: AMQPErrorKind,
    message: ShortString,
}

impl AMQPError {
    /// Get the error corresponding to an id
    pub fn from_id(id: ShortUInt, message: ShortString) -> Option<Self> {
        AMQPErrorKind::from_id(id).map(|kind| Self { kind, message })
    }

    /// Get the kind of error
    pub fn kind(&self) -> &AMQPErrorKind {
        &self.kind
    }
}

impl TryFrom<channel::Close> for AMQPError {
    type Error = String;

    fn try_from(method: channel::Close) -> Result<Self, Self::Error> {
        Self::from_id(method.reply_code, method.reply_text.clone()).ok_or_else(|| format!("Couldn't convert method to error: {:?}", method))
    }
}

impl TryFrom<connection::Close> for AMQPError {
    type Error = String;

    fn try_from(method: connection::Close) -> Result<Self, Self::Error> {
        Self::from_id(method.reply_code, method.reply_text.clone()).ok_or_else(|| format!("Couldn't convert method to error: {:?}", method))
    }
}

impl fmt::Display for AMQPError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}: {}", self.kind, self.message)
    }
}

impl error::Error for AMQPError {}

/// The kind of AMQP Error
#[derive(Clone, Debug, PartialEq)]
pub enum AMQPErrorKind {
    /// A soft AMQP error
    Soft(AMQPSoftError),
    /// A hard AMQP error
    Hard(AMQPHardError),
}

impl AMQPErrorKind {
    /// Get the id of the error
    pub fn get_id(&self) -> ShortUInt {
        match *self {
            AMQPErrorKind::Soft(ref s) => s.get_id(),
            AMQPErrorKind::Hard(ref h) => h.get_id(),
        }
    }

    /// Get the error kind corresponding to an id
    pub fn from_id(id: ShortUInt) -> Option<Self> {
        AMQPSoftError::from_id(id).map(AMQPErrorKind::Soft).or_else(|| AMQPHardError::from_id(id).map(AMQPErrorKind::Hard))
    }
}

impl fmt::Display for AMQPErrorKind {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            AMQPErrorKind::Soft(err) => write!(f, "AMQP soft error: {}", err),
            AMQPErrorKind::Hard(err) => write!(f, "AMQP hard error: {}", err),
        }
    }
}

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

    #[test]
    fn test_description() {
        assert_eq!(
            format!(
                "{} - {}.{}.{}",
                metadata::NAME,
                metadata::MAJOR_VERSION,
                metadata::MINOR_VERSION,
                metadata::REVISION
            ),
            "AMQP - 0.9.1"
        );
    }
}
<commit_msg>protocol: add a simple way of creating an Error<commit_after>use crate::types::{
    flags::*,
    generation::*,
    parsing::{traits::ParsableInput, *},
    *,
};
use nom::{
    combinator::{flat_map, map, map_opt},
    error::context,
};
use std::{convert::TryFrom, error, fmt, io::Write};

include!(concat!(env!("OUT_DIR"), "/protocol.rs"));

/// Type alias for AMQP BasicProperties
pub type BasicProperties = basic::AMQPProperties;

/// An AMQP Error
#[derive(Clone, Debug, PartialEq)]
pub struct AMQPError {
    kind: AMQPErrorKind,
    message: ShortString,
}

impl AMQPError {
    /// Create a new error
    pub fn new(kind: AMQPErrorKind, message: ShortString) -> Self {
        Self { kind, message }
    }

    /// Get the error corresponding to an id
    pub fn from_id(id: ShortUInt, message: ShortString) -> Option<Self> {
        AMQPErrorKind::from_id(id).map(|kind| Self { kind, message })
    }

    /// Get the kind of error
    pub fn kind(&self) -> &AMQPErrorKind {
        &self.kind
    }
}

impl TryFrom<channel::Close> for AMQPError {
    type Error = String;

    fn try_from(method: channel::Close) -> Result<Self, Self::Error> {
        Self::from_id(method.reply_code, method.reply_text.clone()).ok_or_else(|| format!("Couldn't convert method to error: {:?}", method))
    }
}

impl TryFrom<connection::Close> for AMQPError {
    type Error = String;

    fn try_from(method: connection::Close) -> Result<Self, Self::Error> {
        Self::from_id(method.reply_code, method.reply_text.clone()).ok_or_else(|| format!("Couldn't convert method to error: {:?}", method))
    }
}

impl fmt::Display for AMQPError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}: {}", self.kind, self.message)
    }
}

impl error::Error for AMQPError {}

/// The kind of AMQP Error
#[derive(Clone, Debug, PartialEq)]
pub enum AMQPErrorKind {
    /// A soft AMQP error
    Soft(AMQPSoftError),
    /// A hard AMQP error
    Hard(AMQPHardError),
}

impl AMQPErrorKind {
    /// Get the id of the error
    pub fn get_id(&self) -> ShortUInt {
        match *self {
            AMQPErrorKind::Soft(ref s) => s.get_id(),
            AMQPErrorKind::Hard(ref h) => h.get_id(),
        }
    }

    /// Get the error kind corresponding to an id
    pub fn from_id(id: ShortUInt) -> Option<Self> {
        AMQPSoftError::from_id(id).map(AMQPErrorKind::Soft).or_else(|| AMQPHardError::from_id(id).map(AMQPErrorKind::Hard))
    }
}

impl fmt::Display for AMQPErrorKind {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            AMQPErrorKind::Soft(err) => write!(f, "AMQP soft error: {}", err),
            AMQPErrorKind::Hard(err) => write!(f, "AMQP hard error: {}", err),
        }
    }
}

impl From<AMQPSoftError> for AMQPErrorKind {
    fn from(error: AMQPSoftError) -> Self {
        Self::Soft(error)
    }
}

impl From<AMQPHardError> for AMQPErrorKind {
    fn from(error: AMQPHardError) -> Self {
        Self::Hard(error)
    }
}

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

    #[test]
    fn test_description() {
        assert_eq!(
            format!(
                "{} - {}.{}.{}",
                metadata::NAME,
                metadata::MAJOR_VERSION,
                metadata::MINOR_VERSION,
                metadata::REVISION
            ),
            "AMQP - 0.9.1"
        );
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::collections::hash_map::Keys;
use std::cell::RefCell;
use std::ops::Index;
use std::path::Path;

use super::{Buffer, BufferId};

/// Creates, manages and deletes all the buffers in Qork, maintaining the various invariants that
/// we expect from the buffers. Firstly, if a buffer is backed by a file, a second buffer on that
/// file cannot be created. Secondly, all buffers have unique identity.
///
/// Note that a Buffer is very different from a BufferView.
pub struct BufferCollection {
    current_buffer: BufferId,
    buffers: HashMap<BufferId, RefCell<Buffer>>
}

impl BufferCollection {
    pub fn new() -> BufferCollection {
        BufferCollection {
            current_buffer: -1,
            buffers: HashMap::with_capacity(20)
        }
    }

    pub fn len(&self) -> usize {
        self.buffers.len()
    }

    pub fn current_buffer(&self) -> BufferId {
        self.current_buffer
    }

    pub fn set_current_buffer(&mut self, buffer_id: BufferId) -> bool {
        if self.buffers.contains_key(&buffer_id) {
            self.current_buffer = buffer_id;
            return true;
        } else {
            return false;
        }
    }

    pub fn is_empty(&self) -> bool {
        self.buffers.is_empty()
    }

    pub fn get(&self, buffer_id: BufferId) -> Option<&RefCell<Buffer>> {
         self.buffers.get(&buffer_id)
    }

    pub fn keys(&self) -> Keys<BufferId, RefCell<Buffer>> {
         self.buffers.keys()
    }

    pub fn insert(&mut self, buffer: Buffer) {
        self.buffers.insert(buffer.id(), RefCell::new(buffer));
    }

    pub fn remove(&mut self, buffer_id: BufferId) -> Option<RefCell<Buffer>> {
        self.buffers.remove(&buffer_id)
    }

    pub fn find_by_filename<P : AsRef<Path>>(&mut self, filename: P) -> Option<&RefCell<Buffer>> {
        self.buffers.values().find(|refcell| refcell.borrow().filename.as_ref().map_or(false, |f| f == filename.as_ref()))
    }
}

impl Index<BufferId> for BufferCollection {
    type Output = RefCell<Buffer>;

    fn index(&self, buffer_id: BufferId) -> &RefCell<Buffer> {
        &self.buffers[&buffer_id]
    }
}

#[cfg(test)]
mod buffer_collection_tests {
    use super::*;
    use std::path::PathBuf;
    use super::super::BufferFactory;

    #[test]
    fn is_empty_for_empty_collection_returns_true() {
        let bc = BufferCollection::new();
        assert!(bc.is_empty());
    }

    #[test]
    fn len_for_empty_collection_returns_zero() {
        let bc = BufferCollection::new();
        assert_eq!(0, bc.len());
    }

    #[test]
    fn len_for_non_empty_collection_returns_length() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.new_empty_buffer();
        bc.insert(b);

        assert_eq!(1, bc.len());
    }

    #[test]
    fn get_for_empty_collection_returns_false() {
        let bc = BufferCollection::new();
        assert!(bc.get(0).is_none());
    }

    #[test]
    fn get_for_id_not_in_collection_returns_none() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.new_empty_buffer();
        let id = b.id;
        bc.insert(b);
        assert!(bc.get(id + 1).is_none());
    }

    #[test]
    fn get_for_id_in_collection_returns_buffer() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.new_empty_buffer();
        let id = b.id;
        bc.insert(b);

        let result = bc.get(id).unwrap().borrow();
        assert_eq!(id, result.id());

    }

    #[test]
    fn remove_for_non_existent_buffer_returns_none() {
        let mut bc = BufferCollection::new();
        assert_eq!(bc.remove(1), None);
    }

    #[test]
    fn remove_for_buffer_in_collection_returns_buffer() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.new_empty_buffer();
        let id = b.id;
        bc.insert(b);

        let b2 = bc.remove(id).unwrap().into_inner();
        assert_eq!(id, b2.id());
        assert_eq!(0, bc.len());
    }

    #[test]
    fn find_by_filename_for_filename_not_in_collection_returns_none() {
        let mut bc = BufferCollection::new();
        let result = bc.find_by_filename("/c/temp/feeeegfxgdg");
        assert_eq!(result, None);
    }

    #[test]
    fn find_by_filename_for_filename_in_collection_returns_buffer() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.open_file("/c/foo.txt");
        let id = b.id;
        bc.insert(b);

        let result = bc.find_by_filename("/c/foo.txt").unwrap();
        assert_eq!(result.borrow().id(), id);
    }
}
<commit_msg>Buffers: add some comments about next steps.<commit_after>use std::collections::HashMap;
use std::collections::hash_map::Keys;
use std::cell::RefCell;
use std::ops::Index;
use std::path::Path;

use super::{Buffer, BufferId};

/// Creates, manages and deletes all the buffers in Qork, maintaining the various invariants that
/// we expect from the buffers. Firstly, if a buffer is backed by a file, a second buffer on that
/// file cannot be created. Secondly, all buffers have unique identity.
///
/// Note that a Buffer is very different from a BufferView.
pub struct BufferCollection {
    current_buffer: BufferId,
    buffers: HashMap<BufferId, RefCell<Buffer>>
}

impl BufferCollection {
    pub fn new() -> BufferCollection {
        BufferCollection {
            current_buffer: -1,
            buffers: HashMap::with_capacity(20)
        }
    }

    pub fn len(&self) -> usize {
        self.buffers.len()
    }

    pub fn current_buffer(&self) -> BufferId {
        self.current_buffer
    }

    pub fn set_current_buffer(&mut self, buffer_id: BufferId) -> bool {
        if self.buffers.contains_key(&buffer_id) {
            self.current_buffer = buffer_id;
            return true;
        } else {
            return false;
        }
    }

    pub fn is_empty(&self) -> bool {
        self.buffers.is_empty()
    }

    pub fn get(&self, buffer_id: BufferId) -> Option<&RefCell<Buffer>> {
         self.buffers.get(&buffer_id)
    }

    pub fn keys(&self) -> Keys<BufferId, RefCell<Buffer>> {
         self.buffers.keys()
    }

    pub fn insert(&mut self, buffer: Buffer) {
        self.buffers.insert(buffer.id(), RefCell::new(buffer));
    }

    pub fn remove(&mut self, buffer_id: BufferId) -> Option<RefCell<Buffer>> {
        self.buffers.remove(&buffer_id)
    }

    pub fn find_by_filename<P : AsRef<Path>>(&mut self, filename: P) -> Option<&RefCell<Buffer>> {
        self.buffers.values().find(|refcell| refcell.borrow().filename.as_ref().map_or(false, |f| f == filename.as_ref()))
    }

    // Needs a buffer factory passed in. Check to see if the file is already open. If it is, return
    // the id of the first buffer rather than creating a new one.
    pub fn open_file() {}
    // Saves a buffer, but only if it already has a filename. Set changed to false.
    pub fn save_buffer() {}
    // Saves a buffer to a specific filename. Might need to allocate a new title. Can change
    // the filename that a buffer is saved to. Set changed to false.
    pub fn save_buffer_as() {}
    // Not sure we need this, it is really just remove disguised.
    pub fn close_buffer() {}

    // We also need a filename pre-processor better than just expand_variables.
    // It should be able to deal with relative names, trying to find a file relative to the
    // current buffer's directory (for working in projects), or failing that, to the cwd.

    // Title algorithm. We need the ability to uniqueify buffer names. Once a suffix number is
    // assigned it is never changed. They can be reused, or even not used (we only allocate them
    // for our convenience, and they do not need to go up monotonically like buffer ids do).
    // For new buffers not backed by a file "new", then "new<1>" etc.
    // For buffers backed by a file, the leaf filename, then <1> etc.
}

impl Index<BufferId> for BufferCollection {
    type Output = RefCell<Buffer>;

    fn index(&self, buffer_id: BufferId) -> &RefCell<Buffer> {
        &self.buffers[&buffer_id]
    }
}

#[cfg(test)]
mod buffer_collection_tests {
    use super::*;
    use std::path::PathBuf;
    use super::super::BufferFactory;

    #[test]
    fn is_empty_for_empty_collection_returns_true() {
        let bc = BufferCollection::new();
        assert!(bc.is_empty());
    }

    #[test]
    fn len_for_empty_collection_returns_zero() {
        let bc = BufferCollection::new();
        assert_eq!(0, bc.len());
    }

    #[test]
    fn len_for_non_empty_collection_returns_length() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.new_empty_buffer();
        bc.insert(b);

        assert_eq!(1, bc.len());
    }

    #[test]
    fn get_for_empty_collection_returns_false() {
        let bc = BufferCollection::new();
        assert!(bc.get(0).is_none());
    }

    #[test]
    fn get_for_id_not_in_collection_returns_none() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.new_empty_buffer();
        let id = b.id;
        bc.insert(b);
        assert!(bc.get(id + 1).is_none());
    }

    #[test]
    fn get_for_id_in_collection_returns_buffer() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.new_empty_buffer();
        let id = b.id;
        bc.insert(b);

        let result = bc.get(id).unwrap().borrow();
        assert_eq!(id, result.id());

    }

    #[test]
    fn remove_for_non_existent_buffer_returns_none() {
        let mut bc = BufferCollection::new();
        assert_eq!(bc.remove(1), None);
    }

    #[test]
    fn remove_for_buffer_in_collection_returns_buffer() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.new_empty_buffer();
        let id = b.id;
        bc.insert(b);

        let b2 = bc.remove(id).unwrap().into_inner();
        assert_eq!(id, b2.id());
        assert_eq!(0, bc.len());
    }

    #[test]
    fn find_by_filename_for_filename_not_in_collection_returns_none() {
        let mut bc = BufferCollection::new();
        let result = bc.find_by_filename("/c/temp/feeeegfxgdg");
        assert_eq!(result, None);
    }

    #[test]
    fn find_by_filename_for_filename_in_collection_returns_buffer() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.open_file("/c/foo.txt");
        let id = b.id;
        bc.insert(b);

        let result = bc.find_by_filename("/c/foo.txt").unwrap();
        assert_eq!(result.borrow().id(), id);
    }
}
<|endoftext|>