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

use codemap;
use codemap::{FileMap, Loc, Pos, ExpandedFrom, span};
use ext::base::*;
use ext::base;
use ext::build::{mk_base_vec_e, mk_uint, mk_u8, mk_base_str};
use print::pprust;

use core::io;
use core::prelude::*;
use core::result;
use core::str;
use core::vec;

fn topmost_expn_info(expn_info: @codemap::ExpnInfo) -> @codemap::ExpnInfo {
    let ExpandedFrom({call_site, _}) = *expn_info;
    match call_site.expn_info {
        Some(next_expn_info) => {
            let ExpandedFrom({callie: {name, _}, _}) = *next_expn_info;
            // Don't recurse into file using "include!"
            if name == ~"include" { return expn_info; }

            topmost_expn_info(next_expn_info)
        },
        None => expn_info
    }
}

/* line!(): expands to the current line number */
pub fn expand_line(cx: ext_ctxt, sp: span, tts: ~[ast::token_tree])
    -> base::MacResult {
    base::check_zero_tts(cx, sp, tts, "line!");

    let topmost = topmost_expn_info(cx.backtrace().get());
    let loc = cx.codemap().lookup_char_pos(topmost.call_site.lo);

    base::MRExpr(mk_uint(cx, topmost.call_site, loc.line))
}

/* col!(): expands to the current column number */
pub fn expand_col(cx: ext_ctxt, sp: span, tts: ~[ast::token_tree])
    -> base::MacResult {
    base::check_zero_tts(cx, sp, tts, "col!");

    let topmost = topmost_expn_info(cx.backtrace().get());
    let loc = cx.codemap().lookup_char_pos(topmost.call_site.lo);
    base::MRExpr(mk_uint(cx, topmost.call_site, loc.col.to_uint()))
}

/* file!(): expands to the current filename */
/* The filemap (`loc.file`) contains a bunch more information we could spit
 * out if we wanted. */
pub fn expand_file(cx: ext_ctxt, sp: span, tts: ~[ast::token_tree])
    -> base::MacResult {
    base::check_zero_tts(cx, sp, tts, "file!");

    let topmost = topmost_expn_info(cx.backtrace().get());
    let Loc { file: @FileMap { name: filename, _ }, _ } =
        cx.codemap().lookup_char_pos(topmost.call_site.lo);
    base::MRExpr(mk_base_str(cx, topmost.call_site, filename))
}

pub fn expand_stringify(cx: ext_ctxt, sp: span, tts: ~[ast::token_tree])
    -> base::MacResult {
    let s = pprust::tts_to_str(tts, cx.parse_sess().interner);
    base::MRExpr(mk_base_str(cx, sp, s))
}

pub fn expand_mod(cx: ext_ctxt, sp: span, tts: ~[ast::token_tree])
    -> base::MacResult {
    base::check_zero_tts(cx, sp, tts, "module_path!");
    base::MRExpr(mk_base_str(cx, sp,
                              str::connect(cx.mod_path().map(
                                  |x| cx.str_of(*x)), ~"::")))
}

pub fn expand_include(cx: ext_ctxt, sp: span, tts: ~[ast::token_tree])
    -> base::MacResult {
    let file = get_single_str_from_tts(cx, sp, tts, "include!");
    let p = parse::new_sub_parser_from_file(
        cx.parse_sess(), cx.cfg(),
        &res_rel_file(cx, sp, &Path(file)), sp);
    base::MRExpr(p.parse_expr())
}

pub fn expand_include_str(cx: ext_ctxt, sp: span, tts: ~[ast::token_tree])
    -> base::MacResult {
    let file = get_single_str_from_tts(cx, sp, tts, "include_str!");
    let res = io::read_whole_file_str(&res_rel_file(cx, sp, &Path(file)));
    match res {
      result::Ok(_) => { /* Continue. */ }
      result::Err(ref e) => {
        cx.parse_sess().span_diagnostic.handler().fatal((*e));
      }
    }

    base::MRExpr(mk_base_str(cx, sp, result::unwrap(res)))
}

pub fn expand_include_bin(cx: ext_ctxt, sp: span, tts: ~[ast::token_tree])
    -> base::MacResult {
    let file = get_single_str_from_tts(cx, sp, tts, "include_bin!");
    match io::read_whole_file(&res_rel_file(cx, sp, &Path(file))) {
      result::Ok(src) => {
        let u8_exprs = vec::map(src, |char| {
            mk_u8(cx, sp, *char)
        });
        base::MRExpr(mk_base_vec_e(cx, sp, u8_exprs))
      }
      result::Err(ref e) => {
        cx.parse_sess().span_diagnostic.handler().fatal((*e))
      }
    }
}

fn res_rel_file(cx: ext_ctxt, sp: codemap::span, arg: &Path) -> Path {
    // NB: relative paths are resolved relative to the compilation unit
    if !arg.is_absolute {
        let cu = Path(cx.codemap().span_to_filename(sp));
        cu.dir_path().push_many(arg.components)
    } else {
        copy *arg
    }
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
//
<commit_msg>Fix license block<commit_after>// Copyright 2012-2013 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.

use codemap;
use codemap::{FileMap, Loc, Pos, ExpandedFrom, span};
use ext::base::*;
use ext::base;
use ext::build::{mk_base_vec_e, mk_uint, mk_u8, mk_base_str};
use print::pprust;

use core::io;
use core::prelude::*;
use core::result;
use core::str;
use core::vec;

fn topmost_expn_info(expn_info: @codemap::ExpnInfo) -> @codemap::ExpnInfo {
    let ExpandedFrom({call_site, _}) = *expn_info;
    match call_site.expn_info {
        Some(next_expn_info) => {
            let ExpandedFrom({callie: {name, _}, _}) = *next_expn_info;
            // Don't recurse into file using "include!"
            if name == ~"include" { return expn_info; }

            topmost_expn_info(next_expn_info)
        },
        None => expn_info
    }
}

/* line!(): expands to the current line number */
pub fn expand_line(cx: ext_ctxt, sp: span, tts: ~[ast::token_tree])
    -> base::MacResult {
    base::check_zero_tts(cx, sp, tts, "line!");

    let topmost = topmost_expn_info(cx.backtrace().get());
    let loc = cx.codemap().lookup_char_pos(topmost.call_site.lo);

    base::MRExpr(mk_uint(cx, topmost.call_site, loc.line))
}

/* col!(): expands to the current column number */
pub fn expand_col(cx: ext_ctxt, sp: span, tts: ~[ast::token_tree])
    -> base::MacResult {
    base::check_zero_tts(cx, sp, tts, "col!");

    let topmost = topmost_expn_info(cx.backtrace().get());
    let loc = cx.codemap().lookup_char_pos(topmost.call_site.lo);
    base::MRExpr(mk_uint(cx, topmost.call_site, loc.col.to_uint()))
}

/* file!(): expands to the current filename */
/* The filemap (`loc.file`) contains a bunch more information we could spit
 * out if we wanted. */
pub fn expand_file(cx: ext_ctxt, sp: span, tts: ~[ast::token_tree])
    -> base::MacResult {
    base::check_zero_tts(cx, sp, tts, "file!");

    let topmost = topmost_expn_info(cx.backtrace().get());
    let Loc { file: @FileMap { name: filename, _ }, _ } =
        cx.codemap().lookup_char_pos(topmost.call_site.lo);
    base::MRExpr(mk_base_str(cx, topmost.call_site, filename))
}

pub fn expand_stringify(cx: ext_ctxt, sp: span, tts: ~[ast::token_tree])
    -> base::MacResult {
    let s = pprust::tts_to_str(tts, cx.parse_sess().interner);
    base::MRExpr(mk_base_str(cx, sp, s))
}

pub fn expand_mod(cx: ext_ctxt, sp: span, tts: ~[ast::token_tree])
    -> base::MacResult {
    base::check_zero_tts(cx, sp, tts, "module_path!");
    base::MRExpr(mk_base_str(cx, sp,
                              str::connect(cx.mod_path().map(
                                  |x| cx.str_of(*x)), ~"::")))
}

pub fn expand_include(cx: ext_ctxt, sp: span, tts: ~[ast::token_tree])
    -> base::MacResult {
    let file = get_single_str_from_tts(cx, sp, tts, "include!");
    let p = parse::new_sub_parser_from_file(
        cx.parse_sess(), cx.cfg(),
        &res_rel_file(cx, sp, &Path(file)), sp);
    base::MRExpr(p.parse_expr())
}

pub fn expand_include_str(cx: ext_ctxt, sp: span, tts: ~[ast::token_tree])
    -> base::MacResult {
    let file = get_single_str_from_tts(cx, sp, tts, "include_str!");
    let res = io::read_whole_file_str(&res_rel_file(cx, sp, &Path(file)));
    match res {
      result::Ok(_) => { /* Continue. */ }
      result::Err(ref e) => {
        cx.parse_sess().span_diagnostic.handler().fatal((*e));
      }
    }

    base::MRExpr(mk_base_str(cx, sp, result::unwrap(res)))
}

pub fn expand_include_bin(cx: ext_ctxt, sp: span, tts: ~[ast::token_tree])
    -> base::MacResult {
    let file = get_single_str_from_tts(cx, sp, tts, "include_bin!");
    match io::read_whole_file(&res_rel_file(cx, sp, &Path(file))) {
      result::Ok(src) => {
        let u8_exprs = vec::map(src, |char| {
            mk_u8(cx, sp, *char)
        });
        base::MRExpr(mk_base_vec_e(cx, sp, u8_exprs))
      }
      result::Err(ref e) => {
        cx.parse_sess().span_diagnostic.handler().fatal((*e))
      }
    }
}

fn res_rel_file(cx: ext_ctxt, sp: codemap::span, arg: &Path) -> Path {
    // NB: relative paths are resolved relative to the compilation unit
    if !arg.is_absolute {
        let cu = Path(cx.codemap().span_to_filename(sp));
        cu.dir_path().push_many(arg.components)
    } else {
        copy *arg
    }
}

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


<commit_before>use std::ascii::AsciiExt;
use std::cmp::min as min;

fn main() {
}

fn score(choice: &str, query: &str) -> f64 {
  if query.len() == 0 {
    return 1.0;
  }
  if choice.len() == 0 {
    return 0.0;
  }

  let query = query.to_ascii_lower();
  let choice = choice.to_ascii_lower();

  match compute_match_length(choice.as_slice(), query.as_slice()) {
    None => return 0.0,
    Some(match_length) => {
      let score = query.len() as f64 / match_length as f64;
      return score as f64 / choice.len() as f64;
    }
  }
}

fn compute_match_length(string: &str, chars: &str) -> Option<uint> {
  let first_char = chars.char_at(0);
  let rest = chars.slice(1, chars.len());
  let indices = find_char_in_string(string, first_char);

  let mut current_min: Option<uint> = None;
  for i in indices.iter() {
    let last_index = find_end_of_match(string, rest, *i);
    if last_index.is_some() {
      let idx = last_index.unwrap() - *i + 1;
      if current_min.is_some() {
        let cm = min(current_min.unwrap(), idx);
        current_min = Some(cm);
      } else {
        current_min = Some(idx)
      }
    }
  }
  return current_min;
}

fn find_char_in_string(string: &str, char: char) -> Vec<uint> {
  let mut indices = Vec::new();
  let mut i = 0;
  for c in string.chars() {
    if c == char {
      indices.push(i);
    }
    i = i + 1;
  }
  return indices;
}

fn find_end_of_match(string: &str, rest_of_query: &str, first_index: uint) -> Option<uint> {
  let mut last_index = first_index + 1;
  for c in rest_of_query.chars() {
    let current_substring = string.slice_chars(last_index, string.len());
    match current_substring.find(c) {
      None => return None,
      Some(ref i) => {
        last_index += *i + 1;
      }
    }
  }
  return Some(last_index - 1);
}

#[test]
fn find_end_of_match_test() {
  assert!(find_end_of_match("a", "a", 0) == None);
  assert!(find_end_of_match("ba", "a", 1) == None);
  assert!(find_end_of_match("aaa", "aa", 0) == Some(2));
  assert!(find_end_of_match("aaa", "b", 0) == None);
  assert!(find_end_of_match("this is a long match", "this is a match", 0) == None);
  assert!(find_end_of_match("this is a long match", "his is a match", 0) == Some(19));
}

#[test]
fn basic_scoring() {
  assert!(score("", "a") == 0.0);
  assert!(score("a", "") == 1.0);
  assert!(score("short", "longer") == 0.0);
  assert!(score("a", "b") == 0.0);
  assert!(score("ab", "ac") == 0.0);

  assert!(score("a", "a") > 0.0);
  assert!(score("ab", "a") > 0.0);
  assert!(score("ba", "a") > 0.0);
  assert!(score("bab", "a") > 0.0);
  assert!(score("babababab", "aaaa") > 0.0);

  assert!(score("a", "a") == 1_f64 / "a".len() as f64);
  assert!(score("ab", "ab") == 0.5);
  assert!(score("a long string", "a long string") == 1_f64 / "a long string".len() as f64);
  assert!(score("spec/search_spec.rb", "sear") == 1_f64 / "spec/search_spec.rb".len() as f64);
}

#[test]
fn character_matching() {
  assert!(score("/! symbols $^", "/!$^") > 0.0);

  assert!(score("a", "A") == 1.0);
  assert!(score("A", "a") == 1.0);

  assert!(score("a", "aa") == 0.0);
}

#[test]
fn match_equality() {
  assert!(score("selecta.gemspec", "asp") > score("algorithm4_spec.rb", "asp"));
  assert!(score("README.md", "em") > score("benchmark.rb", "em"));
  assert!(score("search.rb", "sear") > score("spec/search_spec.rb", "sear"));

  assert!(score("fbb", "fbb") > score("foo bar baz", "fbb"));
  assert!(score("foo", "foo") > score("longer foo", "foo"));
  assert!(score("foo", "foo") > score("foo longer", "foo"));
  assert!(score("1/2/3/4", "1/2/3") > score("1/9/2/3/4", "1/2/3"));

  assert!(score("long 12 long", "12") > score("1 long 2", "12"));

  assert!(score("121padding2", "12") == 1.0 / "121padding2".len() as f64);
  assert!(score("1padding212", "12") == 1.0 / "1padding212".len() as f64);
}
<commit_msg>Use assert_eq! instead of assert! for equality assertions<commit_after>use std::ascii::AsciiExt;
use std::cmp::min as min;

fn main() {
}

fn score(choice: &str, query: &str) -> f64 {
  if query.len() == 0 {
    return 1.0;
  }
  if choice.len() == 0 {
    return 0.0;
  }

  let query = query.to_ascii_lower();
  let choice = choice.to_ascii_lower();

  match compute_match_length(choice.as_slice(), query.as_slice()) {
    None => return 0.0,
    Some(match_length) => {
      let score = query.len() as f64 / match_length as f64;
      return score as f64 / choice.len() as f64;
    }
  }
}

fn compute_match_length(string: &str, chars: &str) -> Option<uint> {
  let first_char = chars.char_at(0);
  let rest = chars.slice(1, chars.len());
  let indices = find_char_in_string(string, first_char);

  let mut current_min: Option<uint> = None;
  for i in indices.iter() {
    let last_index = find_end_of_match(string, rest, *i);
    if last_index.is_some() {
      let idx = last_index.unwrap() - *i + 1;
      if current_min.is_some() {
        let cm = min(current_min.unwrap(), idx);
        current_min = Some(cm);
      } else {
        current_min = Some(idx)
      }
    }
  }
  return current_min;
}

fn find_char_in_string(string: &str, char: char) -> Vec<uint> {
  let mut indices = Vec::new();
  let mut i = 0;
  for c in string.chars() {
    if c == char {
      indices.push(i);
    }
    i = i + 1;
  }
  return indices;
}

fn find_end_of_match(string: &str, rest_of_query: &str, first_index: uint) -> Option<uint> {
  let mut last_index = first_index + 1;
  for c in rest_of_query.chars() {
    let current_substring = string.slice_chars(last_index, string.len());
    match current_substring.find(c) {
      None => return None,
      Some(ref i) => {
        last_index += *i + 1;
      }
    }
  }
  return Some(last_index - 1);
}

#[test]
fn find_end_of_match_test() {
  assert_eq!(find_end_of_match("a", "a", 0), None);
  assert_eq!(find_end_of_match("ba", "a", 1), None);
  assert_eq!(find_end_of_match("aaa", "aa", 0), Some(2));
  assert_eq!(find_end_of_match("aaa", "b", 0), None);
  assert_eq!(find_end_of_match("this is a long match", "this is a match", 0), None);
  assert_eq!(find_end_of_match("this is a long match", "his is a match", 0), Some(19));
}

#[test]
fn basic_scoring() {
  assert_eq!(score("", "a"), 0.0);
  assert_eq!(score("a", ""), 1.0);
  assert_eq!(score("short", "longer"), 0.0);
  assert_eq!(score("a", "b"), 0.0);
  assert_eq!(score("ab", "ac"), 0.0);

  assert!(score("a", "a") > 0.0);
  assert!(score("ab", "a") > 0.0);
  assert!(score("ba", "a") > 0.0);
  assert!(score("bab", "a") > 0.0);
  assert!(score("babababab", "aaaa") > 0.0);

  assert_eq!(score("a", "a"), 1_f64 / "a".len() as f64);
  assert_eq!(score("ab", "ab"), 0.5);
  assert_eq!(score("a long string", "a long string"), 1_f64 / "a long string".len() as f64);
  assert_eq!(score("spec/search_spec.rb", "sear"), 1_f64 / "spec/search_spec.rb".len() as f64);
}

#[test]
fn character_matching() {
  assert!(score("/! symbols $^", "/!$^") > 0.0);

  assert_eq!(score("a", "A"), 1.0);
  assert_eq!(score("A", "a"), 1.0);

  assert_eq!(score("a", "aa"), 0.0);
}

#[test]
fn match_equality() {
  assert!(score("selecta.gemspec", "asp") > score("algorithm4_spec.rb", "asp"));
  assert!(score("README.md", "em") > score("benchmark.rb", "em"));
  assert!(score("search.rb", "sear") > score("spec/search_spec.rb", "sear"));

  assert!(score("fbb", "fbb") > score("foo bar baz", "fbb"));
  assert!(score("foo", "foo") > score("longer foo", "foo"));
  assert!(score("foo", "foo") > score("foo longer", "foo"));
  assert!(score("1/2/3/4", "1/2/3") > score("1/9/2/3/4", "1/2/3"));

  assert!(score("long 12 long", "12") > score("1 long 2", "12"));

  assert_eq!(score("121padding2", "12"), 1.0 / "121padding2".len() as f64);
  assert_eq!(score("1padding212", "12"), 1.0 / "1padding212".len() as f64);
}
<|endoftext|>


<commit_before>extern crate cc;

fn main() {
    cc::Build::new()
        .cpp(true)
        .file("src/wrapper.cpp")
        .file("src/vendor/SPIRV-Cross/spirv_cfg.cpp")
        .file("src/vendor/SPIRV-Cross/spirv_cross.cpp")
        .file("src/vendor/SPIRV-Cross/spirv_glsl.cpp")
        .file("src/vendor/SPIRV-Cross/spirv_hlsl.cpp")
        .file("src/vendor/SPIRV-Cross/spirv_msl.cpp")
        .flag_if_supported("-std=c++14")
        .compile("spirv-cross-rust-wrapper");
}
<commit_msg>Attempt to fix appveyor<commit_after>extern crate cc;

fn main() {
    cc::Build::new()
        .cpp(true)
        .include("src")
        .file("src/wrapper.cpp")
        .file("src/vendor/SPIRV-Cross/spirv_cfg.cpp")
        .file("src/vendor/SPIRV-Cross/spirv_cross.cpp")
        .file("src/vendor/SPIRV-Cross/spirv_glsl.cpp")
        .file("src/vendor/SPIRV-Cross/spirv_hlsl.cpp")
        .file("src/vendor/SPIRV-Cross/spirv_msl.cpp")
        .flag_if_supported("-std=c++14")
        .compile("spirv-cross-rust-wrapper");
}
<|endoftext|>


<commit_before>use super::{Error, Hashes, Index, Mapper, Record, Records, Result,
            TransactionRecord};
use mysql;
use std::collections::HashMap;
use std::collections::btree_map::{BTreeMap, Entry};
use std::sync::{Arc, Mutex, MutexGuard, RwLock, RwLockWriteGuard};

pub struct TransactionMapper {
  counter: Mutex<u64>,
  records: RwLock<Records<TransactionRecord>>,
  hashes: RwLock<Hashes>,
  indices: [RwLock<Records<Index>>; 2],
}

type FetchManyResult = Result<
  Vec<(u64, String, Arc<Mutex<TransactionRecord>>)>,
>;

type FetchIndexResult<'a> = Result<
  (
    MutexGuard<'a, Index>,
    Vec<(u64, Arc<Mutex<TransactionRecord>>)>,
  ),
>;

impl Mapper for TransactionMapper {
  type Record = TransactionRecord;

  fn new(conn: &mut mysql::Conn, retry_interval: u64) -> Result<Self> {
    let counter = Self::init_counter(
      conn,
      retry_interval,
      r"SELECT id_tx FROM tx ORDER BY id_tx DESC LIMIT 1",
    )?;
    let records = RwLock::new(BTreeMap::new());
    let hashes = RwLock::new(HashMap::new());
    let indices = [RwLock::new(BTreeMap::new()), RwLock::new(BTreeMap::new())];
    Ok(Self {
      counter,
      records,
      hashes,
      indices,
    })
  }

  fn counter(&self) -> &Mutex<u64> {
    &self.counter
  }

  fn records(&self) -> &RwLock<Records<TransactionRecord>> {
    &self.records
  }

  fn hashes(&self) -> &RwLock<Hashes> {
    &self.hashes
  }

  fn indices(&self) -> &[RwLock<Records<Index>>] {
    &self.indices
  }

  fn fill_indices(
    indices: &mut [RwLockWriteGuard<Records<Index>>],
    record: &TransactionRecord,
    skip_index: Option<(usize, u64)>,
  ) {
    let inner = if record.is_persisted() {
      None
    } else {
      Some(Vec::new())
    };
    indices[0].insert(record.id(), Arc::new(Mutex::new(inner.clone())));
    indices[1].insert(record.id(), Arc::new(Mutex::new(inner)));
    if let Some(id_trunk) = record.id_trunk() {
      match skip_index {
        Some((0, id)) if id == id_trunk => {}
        _ => if let Some(index) = indices[0].get(&id_trunk) {
          debug!("Mutex lock");
          let mut index = index.lock().unwrap();
          debug!("Mutex acquire");
          record.fill_index(&mut index);
        },
      }
    }
    if let Some(id_branch) = record.id_branch() {
      match skip_index {
        Some((1, id)) if id == id_branch => {}
        _ => if let Some(index) = indices[1].get(&id_branch) {
          debug!("Mutex lock");
          let mut index = index.lock().unwrap();
          debug!("Mutex acquire");
          record.fill_index(&mut index);
        },
      }
    }
  }
}

impl TransactionMapper {
  pub fn fetch_many(
    &self,
    conn: &mut mysql::Conn,
    mut input: Vec<&str>,
  ) -> FetchManyResult {
    input.dedup();
    let cached = {
      debug!("Mutex lock");
      let records = self.records.read().unwrap();
      debug!("Mutex lock/acquire");
      let hashes = self.hashes.read().unwrap();
      debug!("Mutex acquire");
      input
        .iter()
        .filter_map(|&hash| {
          hashes
            .get(hash)
            .and_then(|&id| records.get(&id).map(|x| (hash, (id, x.clone()))))
        })
        .collect::<HashMap<_, _>>()
    };
    let missing = input
      .iter()
      .filter(|&hash| !cached.contains_key(hash))
      .cloned()
      .collect::<Vec<_>>();
    let found = TransactionRecord::find_by_hashes(conn, missing)?;
    debug!("Mutex lock");
    let mut records = self.records.write().unwrap();
    debug!("Mutex lock/acquire");
    let mut hashes = self.hashes.write().unwrap();
    debug!("Mutex lock/acquire");
    let mut indices = self.lock_indices();
    debug!("Mutex acquire");
    let mut output = input
      .into_iter()
      .map(|hash| {
        cached
          .get(hash)
          .map(|&(id_tx, ref record)| {
            (id_tx, hash.to_owned(), record.clone())
          })
          .unwrap_or_else(|| {
            hashes
              .get(hash)
              .and_then(|&id_tx| {
                records
                  .get(&id_tx)
                  .map(|record| (id_tx, hash.to_owned(), record.clone()))
              })
              .unwrap_or_else(|| {
                let record = found
                  .iter()
                  .find(|record| record.hash() == hash)
                  .cloned()
                  .unwrap_or_else(|| {
                    TransactionRecord::placeholder(
                      hash.to_owned(),
                      self.next_id(),
                    )
                  });
                let id_tx = record.id();
                hashes.insert(hash.to_owned(), id_tx);
                Self::fill_indices(&mut indices, &record, None);
                let wrapper = Arc::new(Mutex::new(record));
                records.insert(id_tx, wrapper.clone());
                (id_tx, hash.to_owned(), wrapper)
              })
          })
      })
      .collect::<Vec<_>>();
    output.sort_unstable_by_key(|&(id_tx, _, _)| id_tx);
    Ok(output)
  }

  pub fn trunk_index(&self, id: u64) -> Option<Arc<Mutex<Index>>> {
    debug!("Mutex lock");
    let trunks = self.indices[0].read().unwrap();
    debug!("Mutex acquire");
    trunks.get(&id).cloned()
  }

  pub fn branch_index(&self, id: u64) -> Option<Arc<Mutex<Index>>> {
    debug!("Mutex lock");
    let branches = self.indices[1].read().unwrap();
    debug!("Mutex acquire");
    branches.get(&id).cloned()
  }

  pub fn fetch_trunk<'a>(
    &self,
    conn: &mut mysql::Conn,
    id: u64,
    index: &'a Mutex<Index>,
  ) -> FetchIndexResult<'a> {
    self.fetch_index(
      conn,
      id,
      index,
      Some((0, id)),
      TransactionRecord::find_trunk,
    )
  }

  pub fn fetch_branch<'a>(
    &self,
    conn: &mut mysql::Conn,
    id: u64,
    index: &'a Mutex<Index>,
  ) -> FetchIndexResult<'a> {
    self.fetch_index(
      conn,
      id,
      index,
      Some((1, id)),
      TransactionRecord::find_branch,
    )
  }

  pub fn fetch_bundle<'a>(
    &self,
    conn: &mut mysql::Conn,
    id: u64,
    index: &'a Mutex<Index>,
  ) -> FetchIndexResult<'a> {
    self.fetch_index(conn, id, index, None, TransactionRecord::find_bundle)
  }

  fn fetch_index<'a, F>(
    &self,
    conn: &mut mysql::Conn,
    id: u64,
    index: &'a Mutex<Index>,
    skip_index: Option<(usize, u64)>,
    f: F,
  ) -> FetchIndexResult<'a>
  where
    F: Fn(&mut mysql::Conn, u64)
      -> Result<Vec<TransactionRecord>>,
  {
    'outer: loop {
      {
        let missing = {
          debug!("Mutex lock");
          let records = self.records.write().unwrap();
          debug!("Mutex lock/acquire");
          let index = index.lock().unwrap();
          debug!("Mutex acquire");
          index.as_ref().map(|index| {
            index
              .iter()
              .filter(|id_tx| !records.contains_key(id_tx))
              .cloned()
              .collect::<Vec<_>>()
          })
        };
        if let Some(missing) = missing {
          let found = TransactionRecord::find_by_ids(conn, &missing)?;
          debug!("Mutex lock");
          let mut records = self.records.write().unwrap();
          debug!("Mutex lock/acquire");
          let mut hashes = self.hashes.write().unwrap();
          debug!("Mutex lock/acquire");
          let mut indices = self.lock_indices();
          debug!("Mutex lock/acquire");
          let index = index.lock().unwrap();
          debug!("Mutex acquire");
          if index.is_some() {
            let mut results = Vec::new();
            if let Some(ref index) = *index {
              for &id_tx in index {
                let record = match records.entry(id_tx) {
                  Entry::Occupied(entry) => (id_tx, entry.get().clone()),
                  Entry::Vacant(entry) => {
                    match found.iter().find(|record| record.id() == id_tx) {
                      Some(record) => {
                        let id_tx = record.id();
                        hashes.insert(record.hash().to_owned(), id_tx);
                        Self::fill_indices(&mut indices, record, skip_index);
                        let wrapper = Arc::new(Mutex::new(record.clone()));
                        entry.insert(wrapper.clone());
                        (id_tx, wrapper)
                      }
                      None => if missing.contains(&id_tx) {
                        return Err(Error::RecordNotFound(id_tx));
                      } else {
                        continue 'outer;
                      },
                    }
                  }
                };
                results.push(record);
              }
            }
            return Ok((index, results));
          }
        }
      }
      match f(conn, id) {
        Ok(found) => {
          debug!("Mutex lock");
          let mut records = self.records.write().unwrap();
          debug!("Mutex lock/acquire");
          let mut hashes = self.hashes.write().unwrap();
          debug!("Mutex lock/acquire");
          let mut indices = self.lock_indices();
          debug!("Mutex lock/acquire");
          let mut index = index.lock().unwrap();
          debug!("Mutex acquire");
          if index.is_none() {
            let mut records = found
              .into_iter()
              .map(|record| {
                let id_tx = record.id();
                let record = records.entry(id_tx).or_insert_with(|| {
                  hashes.insert(record.hash().to_owned(), id_tx);
                  Self::fill_indices(&mut indices, &record, skip_index);
                  Arc::new(Mutex::new(record))
                });
                (id_tx, record.clone())
              })
              .collect::<Vec<_>>();
            records.sort_unstable_by_key(|&(id_tx, _)| id_tx);
            let mut ids =
              records.iter().map(|&(id_tx, _)| id_tx).collect::<Vec<_>>();
            ids.dedup();
            *index = Some(ids);
            return Ok((index, records));
          }
        }
        Err(err) => return Err(err),
      }
    }
  }
}
<commit_msg>Performance fix<commit_after>use super::{Error, Hashes, Index, Mapper, Record, Records, Result,
            TransactionRecord};
use mysql;
use std::collections::HashMap;
use std::collections::btree_map::{BTreeMap, Entry};
use std::sync::{Arc, Mutex, MutexGuard, RwLock, RwLockWriteGuard};

pub struct TransactionMapper {
  counter: Mutex<u64>,
  records: RwLock<Records<TransactionRecord>>,
  hashes: RwLock<Hashes>,
  indices: [RwLock<Records<Index>>; 2],
}

type FetchManyResult = Result<
  Vec<(u64, String, Arc<Mutex<TransactionRecord>>)>,
>;

type FetchIndexResult<'a> = Result<
  (
    MutexGuard<'a, Index>,
    Vec<(u64, Arc<Mutex<TransactionRecord>>)>,
  ),
>;

impl Mapper for TransactionMapper {
  type Record = TransactionRecord;

  fn new(conn: &mut mysql::Conn, retry_interval: u64) -> Result<Self> {
    let counter = Self::init_counter(
      conn,
      retry_interval,
      r"SELECT id_tx FROM tx ORDER BY id_tx DESC LIMIT 1",
    )?;
    let records = RwLock::new(BTreeMap::new());
    let hashes = RwLock::new(HashMap::new());
    let indices = [RwLock::new(BTreeMap::new()), RwLock::new(BTreeMap::new())];
    Ok(Self {
      counter,
      records,
      hashes,
      indices,
    })
  }

  fn counter(&self) -> &Mutex<u64> {
    &self.counter
  }

  fn records(&self) -> &RwLock<Records<TransactionRecord>> {
    &self.records
  }

  fn hashes(&self) -> &RwLock<Hashes> {
    &self.hashes
  }

  fn indices(&self) -> &[RwLock<Records<Index>>] {
    &self.indices
  }

  fn fill_indices(
    indices: &mut [RwLockWriteGuard<Records<Index>>],
    record: &TransactionRecord,
    skip_index: Option<(usize, u64)>,
  ) {
    let inner = if record.is_persisted() {
      None
    } else {
      Some(Vec::new())
    };
    indices[0].insert(record.id(), Arc::new(Mutex::new(inner.clone())));
    indices[1].insert(record.id(), Arc::new(Mutex::new(inner)));
    if let Some(id_trunk) = record.id_trunk() {
      match skip_index {
        Some((0, id)) if id == id_trunk => {}
        _ => if let Some(index) = indices[0].get(&id_trunk) {
          debug!("Mutex lock");
          let mut index = index.lock().unwrap();
          debug!("Mutex acquire");
          record.fill_index(&mut index);
        },
      }
    }
    if let Some(id_branch) = record.id_branch() {
      match skip_index {
        Some((1, id)) if id == id_branch => {}
        _ => if let Some(index) = indices[1].get(&id_branch) {
          debug!("Mutex lock");
          let mut index = index.lock().unwrap();
          debug!("Mutex acquire");
          record.fill_index(&mut index);
        },
      }
    }
  }
}

impl TransactionMapper {
  pub fn fetch_many(
    &self,
    conn: &mut mysql::Conn,
    mut input: Vec<&str>,
  ) -> FetchManyResult {
    input.dedup();
    let cached = {
      debug!("Mutex lock");
      let records = self.records.read().unwrap();
      debug!("Mutex lock/acquire");
      let hashes = self.hashes.read().unwrap();
      debug!("Mutex acquire");
      input
        .iter()
        .filter_map(|&hash| {
          hashes
            .get(hash)
            .and_then(|&id| records.get(&id).map(|x| (hash, (id, x.clone()))))
        })
        .collect::<HashMap<_, _>>()
    };
    let missing = input
      .iter()
      .filter(|&hash| !cached.contains_key(hash))
      .cloned()
      .collect();
    let found = TransactionRecord::find_by_hashes(conn, missing)?;
    debug!("Mutex lock");
    let mut records = self.records.write().unwrap();
    debug!("Mutex lock/acquire");
    let mut hashes = self.hashes.write().unwrap();
    debug!("Mutex lock/acquire");
    let mut indices = self.lock_indices();
    debug!("Mutex acquire");
    let mut output = input
      .into_iter()
      .map(|hash| {
        cached
          .get(hash)
          .map(|&(id_tx, ref record)| {
            (id_tx, hash.to_owned(), record.clone())
          })
          .unwrap_or_else(|| {
            hashes
              .get(hash)
              .and_then(|&id_tx| {
                records
                  .get(&id_tx)
                  .map(|record| (id_tx, hash.to_owned(), record.clone()))
              })
              .unwrap_or_else(|| {
                let record = found
                  .iter()
                  .find(|record| record.hash() == hash)
                  .cloned()
                  .unwrap_or_else(|| {
                    TransactionRecord::placeholder(
                      hash.to_owned(),
                      self.next_id(),
                    )
                  });
                let id_tx = record.id();
                hashes.insert(hash.to_owned(), id_tx);
                Self::fill_indices(&mut indices, &record, None);
                let wrapper = Arc::new(Mutex::new(record));
                records.insert(id_tx, wrapper.clone());
                (id_tx, hash.to_owned(), wrapper)
              })
          })
      })
      .collect::<Vec<_>>();
    output.sort_unstable_by_key(|&(id_tx, _, _)| id_tx);
    Ok(output)
  }

  pub fn trunk_index(&self, id: u64) -> Option<Arc<Mutex<Index>>> {
    debug!("Mutex lock");
    let trunks = self.indices[0].read().unwrap();
    debug!("Mutex acquire");
    trunks.get(&id).cloned()
  }

  pub fn branch_index(&self, id: u64) -> Option<Arc<Mutex<Index>>> {
    debug!("Mutex lock");
    let branches = self.indices[1].read().unwrap();
    debug!("Mutex acquire");
    branches.get(&id).cloned()
  }

  pub fn fetch_trunk<'a>(
    &self,
    conn: &mut mysql::Conn,
    id: u64,
    index: &'a Mutex<Index>,
  ) -> FetchIndexResult<'a> {
    self.fetch_index(
      conn,
      id,
      index,
      Some((0, id)),
      TransactionRecord::find_trunk,
    )
  }

  pub fn fetch_branch<'a>(
    &self,
    conn: &mut mysql::Conn,
    id: u64,
    index: &'a Mutex<Index>,
  ) -> FetchIndexResult<'a> {
    self.fetch_index(
      conn,
      id,
      index,
      Some((1, id)),
      TransactionRecord::find_branch,
    )
  }

  pub fn fetch_bundle<'a>(
    &self,
    conn: &mut mysql::Conn,
    id: u64,
    index: &'a Mutex<Index>,
  ) -> FetchIndexResult<'a> {
    self.fetch_index(conn, id, index, None, TransactionRecord::find_bundle)
  }

  fn fetch_index<'a, F>(
    &self,
    conn: &mut mysql::Conn,
    id: u64,
    index: &'a Mutex<Index>,
    skip_index: Option<(usize, u64)>,
    f: F,
  ) -> FetchIndexResult<'a>
  where
    F: Fn(&mut mysql::Conn, u64)
      -> Result<Vec<TransactionRecord>>,
  {
    'retry: loop {
      {
        let missing = {
          debug!("Mutex lock");
          let records = self.records.write().unwrap();
          debug!("Mutex lock/acquire");
          let index = index.lock().unwrap();
          debug!("Mutex acquire");
          let mut results = index.as_ref().map(|index| {
            index
              .iter()
              .map(|&id_tx| (id_tx, records.get(&id_tx).cloned()))
              .collect::<Vec<_>>()
          });
          if let Some(records) = results {
            if records.iter().all(|&(_, ref record)| record.is_some()) {
              let results = records
                .into_iter()
                .filter_map(
                  |(id_tx, record)| record.map(|record| (id_tx, record)),
                )
                .collect();
              return Ok((index, results));
            }
            results = Some(records);
          }
          results.map(|index| {
            index
              .into_iter()
              .filter_map(|(id_tx, record)| match record {
                Some(_) => None,
                None => Some(id_tx),
              })
              .collect::<Vec<_>>()
          })
        };
        if let Some(missing) = missing {
          let found = TransactionRecord::find_by_ids(conn, &missing)?;
          debug!("Mutex lock");
          let mut records = self.records.write().unwrap();
          debug!("Mutex lock/acquire");
          let mut hashes = self.hashes.write().unwrap();
          debug!("Mutex lock/acquire");
          let mut indices = self.lock_indices();
          debug!("Mutex lock/acquire");
          let index = index.lock().unwrap();
          debug!("Mutex acquire");
          if index.is_some() {
            let mut results = Vec::new();
            if let Some(ref index) = *index {
              for &id_tx in index {
                let record = match records.entry(id_tx) {
                  Entry::Occupied(entry) => (id_tx, entry.get().clone()),
                  Entry::Vacant(entry) => {
                    match found.iter().find(|record| record.id() == id_tx) {
                      Some(record) => {
                        let id_tx = record.id();
                        hashes.insert(record.hash().to_owned(), id_tx);
                        Self::fill_indices(&mut indices, record, skip_index);
                        let wrapper = Arc::new(Mutex::new(record.clone()));
                        entry.insert(wrapper.clone());
                        (id_tx, wrapper)
                      }
                      None => if missing.contains(&id_tx) {
                        return Err(Error::RecordNotFound(id_tx));
                      } else {
                        continue 'retry;
                      },
                    }
                  }
                };
                results.push(record);
              }
            }
            return Ok((index, results));
          }
        }
      }
      match f(conn, id) {
        Ok(found) => {
          debug!("Mutex lock");
          let mut records = self.records.write().unwrap();
          debug!("Mutex lock/acquire");
          let mut hashes = self.hashes.write().unwrap();
          debug!("Mutex lock/acquire");
          let mut indices = self.lock_indices();
          debug!("Mutex lock/acquire");
          let mut index = index.lock().unwrap();
          debug!("Mutex acquire");
          if index.is_none() {
            let mut records = found
              .into_iter()
              .map(|record| {
                let id_tx = record.id();
                let record = records.entry(id_tx).or_insert_with(|| {
                  hashes.insert(record.hash().to_owned(), id_tx);
                  Self::fill_indices(&mut indices, &record, skip_index);
                  Arc::new(Mutex::new(record))
                });
                (id_tx, record.clone())
              })
              .collect::<Vec<_>>();
            records.sort_unstable_by_key(|&(id_tx, _)| id_tx);
            let mut ids =
              records.iter().map(|&(id_tx, _)| id_tx).collect::<Vec<_>>();
            ids.dedup();
            *index = Some(ids);
            return Ok((index, records));
          }
        }
        Err(err) => return Err(err),
      }
    }
  }
}
<|endoftext|>


<commit_before>use std;
use std::fs::File;
use std::io;
use std::io::BufReader;
use std::vec::Vec;

pub enum InputSource<'a> {
    FileName(&'a str),
    Stdin,
    #[allow(dead_code)]
    Stream(Box<dyn io::Read>),
}

// MultifileReader - concatenate all our input, file or stdin.
pub struct MultifileReader<'a> {
    ni: Vec<InputSource<'a>>,
    curr_file: Option<Box<dyn io::Read>>,
    any_err: bool,
}

pub trait HasError {
    fn has_error(&self) -> bool;
}

impl<'b> MultifileReader<'b> {
    pub fn new<'a>(fnames: Vec<InputSource<'a>>) -> MultifileReader<'a> {
        let mut mf = MultifileReader {
            ni: fnames,
            curr_file: None, // normally this means done; call next_file()
            any_err: false,
        };
        mf.next_file();
        mf
    }

    fn next_file(&mut self) {
        // loop retries with subsequent files if err - normally 'loops' once
        loop {
            if self.ni.is_empty() {
                self.curr_file = None;
                break;
            }
            match self.ni.remove(0) {
                InputSource::Stdin => {
                    self.curr_file = Some(Box::new(BufReader::new(std::io::stdin())));
                    break;
                }
                InputSource::FileName(fname) => {
                    match File::open(fname) {
                        Ok(f) => {
                            self.curr_file = Some(Box::new(BufReader::new(f)));
                            break;
                        }
                        Err(e) => {
                            // If any file can't be opened,
                            // print an error at the time that the file is needed,
                            // then move on the the next file.
                            // This matches the behavior of the original `od`
                            eprintln!(
                                "{}: '{}': {}",
                                executable!().split("::").next().unwrap(), // remove module
                                fname,
                                e
                            );
                            self.any_err = true
                        }
                    }
                }
                InputSource::Stream(s) => {
                    self.curr_file = Some(s);
                    break;
                }
            }
        }
    }
}

impl<'b> io::Read for MultifileReader<'b> {
    // Fill buf with bytes read from the list of files
    // Returns Ok(<number of bytes read>)
    // Handles io errors itself, thus always returns OK
    // Fills the provided buffer completely, unless it has run out of input.
    // If any call returns short (< buf.len()), all subsequent calls will return Ok<0>
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let mut xfrd = 0;
        // while buffer we are filling is not full.. May go through several files.
        'fillloop: while xfrd < buf.len() {
            match self.curr_file {
                None => break,
                Some(ref mut curr_file) => {
                    loop {
                        // stdin may return on 'return' (enter), even though the buffer isn't full.
                        xfrd += match curr_file.read(&mut buf[xfrd..]) {
                            Ok(0) => break,
                            Ok(n) => n,
                            Err(e) => {
                                eprintln!(
                                    "{}: I/O: {}",
                                    executable!().split("::").next().unwrap(), // remove module
                                    e
                                );
                                self.any_err = true;
                                break;
                            }
                        };
                        if xfrd == buf.len() {
                            // transferred all that was asked for.
                            break 'fillloop;
                        }
                    }
                }
            }
            self.next_file();
        }
        Ok(xfrd)
    }
}

impl<'b> HasError for MultifileReader<'b> {
    fn has_error(&self) -> bool {
        self.any_err
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use mockstream::*;
    use std::io::{Cursor, ErrorKind, Read};

    #[test]
    fn test_multi_file_reader_one_read() {
        let mut inputs = Vec::new();
        inputs.push(InputSource::Stream(Box::new(Cursor::new(&b"abcd"[..]))));
        inputs.push(InputSource::Stream(Box::new(Cursor::new(&b"ABCD"[..]))));
        let mut v = [0; 10];

        let mut sut = MultifileReader::new(inputs);

        assert_eq!(sut.read(v.as_mut()).unwrap(), 8);
        assert_eq!(v, [0x61, 0x62, 0x63, 0x64, 0x41, 0x42, 0x43, 0x44, 0, 0]);
        assert_eq!(sut.read(v.as_mut()).unwrap(), 0);
    }

    #[test]
    fn test_multi_file_reader_two_reads() {
        let mut inputs = Vec::new();
        inputs.push(InputSource::Stream(Box::new(Cursor::new(&b"abcd"[..]))));
        inputs.push(InputSource::Stream(Box::new(Cursor::new(&b"ABCD"[..]))));
        let mut v = [0; 5];

        let mut sut = MultifileReader::new(inputs);

        assert_eq!(sut.read(v.as_mut()).unwrap(), 5);
        assert_eq!(v, [0x61, 0x62, 0x63, 0x64, 0x41]);
        assert_eq!(sut.read(v.as_mut()).unwrap(), 3);
        assert_eq!(v, [0x42, 0x43, 0x44, 0x64, 0x41]); // last two bytes are not overwritten
    }

    #[test]
    fn test_multi_file_reader_read_error() {
        let c = Cursor::new(&b"1234"[..])
            .chain(FailingMockStream::new(ErrorKind::Other, "Failing", 1))
            .chain(Cursor::new(&b"5678"[..]));
        let mut inputs = Vec::new();
        inputs.push(InputSource::Stream(Box::new(c)));
        inputs.push(InputSource::Stream(Box::new(Cursor::new(&b"ABCD"[..]))));
        let mut v = [0; 5];

        let mut sut = MultifileReader::new(inputs);

        assert_eq!(sut.read(v.as_mut()).unwrap(), 5);
        assert_eq!(v, [49, 50, 51, 52, 65]);
        assert_eq!(sut.read(v.as_mut()).unwrap(), 3);
        assert_eq!(v, [66, 67, 68, 52, 65]); // last two bytes are not overwritten

        // note: no retry on i/o error, so 5678 is missing
    }

    #[test]
    fn test_multi_file_reader_read_error_at_start() {
        let mut inputs = Vec::new();
        inputs.push(InputSource::Stream(Box::new(FailingMockStream::new(
            ErrorKind::Other,
            "Failing",
            1,
        ))));
        inputs.push(InputSource::Stream(Box::new(Cursor::new(&b"abcd"[..]))));
        inputs.push(InputSource::Stream(Box::new(FailingMockStream::new(
            ErrorKind::Other,
            "Failing",
            1,
        ))));
        inputs.push(InputSource::Stream(Box::new(Cursor::new(&b"ABCD"[..]))));
        inputs.push(InputSource::Stream(Box::new(FailingMockStream::new(
            ErrorKind::Other,
            "Failing",
            1,
        ))));
        let mut v = [0; 5];

        let mut sut = MultifileReader::new(inputs);

        assert_eq!(sut.read(v.as_mut()).unwrap(), 5);
        assert_eq!(v, [0x61, 0x62, 0x63, 0x64, 0x41]);
        assert_eq!(sut.read(v.as_mut()).unwrap(), 3);
        assert_eq!(v, [0x42, 0x43, 0x44, 0x64, 0x41]); // last two bytes are not overwritten
    }
}
<commit_msg>fix `cargo clippy` complaint (single_component_path_imports)<commit_after>use std::fs::File;
use std::io;
use std::io::BufReader;
use std::vec::Vec;

pub enum InputSource<'a> {
    FileName(&'a str),
    Stdin,
    #[allow(dead_code)]
    Stream(Box<dyn io::Read>),
}

// MultifileReader - concatenate all our input, file or stdin.
pub struct MultifileReader<'a> {
    ni: Vec<InputSource<'a>>,
    curr_file: Option<Box<dyn io::Read>>,
    any_err: bool,
}

pub trait HasError {
    fn has_error(&self) -> bool;
}

impl<'b> MultifileReader<'b> {
    pub fn new<'a>(fnames: Vec<InputSource<'a>>) -> MultifileReader<'a> {
        let mut mf = MultifileReader {
            ni: fnames,
            curr_file: None, // normally this means done; call next_file()
            any_err: false,
        };
        mf.next_file();
        mf
    }

    fn next_file(&mut self) {
        // loop retries with subsequent files if err - normally 'loops' once
        loop {
            if self.ni.is_empty() {
                self.curr_file = None;
                break;
            }
            match self.ni.remove(0) {
                InputSource::Stdin => {
                    self.curr_file = Some(Box::new(BufReader::new(std::io::stdin())));
                    break;
                }
                InputSource::FileName(fname) => {
                    match File::open(fname) {
                        Ok(f) => {
                            self.curr_file = Some(Box::new(BufReader::new(f)));
                            break;
                        }
                        Err(e) => {
                            // If any file can't be opened,
                            // print an error at the time that the file is needed,
                            // then move on the the next file.
                            // This matches the behavior of the original `od`
                            eprintln!(
                                "{}: '{}': {}",
                                executable!().split("::").next().unwrap(), // remove module
                                fname,
                                e
                            );
                            self.any_err = true
                        }
                    }
                }
                InputSource::Stream(s) => {
                    self.curr_file = Some(s);
                    break;
                }
            }
        }
    }
}

impl<'b> io::Read for MultifileReader<'b> {
    // Fill buf with bytes read from the list of files
    // Returns Ok(<number of bytes read>)
    // Handles io errors itself, thus always returns OK
    // Fills the provided buffer completely, unless it has run out of input.
    // If any call returns short (< buf.len()), all subsequent calls will return Ok<0>
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let mut xfrd = 0;
        // while buffer we are filling is not full.. May go through several files.
        'fillloop: while xfrd < buf.len() {
            match self.curr_file {
                None => break,
                Some(ref mut curr_file) => {
                    loop {
                        // stdin may return on 'return' (enter), even though the buffer isn't full.
                        xfrd += match curr_file.read(&mut buf[xfrd..]) {
                            Ok(0) => break,
                            Ok(n) => n,
                            Err(e) => {
                                eprintln!(
                                    "{}: I/O: {}",
                                    executable!().split("::").next().unwrap(), // remove module
                                    e
                                );
                                self.any_err = true;
                                break;
                            }
                        };
                        if xfrd == buf.len() {
                            // transferred all that was asked for.
                            break 'fillloop;
                        }
                    }
                }
            }
            self.next_file();
        }
        Ok(xfrd)
    }
}

impl<'b> HasError for MultifileReader<'b> {
    fn has_error(&self) -> bool {
        self.any_err
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use mockstream::*;
    use std::io::{Cursor, ErrorKind, Read};

    #[test]
    fn test_multi_file_reader_one_read() {
        let mut inputs = Vec::new();
        inputs.push(InputSource::Stream(Box::new(Cursor::new(&b"abcd"[..]))));
        inputs.push(InputSource::Stream(Box::new(Cursor::new(&b"ABCD"[..]))));
        let mut v = [0; 10];

        let mut sut = MultifileReader::new(inputs);

        assert_eq!(sut.read(v.as_mut()).unwrap(), 8);
        assert_eq!(v, [0x61, 0x62, 0x63, 0x64, 0x41, 0x42, 0x43, 0x44, 0, 0]);
        assert_eq!(sut.read(v.as_mut()).unwrap(), 0);
    }

    #[test]
    fn test_multi_file_reader_two_reads() {
        let mut inputs = Vec::new();
        inputs.push(InputSource::Stream(Box::new(Cursor::new(&b"abcd"[..]))));
        inputs.push(InputSource::Stream(Box::new(Cursor::new(&b"ABCD"[..]))));
        let mut v = [0; 5];

        let mut sut = MultifileReader::new(inputs);

        assert_eq!(sut.read(v.as_mut()).unwrap(), 5);
        assert_eq!(v, [0x61, 0x62, 0x63, 0x64, 0x41]);
        assert_eq!(sut.read(v.as_mut()).unwrap(), 3);
        assert_eq!(v, [0x42, 0x43, 0x44, 0x64, 0x41]); // last two bytes are not overwritten
    }

    #[test]
    fn test_multi_file_reader_read_error() {
        let c = Cursor::new(&b"1234"[..])
            .chain(FailingMockStream::new(ErrorKind::Other, "Failing", 1))
            .chain(Cursor::new(&b"5678"[..]));
        let mut inputs = Vec::new();
        inputs.push(InputSource::Stream(Box::new(c)));
        inputs.push(InputSource::Stream(Box::new(Cursor::new(&b"ABCD"[..]))));
        let mut v = [0; 5];

        let mut sut = MultifileReader::new(inputs);

        assert_eq!(sut.read(v.as_mut()).unwrap(), 5);
        assert_eq!(v, [49, 50, 51, 52, 65]);
        assert_eq!(sut.read(v.as_mut()).unwrap(), 3);
        assert_eq!(v, [66, 67, 68, 52, 65]); // last two bytes are not overwritten

        // note: no retry on i/o error, so 5678 is missing
    }

    #[test]
    fn test_multi_file_reader_read_error_at_start() {
        let mut inputs = Vec::new();
        inputs.push(InputSource::Stream(Box::new(FailingMockStream::new(
            ErrorKind::Other,
            "Failing",
            1,
        ))));
        inputs.push(InputSource::Stream(Box::new(Cursor::new(&b"abcd"[..]))));
        inputs.push(InputSource::Stream(Box::new(FailingMockStream::new(
            ErrorKind::Other,
            "Failing",
            1,
        ))));
        inputs.push(InputSource::Stream(Box::new(Cursor::new(&b"ABCD"[..]))));
        inputs.push(InputSource::Stream(Box::new(FailingMockStream::new(
            ErrorKind::Other,
            "Failing",
            1,
        ))));
        let mut v = [0; 5];

        let mut sut = MultifileReader::new(inputs);

        assert_eq!(sut.read(v.as_mut()).unwrap(), 5);
        assert_eq!(v, [0x61, 0x62, 0x63, 0x64, 0x41]);
        assert_eq!(sut.read(v.as_mut()).unwrap(), 3);
        assert_eq!(v, [0x42, 0x43, 0x44, 0x64, 0x41]); // last two bytes are not overwritten
    }
}
<|endoftext|>


<commit_before>// TODO: Refactor using a matrix for performance

use redox::*;

mod cmd;

#[derive(Copy, Clone, PartialEq, Eq)]
pub enum Mode {
    Insert,
    Normal,
}

pub struct Editor {
    url: String,
    file: Option<File>,
    string: String,
    offset: usize,
    scroll_x: isize,
    scroll_y: isize,
}

impl Editor {
    #[inline(never)]
    pub fn new() -> Self {
        Editor {
            url: String::new(),
            file: Option::None,
            string: String::new(),
            offset: 0,
            scroll_x: 0,
            scroll_y: 0,
        }
    }

    fn backspace(&mut self, window: &mut Window) {
        if self.offset > 0 {
            window.set_title(&format!("{}{}{}","Editor (", &self.url, ") Changed"));
            self.string = self.string[0 .. self.offset - 1].to_string() +
                &self.string[self.offset .. self.string.len()];
            self.offset -= 1;
        }
    }

    fn delete(&mut self, window: &mut Window) {
        if self.offset < self.string.len() {
            window.set_title(&format!("{}{}{}","Editor (", &self.url, ") Changed"));
            self.string = self.string[0 .. self.offset].to_string() +
                &self.string[self.offset + 1 .. self.string.len()];
        }
    }

    // TODO: Add methods for multiple movements
    fn up(&mut self) {
        if self.cur() == '\n' || self.cur() == '\0' {
            self.left();
            while self.cur() != '\n' &&
                  self.cur() != '\0' &&
                  self.offset >= 1 {
                self.left();
            }
        } else {
            let x = self.get_x(); //- if self.cur() == '\n' { 1 } else { 0 };

            while self.cur() != '\n' {
                self.left();
            }
            self.right();
            let mut new_offset = 0;

            for i in 2..self.offset {
                match self.string.as_bytes()[self.offset - i] {
                    0 => break,
                    10 => {
                        new_offset = self.offset - i + 1;
                        break;
                    }
                    _ => (),
                }
            }
            self.offset = new_offset;
            for _ in 1..x {
                if self.cur() != '\n' {
                    self.right();
                } else {
                    break;
                }
            }
        }
    }

    fn left(&mut self) {
        if self.offset > 0 {
            self.offset -= 1;
        }
    }

    fn right(&mut self) {
        if self.offset < self.string.len() {
            self.offset += 1;
        }
    }

    fn down(&mut self) {
        let x = self.get_x(); //- if self.cur() == '\n' { 1 } else { 0 };
        let original_c = self.cur();

        while self.offset >= self.string.len() &&
              self.cur() != '\n' &&
              self.cur() != '\0' {
            self.right();
        }
        self.right();

        if original_c == '\n' {
            while self.cur() != '\n' &&
                  self.cur() != '\0' &&
                  self.offset < self.string.len() {
                self.right();
            }
        } else {
            for _ in 1..x {
                if self.cur() != '\n' {
                    self.right();
                } else {
                    break;
                }
            }
        }
    }

    fn cur(&self) -> char {
        self.string.chars().nth(self.offset).unwrap_or('\0')
    }

    fn insert(&mut self, c: char, window: &mut Window) {
        window.set_title(&format!("{}{}{}","self (", &self.url, ") Changed"));
        self.string = self.string[0 .. self.offset].to_string() +
            &c.to_string() +
            &self.string[self.offset .. self.string.len()];
        self.offset += 1;
    }

    fn reload(&mut self, window: &mut Window) {
        window.set_title(&("Editor (".to_string() + &self.url + ")"));
        self.offset = 0;
        self.scroll_x = 0;
        self.scroll_y = 0;

        match self.file {
            Option::Some(ref mut file) => {
                file.seek(Seek::Start(0));
                let mut vec: Vec<u8> = Vec::new();
                file.read_to_end(&mut vec);
                self.string = unsafe { String::from_utf8_unchecked(vec) };
            },
            Option::None => self.string = String::new(),
        }
    }

    fn save(&mut self, window: &mut Window) {
        match self.file {
            Option::Some(ref mut file) => {
                window.set_title(&("Editor (".to_string() + &self.url + ") Saved"));
                file.seek(Seek::Start(0));
                file.write(&self.string.as_bytes());
                file.sync();
            }
            Option::None => {
                //TODO: Ask for file to save to
                window.set_title(&("Editor (".to_string() + &self.url + ") No Open File"));
            }
        }
    }

    fn get_x(&self) -> usize {
        let mut x = 0;
        for (n, c) in self.string.chars().enumerate() {
            if c == '\n' {
                x = 0;
            } else {
                x += 1;
            }
            if n >= self.offset {
                break;
            }
        }
        x
    }

    fn draw_content(&mut self, window: &mut Window) {
        let mut redraw = false;

        {
            window.set([255, 255, 255, 255]);

            let scroll_x = self.scroll_x;
            let scroll_y = self.scroll_y;

            let mut offset = 0;

            let mut col = -scroll_x;
            let cols = window.width() as isize / 8;

            let mut row = -scroll_y;
            let rows = window.height() as isize / 16;

            for c in self.string.chars() {
                if offset == self.offset {
                    if col >= 0 && col < cols && row >= 0 && row < rows {
                        window.char(8 * col, 16 * row, '_', [128, 128, 128, 255]);
                    } else {
                        if col < 0 { //Too far to the left
                            self.scroll_x += col;
                        } else if col >= cols { //Too far to the right
                            self.scroll_x += cols - col + 1;
                        }
                        if row < 0 { //Too far up
                            self.scroll_y += row;
                        } else if row >= rows { //Too far down
                            self.scroll_y += rows - row + 1;
                        }

                        redraw = true;
                    }
                }

                if c == '\n' {
                    col = -scroll_x;
                    row += 1;
                } else if c == '\t' {
                    col += 8 - col % 8;
                } else {
                    if col >= 0 && col < cols && row >= 0 && row < rows {
                        window.char(8 * col, 16 * row, c, [0, 0, 0, 255]);
                    }
                    col += 1;
                }

                offset += 1;
            }

            if offset == self.offset {
                if col >= 0 && col < cols && row >= 0 && row < rows {
                    window.char(8 * col, 16 * row, '_', [128, 128, 128, 255]);
                } else {
                    if col < 0 { //Too far to the left
                        self.scroll_x += col;
                    } else if col >= cols { //Too far to the right
                        self.scroll_x += cols - col + 1;
                    }
                    if row < 0 { //Too far up
                        self.scroll_y += row;
                    } else if row >= rows { //Too far down
                        self.scroll_y += rows - row + 1;
                    }

                    redraw = true;
                }
            }

            window.sync();
        }

        if redraw {
            self.draw_content(window);
        }
    }

    fn main(&mut self, url: &str) {
        let mut window = Window::new((rand() % 400 + 50) as isize,
        (rand() % 300 + 50) as isize,
        576,
        400,
        &("Editor (".to_string() + url + ")"));

        self.url = url.to_string();
        self.file = Option::Some(File::open(&self.url));

        self.reload(&mut window);
        self.draw_content(&mut window);

        let mut mode = Mode::Normal;

        let mut last_change = String::new();
        let mut multiplier: Option<u32> = None;
        let mut swap = 0;
        let mut period = String::new();
        let mut is_recording = false;

        while let Option::Some(event) = window.poll() {
            match event.to_option() {
                EventOption::Key(key_event) => {
                    if key_event.pressed {
                        cmd::exec(self, &mut mode, &mut multiplier, &mut last_change, key_event, &mut window, &mut swap, &mut period, &mut is_recording);

                        self.draw_content(&mut window);
                    }
                }
                _ => (),
            }
        }
    }
}

pub fn main() {
    match args().get(1) {
        Option::Some(arg) => Editor::new().main(&arg),
        Option::None => Editor::new().main("none://"),
    }
}
<commit_msg>Fix bugs after refactoring<commit_after>// TODO: Refactor using a matrix for performance

use redox::*;

mod cmd;

#[derive(Copy, Clone, PartialEq, Eq)]
pub enum Mode {
    Insert,
    Normal,
}

pub struct Editor {
    url: String,
    file: Option<File>,
    string: String,
    offset: usize,
    scroll_x: isize,
    scroll_y: isize,
}

impl Editor {
    #[inline(never)]
    pub fn new() -> Self {
        Editor {
            url: String::new(),
            file: Option::None,
            string: String::new(),
            offset: 0,
            scroll_x: 0,
            scroll_y: 0,
        }
    }

    fn backspace(&mut self, window: &mut Window) {
        if self.offset > 0 {
            window.set_title(&format!("{}{}{}","Editor (", &self.url, ") Changed"));
            self.string = self.string[0 .. self.offset - 1].to_string() +
                &self.string[self.offset .. self.string.len()];
            self.offset -= 1;
        }
    }

    fn delete(&mut self, window: &mut Window) {
        if self.offset < self.string.len() {
            window.set_title(&format!("{}{}{}","Editor (", &self.url, ") Changed"));
            self.string = self.string[0 .. self.offset].to_string() +
                &self.string[self.offset + 1 .. self.string.len()];
        }
    }

    // TODO: Add methods for multiple movements
    fn up(&mut self) {
        if self.cur() == '\n' || self.cur() == '\0' {
            self.left();
            while self.cur() != '\n' &&
                  self.cur() != '\0' &&
                  self.offset >= 1 {
                self.left();
            }
        } else {
            let x = self.get_x(); //- if self.cur() == '\n' { 1 } else { 0 };

            while self.cur() != '\n' &&
                  self.offset >= 1 {
                self.left();
            }
            self.right();
            let mut new_offset = 0;

            for i in 2..self.offset {
                match self.string.as_bytes()[self.offset - i] {
                    0 => break,
                    10 => {
                        new_offset = self.offset - i + 1;
                        break;
                    }
                    _ => (),
                }
            }
            self.offset = new_offset;
            for _ in 1..x {
                if self.cur() != '\n' {
                    self.right();
                } else {
                    break;
                }
            }
        }
    }

    fn left(&mut self) {
        if self.offset > 0 {
            self.offset -= 1;
        }
    }

    fn right(&mut self) {
        if self.offset < self.string.len() {
            self.offset += 1;
        }
    }

    fn down(&mut self) {
        let x = self.get_x(); //- if self.cur() == '\n' { 1 } else { 0 };
        let original_c = self.cur();

        while self.offset < self.string.len() &&
              self.cur() != '\n' &&
              self.cur() != '\0' {
            self.right();
        }
        self.right();

        if original_c == '\n' {
            while self.cur() != '\n' &&
                  self.cur() != '\0' &&
                  self.offset < self.string.len() {
                self.right();
            }
        } else {
            for _ in 1..x {
                if self.cur() != '\n' {
                    self.right();
                } else {
                    break;
                }
            }
        }
    }

    fn cur(&self) -> char {
        self.string.chars().nth(self.offset).unwrap_or('\0')
    }

    fn insert(&mut self, c: char, window: &mut Window) {
        window.set_title(&format!("{}{}{}","self (", &self.url, ") Changed"));
        self.string = self.string[0 .. self.offset].to_string() +
            &c.to_string() +
            &self.string[self.offset .. self.string.len()];
        self.offset += 1;
    }

    fn reload(&mut self, window: &mut Window) {
        window.set_title(&("Editor (".to_string() + &self.url + ")"));
        self.offset = 0;
        self.scroll_x = 0;
        self.scroll_y = 0;

        match self.file {
            Option::Some(ref mut file) => {
                file.seek(Seek::Start(0));
                let mut vec: Vec<u8> = Vec::new();
                file.read_to_end(&mut vec);
                self.string = unsafe { String::from_utf8_unchecked(vec) };
            },
            Option::None => self.string = String::new(),
        }
    }

    fn save(&mut self, window: &mut Window) {
        match self.file {
            Option::Some(ref mut file) => {
                window.set_title(&("Editor (".to_string() + &self.url + ") Saved"));
                file.seek(Seek::Start(0));
                file.write(&self.string.as_bytes());
                file.sync();
            }
            Option::None => {
                //TODO: Ask for file to save to
                window.set_title(&("Editor (".to_string() + &self.url + ") No Open File"));
            }
        }
    }

    fn get_x(&self) -> usize {
        let mut x = 0;
        for (n, c) in self.string.chars().enumerate() {
            if c == '\n' {
                x = 0;
            } else {
                x += 1;
            }
            if n >= self.offset {
                break;
            }
        }
        x
    }

    fn draw_content(&mut self, window: &mut Window) {
        let mut redraw = false;

        {
            window.set([255, 255, 255, 255]);

            let scroll_x = self.scroll_x;
            let scroll_y = self.scroll_y;

            let mut offset = 0;

            let mut col = -scroll_x;
            let cols = window.width() as isize / 8;

            let mut row = -scroll_y;
            let rows = window.height() as isize / 16;

            for c in self.string.chars() {
                if offset == self.offset {
                    if col >= 0 && col < cols && row >= 0 && row < rows {
                        window.char(8 * col, 16 * row, '_', [128, 128, 128, 255]);
                    } else {
                        if col < 0 { //Too far to the left
                            self.scroll_x += col;
                        } else if col >= cols { //Too far to the right
                            self.scroll_x += cols - col + 1;
                        }
                        if row < 0 { //Too far up
                            self.scroll_y += row;
                        } else if row >= rows { //Too far down
                            self.scroll_y += rows - row + 1;
                        }

                        redraw = true;
                    }
                }

                if c == '\n' {
                    col = -scroll_x;
                    row += 1;
                } else if c == '\t' {
                    col += 8 - col % 8;
                } else {
                    if col >= 0 && col < cols && row >= 0 && row < rows {
                        window.char(8 * col, 16 * row, c, [0, 0, 0, 255]);
                    }
                    col += 1;
                }

                offset += 1;
            }

            if offset == self.offset {
                if col >= 0 && col < cols && row >= 0 && row < rows {
                    window.char(8 * col, 16 * row, '_', [128, 128, 128, 255]);
                } else {
                    if col < 0 { //Too far to the left
                        self.scroll_x += col;
                    } else if col >= cols { //Too far to the right
                        self.scroll_x += cols - col + 1;
                    }
                    if row < 0 { //Too far up
                        self.scroll_y += row;
                    } else if row >= rows { //Too far down
                        self.scroll_y += rows - row + 1;
                    }

                    redraw = true;
                }
            }

            window.sync();
        }

        if redraw {
            self.draw_content(window);
        }
    }

    fn main(&mut self, url: &str) {
        let mut window = Window::new((rand() % 400 + 50) as isize,
        (rand() % 300 + 50) as isize,
        576,
        400,
        &("Editor (".to_string() + url + ")"));

        self.url = url.to_string();
        self.file = Option::Some(File::open(&self.url));

        self.reload(&mut window);
        self.draw_content(&mut window);

        let mut mode = Mode::Normal;

        let mut last_change = String::new();
        let mut multiplier: Option<u32> = None;
        let mut swap = 0;
        let mut period = String::new();
        let mut is_recording = false;

        while let Option::Some(event) = window.poll() {
            match event.to_option() {
                EventOption::Key(key_event) => {
                    if key_event.pressed {
                        cmd::exec(self, &mut mode, &mut multiplier, &mut last_change, key_event, &mut window, &mut swap, &mut period, &mut is_recording);

                        self.draw_content(&mut window);
                    }
                }
                _ => (),
            }
        }
    }
}

pub fn main() {
    match args().get(1) {
        Option::Some(arg) => Editor::new().main(&arg),
        Option::None => Editor::new().main("none://"),
    }
}
<|endoftext|>


<commit_before>use std::f32;
use std::f64;

use protobuf::Message;

use protobuf_test_common::*;

use super::test_fmt_json_pb::*;

#[test]
fn empty() {
    test_json_print_parse_message("{}", &TestTypes::new());
}

#[test]
fn test_bool() {
    let mut m = TestTypes::new();
    m.set_bool_singular(true);
    test_json_print_parse_message("{bool_singular: true}", &m);

    let mut m = TestTypes::new();
    m.set_bool_repeated(vec![true, false, false]);
    test_json_print_parse_message("{bool_repeated: [true, false, false]}", &m);
}

#[test]
fn test_float() {
    let mut m = TestTypes::new();
    m.set_float_singular(10.0);
    test_json_print_parse_message("{float_singular: 10.0}", &m);

    let mut m = TestTypes::new();
    m.float_repeated.push(11.0);
    m.float_repeated.push(-12.5);
    m.float_repeated.push(f32::NAN);
    m.float_repeated.push(f32::NEG_INFINITY);
    test_json_print_parse_message("{float_repeated: [11.0, -12.5, \"NaN\", \"-Infinity\"]}", &m);
}

#[test]
fn test_double() {
    let mut m = TestTypes::new();
    m.set_double_singular(12.0);
    test_json_print_parse_message("{double_singular: 12.0}", &m);

    let mut m = TestTypes::new();
    m.double_repeated.push(13.0);
    m.double_repeated.push(f64::INFINITY);
    test_json_print_parse_message("{double_repeated: [13.0, \"Infinity\"]}", &m);
}

#[test]
fn test_int32() {
    let mut m = TestTypes::new();
    m.set_int32_singular(1234);
    test_json_print_parse_message("{int32_singular: 1234}", &m);

    let mut m = TestTypes::new();
    m.int32_repeated.push(10);
    m.int32_repeated.push(-20);
    test_json_print_parse_message("{int32_repeated: [10, -20]}", &m);
}

#[test]
fn test_int64() {
    let mut m = TestTypes::new();
    m.set_int64_singular(1234567890123456789);
    test_json_print_parse_message("{int64_singular: \"1234567890123456789\"}", &m);

    let mut m = TestTypes::new();
    m.int64_repeated.push(2345678901234567890);
    m.int64_repeated.push(-2345678901234567890);
    test_json_print_parse_message(
        "{int64_repeated: [\"2345678901234567890\", \"-2345678901234567890\"]}", &m);
}

#[test]
fn test_sint32() {
    let mut m = TestTypes::new();
    m.set_sint32_singular(1234);
    test_json_print_parse_message("{sint32_singular: 1234}", &m);

    let mut m = TestTypes::new();
    m.sint32_repeated.push(10);
    m.sint32_repeated.push(-20);
    test_json_print_parse_message("{sint32_repeated: [10, -20]}", &m);
}

#[test]
fn test_sint64() {
    let mut m = TestTypes::new();
    m.set_sint64_singular(1234567890123456789);
    test_json_print_parse_message("{sint64_singular: \"1234567890123456789\"}", &m);

    let mut m = TestTypes::new();
    m.sint64_repeated.push(2345678901234567890);
    m.sint64_repeated.push(-2345678901234567890);
    test_json_print_parse_message(
        "{sint64_repeated: [\"2345678901234567890\", \"-2345678901234567890\"]}", &m);
}

#[test]
fn test_sfixed32() {
    let mut m = TestTypes::new();
    m.set_sfixed32_singular(1234);
    test_json_print_parse_message("{sfixed32_singular: 1234}", &m);

    let mut m = TestTypes::new();
    m.sfixed32_repeated.push(10);
    m.sfixed32_repeated.push(-20);
    test_json_print_parse_message("{sfixed32_repeated: [10, -20]}", &m);
}

#[test]
fn test_sfixed64() {
    let mut m = TestTypes::new();
    m.set_sfixed64_singular(1234567890123456789);
    test_json_print_parse_message("{sfixed64_singular: \"1234567890123456789\"}", &m);

    let mut m = TestTypes::new();
    m.sfixed64_repeated.push(2345678901234567890);
    m.sfixed64_repeated.push(-2345678901234567890);
    test_json_print_parse_message(
        "{sfixed64_repeated: [\"2345678901234567890\", \"-2345678901234567890\"]}", &m);
}

#[test]
fn test_uint32() {
    let mut m = TestTypes::new();
    m.set_uint32_singular(1234);
    test_json_print_parse_message("{uint32_singular: 1234}", &m);

    let mut m = TestTypes::new();
    m.uint32_repeated.push(10);
    m.uint32_repeated.push(20300);
    test_json_print_parse_message("{uint32_repeated: [10, 20300]}", &m);
}

#[test]
fn test_uint64() {
    let mut m = TestTypes::new();
    m.set_uint64_singular(1234567890123456789);
    test_json_print_parse_message(
        "{uint64_singular: \"1234567890123456789\"}", &m);

    let mut m = TestTypes::new();
    m.uint64_repeated.push(2345678901234567890);
    m.uint64_repeated.push(1345678901234567890);
    test_json_print_parse_message(
        "{uint64_repeated: [\"2345678901234567890\", \"1345678901234567890\"]}", &m);
}

#[test]
fn test_fixed32() {
    let mut m = TestTypes::new();
    m.set_fixed32_singular(1234);
    test_json_print_parse_message("{fixed32_singular: 1234}", &m);

    let mut m = TestTypes::new();
    m.fixed32_repeated.push(10);
    m.fixed32_repeated.push(20300);
    test_json_print_parse_message("{fixed32_repeated: [10, 20300]}", &m);
}

#[test]
fn test_fixed64() {
    let mut m = TestTypes::new();
    m.set_fixed64_singular(1234567890123456789);
    test_json_print_parse_message(
        "{fixed64_singular: \"1234567890123456789\"}", &m);

    let mut m = TestTypes::new();
    m.fixed64_repeated.push(2345678901234567890);
    m.fixed64_repeated.push(1345678901234567890);
    test_json_print_parse_message(
        "{fixed64_repeated: [\"2345678901234567890\", \"1345678901234567890\"]}", &m);
}

#[test]
fn test_string() {
    let mut m = TestTypes::new();
    m.set_string_singular("ab".to_owned());
    test_json_print_parse_message("{string_singular: \"ab\"}", &m);

    let mut m = TestTypes::new();
    m.set_string_repeated(vec!["".to_owned(), "\0".to_owned(), "A\nB".to_owned()].into());
    test_json_print_parse_message("{string_repeated: [\"\", \"\\u0000\", \"A\\nB\"]}", &m);
}

#[test]
fn test_bytes() {
    let mut m = TestTypes::new();
    m.set_bytes_singular(b"ab".to_vec());
    test_json_print_parse_message("{bytes_singular: \"YWI=\"}", &m);

    let mut m = TestTypes::new();
    m.set_bytes_repeated(vec![b"".to_vec(), b"\0".to_vec(), b"A\nB".to_vec()].into());
    test_json_print_parse_message("{bytes_repeated: [\"\", \"AA==\", \"QQpC\"]}", &m);
}

#[test]
fn test_enum() {
    let mut m = TestTypes::new();
    m.set_test_enum_singular(TestEnum::DARK);
    test_json_print_parse_message("{test_enum_singular: \"DARK\"}", &m);
    test_json_parse_message("{test_enum_singular: 10}", &m);

    let mut m = TestTypes::new();
    m.set_test_enum_repeated(vec![TestEnum::DARK, TestEnum::LIGHT]);
    test_json_print_parse_message("{test_enum_repeated: [\"DARK\", \"LIGHT\"]}", &m);
    test_json_parse_message("{test_enum_repeated: [\"DARK\", 20]}", &m);
}

#[test]
fn test_reflect() {
    for m in special_messages(TestTypes::descriptor_static()) {
        test_json_message(&*m);
    }
}
<commit_msg>More JSON tests<commit_after>use std::f32;
use std::f64;

use protobuf::Message;

use protobuf_test_common::*;

use super::test_fmt_json_pb::*;

#[test]
fn empty() {
    test_json_print_parse_message("{}", &TestTypes::new());
}

#[test]
fn test_bool() {
    let mut m = TestTypes::new();
    m.set_bool_singular(true);
    test_json_print_parse_message("{bool_singular: true}", &m);

    let mut m = TestTypes::new();
    m.set_bool_repeated(vec![true, false, false]);
    test_json_print_parse_message("{bool_repeated: [true, false, false]}", &m);
}

#[test]
fn test_float() {
    let mut m = TestTypes::new();
    m.set_float_singular(10.0);
    test_json_print_parse_message("{float_singular: 10.0}", &m);

    let mut m = TestTypes::new();
    m.float_repeated.push(11.0);
    m.float_repeated.push(-12.5);
    m.float_repeated.push(f32::NAN);
    m.float_repeated.push(f32::NEG_INFINITY);
    test_json_print_parse_message("{float_repeated: [11.0, -12.5, \"NaN\", \"-Infinity\"]}", &m);
}

#[test]
fn test_double() {
    let mut m = TestTypes::new();
    m.set_double_singular(12.0);
    test_json_print_parse_message("{double_singular: 12.0}", &m);
    test_json_parse_message("{double_singular: \"12.0\"}", &m);

    let mut m = TestTypes::new();
    m.double_repeated.push(13.0);
    m.double_repeated.push(f64::INFINITY);
    test_json_print_parse_message("{double_repeated: [13.0, \"Infinity\"]}", &m);
}

#[test]
fn test_int32() {
    let mut m = TestTypes::new();
    m.set_int32_singular(1234);
    test_json_print_parse_message("{int32_singular: 1234}", &m);

    let mut m = TestTypes::new();
    m.int32_repeated.push(10);
    m.int32_repeated.push(-20);
    test_json_print_parse_message("{int32_repeated: [10, -20]}", &m);
}

#[test]
fn test_int64() {
    let mut m = TestTypes::new();
    m.set_int64_singular(1234567890123456789);
    test_json_print_parse_message("{int64_singular: \"1234567890123456789\"}", &m);

    let mut m = TestTypes::new();
    m.int64_repeated.push(2345678901234567890);
    m.int64_repeated.push(-2345678901234567890);
    test_json_print_parse_message(
        "{int64_repeated: [\"2345678901234567890\", \"-2345678901234567890\"]}", &m);
}

#[test]
fn test_sint32() {
    let mut m = TestTypes::new();
    m.set_sint32_singular(1234);
    test_json_print_parse_message("{sint32_singular: 1234}", &m);

    let mut m = TestTypes::new();
    m.sint32_repeated.push(10);
    m.sint32_repeated.push(-20);
    test_json_print_parse_message("{sint32_repeated: [10, -20]}", &m);
}

#[test]
fn test_sint64() {
    let mut m = TestTypes::new();
    m.set_sint64_singular(1234567890123456789);
    test_json_print_parse_message("{sint64_singular: \"1234567890123456789\"}", &m);

    let mut m = TestTypes::new();
    m.sint64_repeated.push(2345678901234567890);
    m.sint64_repeated.push(-2345678901234567890);
    test_json_print_parse_message(
        "{sint64_repeated: [\"2345678901234567890\", \"-2345678901234567890\"]}", &m);
}

#[test]
fn test_sfixed32() {
    let mut m = TestTypes::new();
    m.set_sfixed32_singular(1234);
    test_json_print_parse_message("{sfixed32_singular: 1234}", &m);

    let mut m = TestTypes::new();
    m.sfixed32_repeated.push(10);
    m.sfixed32_repeated.push(-20);
    test_json_print_parse_message("{sfixed32_repeated: [10, -20]}", &m);
}

#[test]
fn test_sfixed64() {
    let mut m = TestTypes::new();
    m.set_sfixed64_singular(1234567890123456789);
    test_json_print_parse_message("{sfixed64_singular: \"1234567890123456789\"}", &m);

    let mut m = TestTypes::new();
    m.sfixed64_repeated.push(2345678901234567890);
    m.sfixed64_repeated.push(-2345678901234567890);
    test_json_print_parse_message(
        "{sfixed64_repeated: [\"2345678901234567890\", \"-2345678901234567890\"]}", &m);
}

#[test]
fn test_uint32() {
    let mut m = TestTypes::new();
    m.set_uint32_singular(1234);
    test_json_print_parse_message("{uint32_singular: 1234}", &m);

    let mut m = TestTypes::new();
    m.uint32_repeated.push(10);
    m.uint32_repeated.push(20300);
    test_json_print_parse_message("{uint32_repeated: [10, 20300]}", &m);
}

#[test]
fn test_uint64() {
    let mut m = TestTypes::new();
    m.set_uint64_singular(1234567890123456789);
    test_json_print_parse_message(
        "{uint64_singular: \"1234567890123456789\"}", &m);

    let mut m = TestTypes::new();
    m.uint64_repeated.push(2345678901234567890);
    m.uint64_repeated.push(1345678901234567890);
    test_json_print_parse_message(
        "{uint64_repeated: [\"2345678901234567890\", \"1345678901234567890\"]}", &m);
}

#[test]
fn test_fixed32() {
    let mut m = TestTypes::new();
    m.set_fixed32_singular(1234);
    test_json_print_parse_message("{fixed32_singular: 1234}", &m);

    let mut m = TestTypes::new();
    m.fixed32_repeated.push(10);
    m.fixed32_repeated.push(20300);
    test_json_print_parse_message("{fixed32_repeated: [10, 20300]}", &m);
}

#[test]
fn test_fixed64() {
    let mut m = TestTypes::new();
    m.set_fixed64_singular(1234567890123456789);
    test_json_print_parse_message(
        "{fixed64_singular: \"1234567890123456789\"}", &m);
    test_json_parse_message(
        "{fixed64_singular: 1234567890123456789}", &m);

    let mut m = TestTypes::new();
    m.fixed64_repeated.push(2345678901234567890);
    m.fixed64_repeated.push(1345678901234567890);
    test_json_print_parse_message(
        "{fixed64_repeated: [\"2345678901234567890\", \"1345678901234567890\"]}", &m);
    test_json_parse_message(
        "{fixed64_repeated: [\"2345678901234567890\", 1345678901234567890]}", &m);
}

#[test]
fn test_string() {
    let mut m = TestTypes::new();
    m.set_string_singular("ab".to_owned());
    test_json_print_parse_message("{string_singular: \"ab\"}", &m);

    let mut m = TestTypes::new();
    m.set_string_repeated(vec!["".to_owned(), "\0".to_owned(), "A\nB".to_owned()].into());
    test_json_print_parse_message("{string_repeated: [\"\", \"\\u0000\", \"A\\nB\"]}", &m);
}

#[test]
fn test_bytes() {
    let mut m = TestTypes::new();
    m.set_bytes_singular(b"ab".to_vec());
    test_json_print_parse_message("{bytes_singular: \"YWI=\"}", &m);

    let mut m = TestTypes::new();
    m.set_bytes_repeated(vec![b"".to_vec(), b"\0".to_vec(), b"A\nB".to_vec()].into());
    test_json_print_parse_message("{bytes_repeated: [\"\", \"AA==\", \"QQpC\"]}", &m);
}

#[test]
fn test_enum() {
    let mut m = TestTypes::new();
    m.set_test_enum_singular(TestEnum::DARK);
    test_json_print_parse_message("{test_enum_singular: \"DARK\"}", &m);
    test_json_parse_message("{test_enum_singular: 10}", &m);

    let mut m = TestTypes::new();
    m.set_test_enum_repeated(vec![TestEnum::DARK, TestEnum::LIGHT]);
    test_json_print_parse_message("{test_enum_repeated: [\"DARK\", \"LIGHT\"]}", &m);
    test_json_parse_message("{test_enum_repeated: [\"DARK\", 20]}", &m);
}

#[test]
fn test_reflect() {
    for m in special_messages(TestTypes::descriptor_static()) {
        test_json_message(&*m);
    }
}
<|endoftext|>