<commit_before>use super::{ParallelIterator, ExactParallelIterator};

use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use std::hash::{BuildHasher, Hash};
use std::collections::LinkedList;
use std::collections::{BinaryHeap, VecDeque};

pub trait FromParallelIterator<PAR_ITER> {
    fn from_par_iter(par_iter: PAR_ITER) -> Self;
}

fn combine<PAR_ITER, START, COLL>(par_iter: PAR_ITER, make_start: START) -> COLL
    where PAR_ITER: ParallelIterator,
          START: FnOnce(&LinkedList<Vec<PAR_ITER::Item>>) -> COLL,
          COLL: Extend<PAR_ITER::Item>
{
    let list = par_iter
        .fold(Vec::new, |mut vec, elem| { vec.push(elem); vec })
        .collect();

    let start = make_start(&list);
    list.into_iter()
        .fold(start, |mut coll, vec| { coll.extend(vec); coll })
}

fn combined_len<T>(list: &LinkedList<Vec<T>>) -> usize {
    list.iter().map(Vec::len).sum()
}

/// Collect items from a parallel iterator into a freshly allocated
/// vector. This is very efficient, but requires precise knowledge of
/// the number of items being iterated.
impl<PAR_ITER, T> FromParallelIterator<PAR_ITER> for Vec<T>
    where PAR_ITER: ExactParallelIterator<Item=T>,
          T: Send,
{
    fn from_par_iter(par_iter: PAR_ITER) -> Self {
        let mut vec = vec![];
        par_iter.collect_into(&mut vec);
        vec
    }
}

/// Collect items from a parallel iterator into a vecdeque.
impl<PAR_ITER, T> FromParallelIterator<PAR_ITER> for VecDeque<T>
    where Vec<T>: FromParallelIterator<PAR_ITER>,
          T: Send,
{
    fn from_par_iter(par_iter: PAR_ITER) -> Self {
        Vec::from_par_iter(par_iter).into()
    }
}

/// Collect items from a parallel iterator into a binaryheap.
/// The heap-ordering is calculated serially after all items are collected.
impl<PAR_ITER, T> FromParallelIterator<PAR_ITER> for BinaryHeap<T>
    where Vec<T>: FromParallelIterator<PAR_ITER>,
          T: Ord + Send,
{
    fn from_par_iter(par_iter: PAR_ITER) -> Self {
        Vec::from_par_iter(par_iter).into()
    }
}

/// Collect items from a parallel iterator into a freshly allocated
/// linked list.
impl<PAR_ITER, T> FromParallelIterator<PAR_ITER> for LinkedList<T>
    where PAR_ITER: ParallelIterator<Item=T>,
          T: Send,
{
    fn from_par_iter(par_iter: PAR_ITER) -> Self {
        par_iter.map(|elem| { let mut list = LinkedList::new(); list.push_back(elem); list })
                .reduce_with(|mut list1, mut list2| { list1.append(&mut list2); list1 })
                .unwrap_or_else(|| LinkedList::new())
    }
}

/// Collect (key, value) pairs from a parallel iterator into a
/// hashmap. If multiple pairs correspond to the same key, then the
/// ones produced earlier in the parallel iterator will be
/// overwritten, just as with a sequential iterator.
impl<PAR_ITER, K, V, S> FromParallelIterator<PAR_ITER> for HashMap<K, V, S>
    where PAR_ITER: ParallelIterator<Item=(K, V)>,
          K: Eq + Hash + Send,
          V: Send,
          S: BuildHasher + Default + Send,
{
    fn from_par_iter(par_iter: PAR_ITER) -> Self {
        combine(par_iter, |list| {
            let len = combined_len(list);
            HashMap::with_capacity_and_hasher(len, Default::default())
        })
    }
}

/// Collect (key, value) pairs from a parallel iterator into a
/// btreemap. If multiple pairs correspond to the same key, then the
/// ones produced earlier in the parallel iterator will be
/// overwritten, just as with a sequential iterator.
impl<PAR_ITER, K, V> FromParallelIterator<PAR_ITER> for BTreeMap<K, V>
    where PAR_ITER: ParallelIterator<Item=(K, V)>,
          K: Ord + Send,
          V: Send,
{
    fn from_par_iter(par_iter: PAR_ITER) -> Self {
        combine(par_iter, |_| BTreeMap::new())
    }
}

/// Collect values from a parallel iterator into a hashset.
impl<PAR_ITER, V, S> FromParallelIterator<PAR_ITER> for HashSet<V, S>
    where PAR_ITER: ParallelIterator<Item=V>,
          V: Eq + Hash + Send,
          S: BuildHasher + Default + Send,
{
    fn from_par_iter(par_iter: PAR_ITER) -> Self {
        combine(par_iter, |list| {
            let len = combined_len(list);
            HashSet::with_capacity_and_hasher(len, Default::default())
        })
    }
}

/// Collect values from a parallel iterator into a btreeset.
impl<PAR_ITER, V> FromParallelIterator<PAR_ITER> for BTreeSet<V>
    where PAR_ITER: ParallelIterator<Item=V>,
          V: Send + Ord,
{
    fn from_par_iter(par_iter: PAR_ITER) -> Self {
        combine(par_iter, |_| BTreeSet::new())
    }
}
<commit_msg>Reference the map_collect benchmarks<commit_after>use super::{ParallelIterator, ExactParallelIterator};

use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use std::hash::{BuildHasher, Hash};
use std::collections::LinkedList;
use std::collections::{BinaryHeap, VecDeque};

pub trait FromParallelIterator<PAR_ITER> {
    fn from_par_iter(par_iter: PAR_ITER) -> Self;
}

fn combine<PAR_ITER, START, COLL>(par_iter: PAR_ITER, make_start: START) -> COLL
    where PAR_ITER: ParallelIterator,
          START: FnOnce(&LinkedList<Vec<PAR_ITER::Item>>) -> COLL,
          COLL: Extend<PAR_ITER::Item>
{
    let list = par_iter
        .fold(Vec::new, |mut vec, elem| { vec.push(elem); vec })
        .collect();

    let start = make_start(&list);
    list.into_iter()
        .fold(start, |mut coll, vec| { coll.extend(vec); coll })
}

fn combined_len<T>(list: &LinkedList<Vec<T>>) -> usize {
    list.iter().map(Vec::len).sum()
}

/// Collect items from a parallel iterator into a freshly allocated
/// vector. This is very efficient, but requires precise knowledge of
/// the number of items being iterated.
impl<PAR_ITER, T> FromParallelIterator<PAR_ITER> for Vec<T>
    where PAR_ITER: ExactParallelIterator<Item=T>,
          T: Send,
{
    fn from_par_iter(par_iter: PAR_ITER) -> Self {
        let mut vec = vec![];
        par_iter.collect_into(&mut vec);
        vec
    }
}

/// Collect items from a parallel iterator into a vecdeque.
impl<PAR_ITER, T> FromParallelIterator<PAR_ITER> for VecDeque<T>
    where Vec<T>: FromParallelIterator<PAR_ITER>,
          T: Send,
{
    fn from_par_iter(par_iter: PAR_ITER) -> Self {
        Vec::from_par_iter(par_iter).into()
    }
}

/// Collect items from a parallel iterator into a binaryheap.
/// The heap-ordering is calculated serially after all items are collected.
impl<PAR_ITER, T> FromParallelIterator<PAR_ITER> for BinaryHeap<T>
    where Vec<T>: FromParallelIterator<PAR_ITER>,
          T: Ord + Send,
{
    fn from_par_iter(par_iter: PAR_ITER) -> Self {
        Vec::from_par_iter(par_iter).into()
    }
}

/// Collect items from a parallel iterator into a freshly allocated
/// linked list.
impl<PAR_ITER, T> FromParallelIterator<PAR_ITER> for LinkedList<T>
    where PAR_ITER: ParallelIterator<Item=T>,
          T: Send,
{
    fn from_par_iter(par_iter: PAR_ITER) -> Self {
        par_iter.map(|elem| { let mut list = LinkedList::new(); list.push_back(elem); list })
                .reduce_with(|mut list1, mut list2| { list1.append(&mut list2); list1 })
                .unwrap_or_else(|| LinkedList::new())
    }
}

/// Collect (key, value) pairs from a parallel iterator into a
/// hashmap. If multiple pairs correspond to the same key, then the
/// ones produced earlier in the parallel iterator will be
/// overwritten, just as with a sequential iterator.
impl<PAR_ITER, K, V, S> FromParallelIterator<PAR_ITER> for HashMap<K, V, S>
    where PAR_ITER: ParallelIterator<Item=(K, V)>,
          K: Eq + Hash + Send,
          V: Send,
          S: BuildHasher + Default + Send,
{
    fn from_par_iter(par_iter: PAR_ITER) -> Self {
        // See the map_collect benchmarks in rayon-demo for different strategies.
        combine(par_iter, |list| {
            let len = combined_len(list);
            HashMap::with_capacity_and_hasher(len, Default::default())
        })
    }
}

/// Collect (key, value) pairs from a parallel iterator into a
/// btreemap. If multiple pairs correspond to the same key, then the
/// ones produced earlier in the parallel iterator will be
/// overwritten, just as with a sequential iterator.
impl<PAR_ITER, K, V> FromParallelIterator<PAR_ITER> for BTreeMap<K, V>
    where PAR_ITER: ParallelIterator<Item=(K, V)>,
          K: Ord + Send,
          V: Send,
{
    fn from_par_iter(par_iter: PAR_ITER) -> Self {
        combine(par_iter, |_| BTreeMap::new())
    }
}

/// Collect values from a parallel iterator into a hashset.
impl<PAR_ITER, V, S> FromParallelIterator<PAR_ITER> for HashSet<V, S>
    where PAR_ITER: ParallelIterator<Item=V>,
          V: Eq + Hash + Send,
          S: BuildHasher + Default + Send,
{
    fn from_par_iter(par_iter: PAR_ITER) -> Self {
        combine(par_iter, |list| {
            let len = combined_len(list);
            HashSet::with_capacity_and_hasher(len, Default::default())
        })
    }
}

/// Collect values from a parallel iterator into a btreeset.
impl<PAR_ITER, V> FromParallelIterator<PAR_ITER> for BTreeSet<V>
    where PAR_ITER: ParallelIterator<Item=V>,
          V: Send + Ord,
{
    fn from_par_iter(par_iter: PAR_ITER) -> Self {
        combine(par_iter, |_| BTreeSet::new())
    }
}
<|endoftext|>


<commit_before>use std::ffi::OsStr;
use std::fmt::Display;
use std::io::BufRead;

use clap::{self, Arg, SubCommand};
use shlex;

use config::{self, Config};
use errors::Result;
use repository::{self, Repository};
use vcs;

pub struct App {
  config: Config,
}

impl App {
  /// Creates a new instance of rhq application.
  pub fn new() -> Result<App> {
    let config = config::read_all_config()?;
    Ok(App { config: config })
  }

  pub fn clone_from_queries<Q, R, S>(&self, queries: R, args: Vec<S>, dry_run: bool) -> Result<()>
    where Q: AsRef<str>,
          R: Iterator<Item = Q>,
          S: AsRef<OsStr> + Display
  {
    for query in queries {
      let query = query.as_ref().parse()?;
      vcs::clone_from_query(query, &self.config.root, &args, dry_run)?;
    }
    Ok(())
  }

  pub fn iter_repos<F>(&self, func: F) -> Result<()>
    where F: Fn(&Repository) -> Result<()>
  {
    for root in self.config.roots() {
      for ref repo in repository::collect_from(root) {
        func(repo)?;
      }
    }
    Ok(())
  }

  /// Returns the reference of configuration.
  pub fn command_config(&self) -> Result<()> {
    println!("{}", self.config);
    Ok(())
  }
}

#[cfg_attr(rustfmt, rustfmt_skip)]
fn build_cli() -> clap::App<'static, 'static> {
  cli_template()
    .subcommand(SubCommand::with_name("clone")
      .about("Clone remote repositories into the root directory")
      .arg(Arg::from_usage("[query]         'URL or query of remote repository'"))
      .arg(Arg::from_usage("--arg=[arg]     'Supplemental arguments for Git command'"))
      .arg(Arg::from_usage("-n, --dry-run   'Do not actually execute Git command'")))

    .subcommand(SubCommand::with_name("list")
      .about("List local repositories managed by rhq"))

    .subcommand(SubCommand::with_name("foreach")
      .about("Execute command into each repositories")
      .arg(Arg::from_usage("<command>       'Command name'"))
      .arg(Arg::from_usage("[args]...       'Arguments of command'"))
      .arg(Arg::from_usage("-n, --dry-run   'Do not actually execute command'")))

    .subcommand(SubCommand::with_name("config")
      .about("Show current configuration"))
}

pub fn run() -> Result<()> {
  let matches = get_matches(build_cli())?;

  let app = App::new()?;
  match matches.subcommand() {
    ("clone", Some(m)) => {
      let args = m.value_of("arg").and_then(|s| shlex::split(s)).unwrap_or_default();
      let dry_run = m.is_present("dry-run");

      if let Some(query) = m.value_of("query") {
        app.clone_from_queries(vec![query].into_iter(), args, dry_run)?;
      } else {
        let stdin = ::std::io::stdin();
        app.clone_from_queries(stdin.lock().lines().filter_map(|l| l.ok()), args, dry_run)?;
      }

      Ok(())
    }
    ("list", _) => {
      app.iter_repos(|ref repo| {
        println!("{}", repo.path_string());
        Ok(())
      })
    }
    ("foreach", Some(m)) => {
      let command = m.value_of("command").unwrap();
      let args: Vec<_> = m.values_of("args").map(|s| s.collect()).unwrap_or_default();
      let dry_run = m.is_present("dry-run");
      app.iter_repos(|repo| if repo.run_command(command, &args, dry_run)? {
        Ok(())
      } else {
        Err("failed to execute command".to_owned().into())
      })
    }
    ("config", _) => app.command_config(),
    _ => unreachable!(),
  }
}

fn cli_template<'a, 'b>() -> clap::App<'a, 'b> {
  app_from_crate!()
    .setting(clap::AppSettings::VersionlessSubcommands)
    .setting(clap::AppSettings::SubcommandRequiredElseHelp)
    .subcommand(clap::SubCommand::with_name("completion")
      .about("Generate completion scripts for your shell")
      .setting(clap::AppSettings::ArgRequiredElseHelp)
      .arg(clap::Arg::with_name("shell")
        .help("target shell")
        .possible_values(&["bash", "zsh", "fish", "powershell"])
        .required(true))
      .arg(Arg::from_usage("[out-file]  'path to output script'")))
}

fn get_matches<'a, 'b>(mut cli: clap::App<'a, 'b>) -> ::std::io::Result<clap::ArgMatches<'a>> {
  let matches = cli.clone().get_matches();
  if let ("completion", Some(m)) = matches.subcommand() {
    let shell = m.value_of("shell")
      .and_then(|s| s.parse().ok())
      .expect("failed to parse target shell");

    if let Some(path) = m.value_of("out-file") {
      let mut file =
        ::std::fs::OpenOptions::new().write(true).create(true).append(false).open(path)?;
      cli.gen_completions_to(env!("CARGO_PKG_NAME"), shell, &mut file);
    } else {
      cli.gen_completions_to(env!("CARGO_PKG_NAME"), shell, &mut ::std::io::stdout());
    }
    ::std::process::exit(0);
  }
  Ok(matches)
}
<commit_msg>clone: add option "--root", for setting root directory explicitly<commit_after>use std::ffi::OsStr;
use std::fmt::Display;
use std::io::BufRead;
use std::path::PathBuf;

use clap::{self, Arg, SubCommand};
use shlex;

use config::{self, Config};
use errors::Result;
use repository::{self, Repository};
use vcs;

pub struct App {
  config: Config,
}

impl App {
  /// Creates a new instance of rhq application.
  pub fn new() -> Result<App> {
    let config = config::read_all_config()?;
    Ok(App { config: config })
  }

  pub fn clone_from_queries<Q, R, S>(&self,
                                     queries: R,
                                     args: Vec<S>,
                                     dry_run: bool,
                                     root: Option<&str>)
                                     -> Result<()>
    where Q: AsRef<str>,
          R: Iterator<Item = Q>,
          S: AsRef<OsStr> + Display
  {
    let root = root.map(|s| PathBuf::from(s));
    let root = root.as_ref().unwrap_or(&self.config.root);
    for query in queries {
      let query = query.as_ref().parse()?;
      vcs::clone_from_query(query, root, &args, dry_run)?;
    }
    Ok(())
  }

  pub fn iter_repos<F>(&self, func: F) -> Result<()>
    where F: Fn(&Repository) -> Result<()>
  {
    for root in self.config.roots() {
      for ref repo in repository::collect_from(root) {
        func(repo)?;
      }
    }
    Ok(())
  }

  /// Returns the reference of configuration.
  pub fn command_config(&self) -> Result<()> {
    println!("{}", self.config);
    Ok(())
  }
}

#[cfg_attr(rustfmt, rustfmt_skip)]
fn build_cli() -> clap::App<'static, 'static> {
  cli_template()
    .subcommand(SubCommand::with_name("clone")
      .about("Clone remote repositories into the root directory")
      .arg(Arg::from_usage("[query]         'URL or query of remote repository'"))
      .arg(Arg::from_usage("--root=[root]   'Root directory of cloned repository'"))
      .arg(Arg::from_usage("--arg=[arg]     'Supplemental arguments for Git command'"))
      .arg(Arg::from_usage("-n, --dry-run   'Do not actually execute Git command'")))

    .subcommand(SubCommand::with_name("list")
      .about("List local repositories managed by rhq"))

    .subcommand(SubCommand::with_name("foreach")
      .about("Execute command into each repositories")
      .arg(Arg::from_usage("<command>       'Command name'"))
      .arg(Arg::from_usage("[args]...       'Arguments of command'"))
      .arg(Arg::from_usage("-n, --dry-run   'Do not actually execute command'")))

    .subcommand(SubCommand::with_name("config")
      .about("Show current configuration"))
}

pub fn run() -> Result<()> {
  let matches = get_matches(build_cli())?;

  let app = App::new()?;
  match matches.subcommand() {
    ("clone", Some(m)) => {
      let args = m.value_of("arg").and_then(|s| shlex::split(s)).unwrap_or_default();
      let root = m.value_of("root");
      let dry_run = m.is_present("dry-run");

      if let Some(query) = m.value_of("query") {
        app.clone_from_queries(vec![query].into_iter(), args, dry_run, root)?;
      } else {
        let stdin = ::std::io::stdin();
        app.clone_from_queries(stdin.lock().lines().filter_map(|l| l.ok()),
                              args,
                              dry_run,
                              root)?;
      }

      Ok(())
    }
    ("list", _) => {
      app.iter_repos(|ref repo| {
        println!("{}", repo.path_string());
        Ok(())
      })
    }
    ("foreach", Some(m)) => {
      let command = m.value_of("command").unwrap();
      let args: Vec<_> = m.values_of("args").map(|s| s.collect()).unwrap_or_default();
      let dry_run = m.is_present("dry-run");
      app.iter_repos(|repo| if repo.run_command(command, &args, dry_run)? {
        Ok(())
      } else {
        Err("failed to execute command".to_owned().into())
      })
    }
    ("config", _) => app.command_config(),
    _ => unreachable!(),
  }
}

fn cli_template<'a, 'b>() -> clap::App<'a, 'b> {
  app_from_crate!()
    .setting(clap::AppSettings::VersionlessSubcommands)
    .setting(clap::AppSettings::SubcommandRequiredElseHelp)
    .subcommand(clap::SubCommand::with_name("completion")
      .about("Generate completion scripts for your shell")
      .setting(clap::AppSettings::ArgRequiredElseHelp)
      .arg(clap::Arg::with_name("shell")
        .help("target shell")
        .possible_values(&["bash", "zsh", "fish", "powershell"])
        .required(true))
      .arg(Arg::from_usage("[out-file]  'path to output script'")))
}

fn get_matches<'a, 'b>(mut cli: clap::App<'a, 'b>) -> ::std::io::Result<clap::ArgMatches<'a>> {
  let matches = cli.clone().get_matches();
  if let ("completion", Some(m)) = matches.subcommand() {
    let shell = m.value_of("shell")
      .and_then(|s| s.parse().ok())
      .expect("failed to parse target shell");

    if let Some(path) = m.value_of("out-file") {
      let mut file =
        ::std::fs::OpenOptions::new().write(true).create(true).append(false).open(path)?;
      cli.gen_completions_to(env!("CARGO_PKG_NAME"), shell, &mut file);
    } else {
      cli.gen_completions_to(env!("CARGO_PKG_NAME"), shell, &mut ::std::io::stdout());
    }
    ::std::process::exit(0);
  }
  Ok(matches)
}
<|endoftext|>


<commit_before>use quickcheck::{Arbitrary, Gen};
use rand::{
    distributions::{weighted::WeightedIndex, Distribution},
    Rng,
};

use crate::MultihashGeneric;

/// Generates a random valid multihash.
impl Arbitrary for MultihashGeneric<64> {
    fn arbitrary<G: Gen>(g: &mut G) -> Self {
        // In real world lower multihash codes are more likely to happen, hence distribute them
        // with bias towards smaller values.
        let weights = [128, 64, 32, 16, 8, 4, 2, 1];
        let dist = WeightedIndex::new(weights.iter()).unwrap();
        let code = match dist.sample(g) {
            0 => g.gen_range(0, u64::pow(2, 7)),
            1 => g.gen_range(u64::pow(2, 7), u64::pow(2, 14)),
            2 => g.gen_range(u64::pow(2, 14), u64::pow(2, 21)),
            3 => g.gen_range(u64::pow(2, 21), u64::pow(2, 28)),
            4 => g.gen_range(u64::pow(2, 28), u64::pow(2, 35)),
            5 => g.gen_range(u64::pow(2, 35), u64::pow(2, 42)),
            6 => g.gen_range(u64::pow(2, 42), u64::pow(2, 49)),
            7 => g.gen_range(u64::pow(2, 56), u64::pow(2, 63)),
            _ => unreachable!(),
        };

        // Maximum size is 64 byte due to the `U64` generic
        let size = g.gen_range(0, 64);
        let mut data = [0; 64];
        g.fill_bytes(&mut data);
        MultihashGeneric::wrap(code, &data[..size]).unwrap()
    }
}
<commit_msg>make arbitrary generic over size<commit_after>use quickcheck::{Arbitrary, Gen};
use rand::{
    distributions::{weighted::WeightedIndex, Distribution},
    Rng,
};

use crate::MultihashGeneric;

/// Generates a random valid multihash.
impl<const S: usize> Arbitrary for MultihashGeneric<S> {
    fn arbitrary<G: Gen>(g: &mut G) -> Self {
        // In real world lower multihash codes are more likely to happen, hence distribute them
        // with bias towards smaller values.
        let weights = [128, 64, 32, 16, 8, 4, 2, 1];
        let dist = WeightedIndex::new(weights.iter()).unwrap();
        let code = match dist.sample(g) {
            0 => g.gen_range(0, u64::pow(2, 7)),
            1 => g.gen_range(u64::pow(2, 7), u64::pow(2, 14)),
            2 => g.gen_range(u64::pow(2, 14), u64::pow(2, 21)),
            3 => g.gen_range(u64::pow(2, 21), u64::pow(2, 28)),
            4 => g.gen_range(u64::pow(2, 28), u64::pow(2, 35)),
            5 => g.gen_range(u64::pow(2, 35), u64::pow(2, 42)),
            6 => g.gen_range(u64::pow(2, 42), u64::pow(2, 49)),
            7 => g.gen_range(u64::pow(2, 56), u64::pow(2, 63)),
            _ => unreachable!(),
        };

        // Maximum size is S byte due to the generic.
        let size = g.gen_range(0, S);
        let mut data = [0; S];
        g.fill_bytes(&mut data);
        MultihashGeneric::wrap(code, &data[..size]).unwrap()
    }
}
<|endoftext|>


<commit_before>use core::intrinsics;

#[cfg(feature = "mem")]
use mem::{memcpy, memmove, memset};

// NOTE This function and the ones below are implemented using assembly because they using a custom
// calling convention which can't be implemented using a normal Rust function
#[naked]
#[cfg_attr(not(test), no_mangle)]
pub unsafe fn __aeabi_uidivmod() {
    asm!("push {lr}
          sub sp, sp, #4
          mov r2, sp
          bl __udivmodsi4
          ldr r1, [sp]
          add sp, sp, #4
          pop {pc}");
    intrinsics::unreachable();
}

#[naked]
#[cfg_attr(not(test), no_mangle)]
pub unsafe fn __aeabi_uldivmod() {
    asm!("push {r4, lr}
          sub sp, sp, #16
          add r4, sp, #8
          str r4, [sp]
          bl __udivmoddi4
          ldr r2, [sp, #8]
          ldr r3, [sp, #12]
          add sp, sp, #16
          pop {r4, pc}");
    intrinsics::unreachable();
}

#[naked]
#[cfg_attr(not(test), no_mangle)]
pub unsafe fn __aeabi_idivmod() {
    asm!("push {r0, r1, r4, lr}
          bl __divsi3
          pop {r1, r2}
          muls r2, r2, r0
          subs r1, r1, r2
          pop {r4, pc}");
    intrinsics::unreachable();
}

#[naked]
#[cfg_attr(not(test), no_mangle)]
pub unsafe fn __aeabi_ldivmod() {
    asm!("push {r4, lr}
          sub sp, sp, #16
          add r4, sp, #8
          str r4, [sp]
          bl __divmoddi4
          ldr r2, [sp, #8]
          ldr r3, [sp, #12]
          add sp, sp, #16
          pop {r4, pc}");
    intrinsics::unreachable();
}

#[cfg_attr(not(test), no_mangle)]
pub extern "aapcs" fn __aeabi_dadd(a: f64, b: f64) -> f64 {
    ::float::add::__adddf3(a, b)
}

#[cfg_attr(not(test), no_mangle)]
pub extern "aapcs" fn __aeabi_fadd(a: f32, b: f32) -> f32 {
    ::float::add::__addsf3(a, b)
}

#[cfg_attr(not(test), no_mangle)]
pub extern "aapcs" fn __aeabi_dsub(a: f64, b: f64) -> f64 {
    ::float::sub::__subdf3(a, b)
}

#[cfg_attr(not(test), no_mangle)]
pub extern "aapcs" fn __aeabi_fsub(a: f32, b: f32) -> f32 {
    ::float::sub::__subsf3(a, b)
}

#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))]
#[cfg_attr(not(test), no_mangle)]
pub extern "aapcs" fn __aeabi_idiv(a: i32, b: i32) -> i32 {
    ::int::sdiv::__divsi3(a, b)
}

#[cfg_attr(not(test), no_mangle)]
pub extern "aapcs" fn __aeabi_lasr(a: i64, b: u32) -> i64 {
    ::int::shift::__ashrdi3(a, b)
}

#[cfg_attr(not(test), no_mangle)]
pub extern "aapcs" fn __aeabi_llsl(a: u64, b: u32) -> u64 {
    ::int::shift::__ashldi3(a, b)
}

#[cfg_attr(not(test), no_mangle)]
pub extern "aapcs" fn __aeabi_llsr(a: u64, b: u32) -> u64 {
    ::int::shift::__lshrdi3(a, b)
}

#[cfg_attr(not(test), no_mangle)]
pub extern "aapcs" fn __aeabi_lmul(a: u64, b: u64) -> u64 {
    ::int::mul::__muldi3(a, b)
}

#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))]
#[cfg_attr(not(test), no_mangle)]
pub extern "aapcs" fn __aeabi_uidiv(a: u32, b: u32) -> u32 {
    ::int::udiv::__udivsi3(a, b)
}

#[cfg(not(feature = "c"))]
#[cfg_attr(not(test), no_mangle)]
pub extern "C" fn __aeabi_ui2d(a: u32) -> f64 {
    ::float::conv::__floatunsidf(a)
}

// TODO: These aeabi_* functions should be defined as aliases
#[cfg(not(feature = "mem"))]
extern "C" {
    fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8;
    fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8;
    fn memset(dest: *mut u8, c: i32, n: usize) -> *mut u8;
}

// FIXME: The `*4` and `*8` variants should be defined as aliases.

#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) {
    memcpy(dest, src, n);
}
#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, n: usize) {
    memcpy(dest, src, n);
}
#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "aapcs" fn __aeabi_memcpy8(dest: *mut u8, src: *const u8, n: usize) {
    memcpy(dest, src, n);
}

#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "aapcs" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) {
    memmove(dest, src, n);
}
#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "aapcs" fn __aeabi_memmove4(dest: *mut u8, src: *const u8, n: usize) {
    memmove(dest, src, n);
}
#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "aapcs" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: usize) {
    memmove(dest, src, n);
}

// Note the different argument order
#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) {
    memset(dest, c, n);
}
#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, n: usize, c: i32) {
    memset(dest, c, n);
}
#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "aapcs" fn __aeabi_memset8(dest: *mut u8, n: usize, c: i32) {
    memset(dest, c, n);
}

#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "aapcs" fn __aeabi_memclr(dest: *mut u8, n: usize) {
    memset(dest, 0, n);
}
#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) {
    memset(dest, 0, n);
}
#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) {
    memset(dest, 0, n);
}

#[cfg(test)]
mod tests {
    use quickcheck::TestResult;
    use qc::{U32, U64};

    quickcheck!{
        fn uldivmod(n: U64, d: U64) -> TestResult {
            let (n, d) = (n.0, d.0);
            if d == 0 {
                TestResult::discard()
            } else {
                let q: u64;
                let r: u64;
                unsafe {
                    // The inline asm is a bit tricky here, LLVM will allocate
                    // both r0 and r1 when we specify a 64-bit value for {r0}.
                    asm!("bl __aeabi_uldivmod"
                         : "={r0}" (q), "={r2}" (r)
                         : "{r0}" (n), "{r2}" (d)
                         : "r12", "lr", "flags");
                }
                TestResult::from_bool(q == n / d && r == n % d)
            }
        }

        fn uidivmod(n: U32, d: U32) -> TestResult {
            let (n, d) = (n.0, d.0);
            if d == 0 {
                TestResult::discard()
            } else {
                let q: u32;
                let r: u32;
                unsafe {
                    asm!("bl __aeabi_uidivmod"
                         : "={r0}" (q), "={r1}" (r)
                         : "{r0}" (n), "{r1}" (d)
                         : "r2", "r3", "r12", "lr", "flags");
                }
                TestResult::from_bool(q == n / d && r == n % d)
            }
        }

        fn ldivmod(n: U64, d: U64) -> TestResult {
            let (n, d) = (n.0 as i64, d.0 as i64);
            if d == 0 {
                TestResult::discard()
            } else {
                let q: i64;
                let r: i64;
                unsafe {
                    // The inline asm is a bit tricky here, LLVM will allocate
                    // both r0 and r1 when we specify a 64-bit value for {r0}.
                    asm!("bl __aeabi_ldivmod"
                         : "={r0}" (q), "={r2}" (r)
                         : "{r0}" (n), "{r2}" (d)
                         : "r12", "lr", "flags");
                }
                TestResult::from_bool(q == n / d && r == n % d)
            }
        }

        fn idivmod(n: U32, d: U32) -> TestResult {
            let (n, d) = (n.0 as i32, d.0 as i32);
            if d == 0 || (n == i32::min_value() && d == -1) {
                TestResult::discard()
            } else {
                let q: i32;
                let r: i32;
                unsafe {
                    asm!("bl __aeabi_idivmod"
                         : "={r0}" (q), "={r1}" (r)
                         : "{r0}" (n), "{r1}" (d)
                         : "r2", "r3", "r12", "lr", "flags");
                }
                TestResult::from_bool(q == n / d && r == n % d)
            }
        }
    }
}
<commit_msg>remove arm tests from the old test suite<commit_after>use core::intrinsics;

#[cfg(feature = "mem")]
use mem::{memcpy, memmove, memset};

// NOTE This function and the ones below are implemented using assembly because they using a custom
// calling convention which can't be implemented using a normal Rust function
#[naked]
#[cfg_attr(not(test), no_mangle)]
pub unsafe fn __aeabi_uidivmod() {
    asm!("push {lr}
          sub sp, sp, #4
          mov r2, sp
          bl __udivmodsi4
          ldr r1, [sp]
          add sp, sp, #4
          pop {pc}");
    intrinsics::unreachable();
}

#[naked]
#[cfg_attr(not(test), no_mangle)]
pub unsafe fn __aeabi_uldivmod() {
    asm!("push {r4, lr}
          sub sp, sp, #16
          add r4, sp, #8
          str r4, [sp]
          bl __udivmoddi4
          ldr r2, [sp, #8]
          ldr r3, [sp, #12]
          add sp, sp, #16
          pop {r4, pc}");
    intrinsics::unreachable();
}

#[naked]
#[cfg_attr(not(test), no_mangle)]
pub unsafe fn __aeabi_idivmod() {
    asm!("push {r0, r1, r4, lr}
          bl __divsi3
          pop {r1, r2}
          muls r2, r2, r0
          subs r1, r1, r2
          pop {r4, pc}");
    intrinsics::unreachable();
}

#[naked]
#[cfg_attr(not(test), no_mangle)]
pub unsafe fn __aeabi_ldivmod() {
    asm!("push {r4, lr}
          sub sp, sp, #16
          add r4, sp, #8
          str r4, [sp]
          bl __divmoddi4
          ldr r2, [sp, #8]
          ldr r3, [sp, #12]
          add sp, sp, #16
          pop {r4, pc}");
    intrinsics::unreachable();
}

#[cfg_attr(not(test), no_mangle)]
pub extern "aapcs" fn __aeabi_dadd(a: f64, b: f64) -> f64 {
    ::float::add::__adddf3(a, b)
}

#[cfg_attr(not(test), no_mangle)]
pub extern "aapcs" fn __aeabi_fadd(a: f32, b: f32) -> f32 {
    ::float::add::__addsf3(a, b)
}

#[cfg_attr(not(test), no_mangle)]
pub extern "aapcs" fn __aeabi_dsub(a: f64, b: f64) -> f64 {
    ::float::sub::__subdf3(a, b)
}

#[cfg_attr(not(test), no_mangle)]
pub extern "aapcs" fn __aeabi_fsub(a: f32, b: f32) -> f32 {
    ::float::sub::__subsf3(a, b)
}

#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))]
#[cfg_attr(not(test), no_mangle)]
pub extern "aapcs" fn __aeabi_idiv(a: i32, b: i32) -> i32 {
    ::int::sdiv::__divsi3(a, b)
}

#[cfg_attr(not(test), no_mangle)]
pub extern "aapcs" fn __aeabi_lasr(a: i64, b: u32) -> i64 {
    ::int::shift::__ashrdi3(a, b)
}

#[cfg_attr(not(test), no_mangle)]
pub extern "aapcs" fn __aeabi_llsl(a: u64, b: u32) -> u64 {
    ::int::shift::__ashldi3(a, b)
}

#[cfg_attr(not(test), no_mangle)]
pub extern "aapcs" fn __aeabi_llsr(a: u64, b: u32) -> u64 {
    ::int::shift::__lshrdi3(a, b)
}

#[cfg_attr(not(test), no_mangle)]
pub extern "aapcs" fn __aeabi_lmul(a: u64, b: u64) -> u64 {
    ::int::mul::__muldi3(a, b)
}

#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))]
#[cfg_attr(not(test), no_mangle)]
pub extern "aapcs" fn __aeabi_uidiv(a: u32, b: u32) -> u32 {
    ::int::udiv::__udivsi3(a, b)
}

#[cfg(not(feature = "c"))]
#[cfg_attr(not(test), no_mangle)]
pub extern "C" fn __aeabi_ui2d(a: u32) -> f64 {
    ::float::conv::__floatunsidf(a)
}

// TODO: These aeabi_* functions should be defined as aliases
#[cfg(not(feature = "mem"))]
extern "C" {
    fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8;
    fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8;
    fn memset(dest: *mut u8, c: i32, n: usize) -> *mut u8;
}

// FIXME: The `*4` and `*8` variants should be defined as aliases.

#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) {
    memcpy(dest, src, n);
}
#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, n: usize) {
    memcpy(dest, src, n);
}
#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "aapcs" fn __aeabi_memcpy8(dest: *mut u8, src: *const u8, n: usize) {
    memcpy(dest, src, n);
}

#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "aapcs" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) {
    memmove(dest, src, n);
}
#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "aapcs" fn __aeabi_memmove4(dest: *mut u8, src: *const u8, n: usize) {
    memmove(dest, src, n);
}
#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "aapcs" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: usize) {
    memmove(dest, src, n);
}

// Note the different argument order
#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) {
    memset(dest, c, n);
}
#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, n: usize, c: i32) {
    memset(dest, c, n);
}
#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "aapcs" fn __aeabi_memset8(dest: *mut u8, n: usize, c: i32) {
    memset(dest, c, n);
}

#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "aapcs" fn __aeabi_memclr(dest: *mut u8, n: usize) {
    memset(dest, 0, n);
}
#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) {
    memset(dest, 0, n);
}
#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) {
    memset(dest, 0, n);
}
<|endoftext|>


<commit_before>//! Methods for reading tile and static data out of art.mul
//!
//! Tiles and Statics are both traditionally stored in art.mul/artidx.mul
use std::fs::{File};
use mul_reader::MulReader;
use std::io::{Result, Error, ErrorKind, Cursor, SeekFrom, Seek, Write, Read};
use color::{Color, Color16, Color32};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use utils::{MEMWRITER_ERROR, SURFACE_ERROR};
use std::path::Path;

#[cfg(feature = "use-sdl2")]
use sdl2::surface::Surface;
#[cfg(feature = "use-sdl2")]
use sdl2::pixels::PixelFormatEnum;

use image::{Rgba, RgbaImage};

pub trait Art {
    /**
     * Convert to a 32bit array
     *
     * Returns (width, height, colors)
     */
    fn to_32bit(&self) -> (u32, u32, Vec<Color32>);
    fn serialize(&self) -> Vec<u8>;

    #[cfg(feature = "use-sdl2")]
    fn to_surface(&self) -> Surface;

    fn to_image(&self) -> RgbaImage;
}

pub const TILE_SIZE: u32 = 2048;
pub const STATIC_OFFSET: u32 = 0x4000;

pub struct RunPair {
    pub offset: u16,
    pub run: Vec<Color16>
}

impl RunPair {
    fn serialize(&self) -> Vec<u8> {
        let mut writer = vec![];

        writer.write_u16::<LittleEndian>(self.offset).expect(MEMWRITER_ERROR);
        writer.write_u16::<LittleEndian>(self.run.len() as u16).expect(MEMWRITER_ERROR);
        for &color in self.run.iter() {
            writer.write_u16::<LittleEndian>(color).expect(MEMWRITER_ERROR);
        }
        writer
    }
}

pub type StaticRow = Vec<RunPair>;

/// A Map Tile, 44px by 44px
///
/// Map tiles are stored as
/// |Header:u32|Pixels:u16|
/// Where pixels represents a list of rows, length 2, 4, 6, 8 .. 42, 44, 44, 42 .. 8, 6, 4, 2 and are drawn
/// centred
pub struct Tile {
    /// Header information for a tile.  Unused
    pub header: u32,
    /// Individual pixels. These work as rows, of length 2, 4, 6, 8 .. 42, 44, 44, 42 .. 8, 6, 4, 2
    pub image_data: [Color16; 1022]
}

impl Art for Tile {
    fn to_32bit(&self) -> (u32, u32, Vec<Color32>) {
        let mut image: Vec<Color32> = vec![];

        let mut read_idx = 0;

        for i in 0..44 {

            let slice_size = if i >= 22 {
                (44 - i) * 2
            } else {
                (i + 1) * 2
            };

            image.extend_from_slice(vec![0; (22 - (slice_size / 2))].as_slice());
            for _pixel_idx in 0..slice_size {
                let (r, g, b, a) = self.image_data[read_idx].to_rgba();
                image.push(Color::from_rgba(r, g, b, a));
                read_idx += 1;
            }
            image.extend_from_slice(vec![0; (22 - (slice_size / 2))].as_slice());
        };
        (44, 44, image)
    }

    fn serialize(&self) -> Vec<u8> {
        let mut writer = vec![];
        writer.write_u32::<LittleEndian>(self.header).ok().expect(MEMWRITER_ERROR);
        for &pixel in self.image_data.iter() {
            writer.write_u16::<LittleEndian>(pixel).ok().expect(MEMWRITER_ERROR);
        }
        writer
    }

    fn to_image(&self) -> RgbaImage {
        let mut buffer = RgbaImage::new(44, 44);
        let mut read_idx = 0;

        for y in 0..44 {

            let slice_size = if y >= 22 {
                (44 - y) * 2
            } else {
                (y + 1) * 2
            };

            let indent = 22 - (slice_size / 2);

            for x in 0..slice_size {
                let (r, g, b, a) = self.image_data[read_idx].to_rgba();
                buffer.put_pixel(indent + x, y, Rgba([r, g, b, a]));
                read_idx += 1;
            }
        };
        buffer
    }

    #[cfg(feature = "use-sdl2")]
    fn to_surface(&self) -> Surface {
        let mut surface = Surface::new(44, 44, PixelFormatEnum::RGBA8888).expect(SURFACE_ERROR);
        surface.with_lock_mut(|bitmap| {
            let mut read_idx = 0;

            for y in 0..44 {

                let slice_width = if y >= 22 {
                    (44 - y) * 2
                } else {
                    (y + 1) * 2
                };

                let offset_left = 22 - (slice_width / 2);
                for pixel_idx in 0..slice_width {
                    let x = offset_left + pixel_idx;
                    let (r, g, b, a) = self.image_data[read_idx].to_rgba();
                    let target = ((y * 44) + x) * 4;
                    bitmap[target] = a;
                    bitmap[target + 1] = b;
                    bitmap[target + 2] = g;
                    bitmap[target + 3] = r;
                    read_idx += 1;
                }
            };
        });
        surface
    }
}

impl Art for Static {
    fn to_32bit(&self) -> (u32, u32, Vec<Color32>) {
        let mut image: Vec<Color32> = vec![];

        for row in self.rows.iter() {
            let mut current_width = 0;
            for run_pair in row.iter() {
                image.extend_from_slice(vec![0; run_pair.offset as usize].as_slice());
                for pixel in run_pair.run.iter() {
                    let (r, g, b, a) = pixel.to_rgba();
                    image.push(Color::from_rgba(r, g, b, a));
                }
                current_width += run_pair.offset  + run_pair.run.len() as u16;
                assert!(current_width <= self.width)
            }
            if current_width < self.width {
                image.extend_from_slice(vec![0; (self.width - current_width) as usize].as_slice());
            }
        };

        (self.width as u32, self.height as u32, image)
    }

    fn serialize(&self) -> Vec<u8> {
        let mut writer = vec![];
        writer.write_u16::<LittleEndian>(self.size).ok().expect(MEMWRITER_ERROR);
        writer.write_u16::<LittleEndian>(self.trigger).ok().expect(MEMWRITER_ERROR);
        writer.write_u16::<LittleEndian>(self.width).ok().expect(MEMWRITER_ERROR);
        writer.write_u16::<LittleEndian>(self.height).ok().expect(MEMWRITER_ERROR);

        let mut rows = vec![];

        //Write our rows
        for row in self.rows.iter() {
            let mut out = vec![];
            for pair in row.iter() {
                out.write(pair.serialize().as_slice()).ok().expect(MEMWRITER_ERROR);
            }
            //We write a "newline" after each out
            out.write_u16::<LittleEndian>(0).ok().expect(MEMWRITER_ERROR);
            out.write_u16::<LittleEndian>(0).ok().expect(MEMWRITER_ERROR);
            rows.push(out);
        }

        let mut lookup_table = vec![];
        let mut last_position = 0;
        //Generate a lookup table
        for row in rows.iter() {
            lookup_table.write_u16::<LittleEndian>(last_position).ok().expect(MEMWRITER_ERROR);
            last_position += (row.len() / 2) as u16;
        }
        writer.write(lookup_table.as_slice()).ok().expect(MEMWRITER_ERROR);
        for row in rows.iter() {
            writer.write(row.as_slice()).ok().expect(MEMWRITER_ERROR);
        }

        writer
    }

    fn to_image(&self) -> RgbaImage {
        panic!("Not implemented");
    }

    #[cfg(feature = "use-sdl2")]
    fn to_surface(&self) -> Surface {
        let mut surface = Surface::new(self.width as u32, self.height as u32, PixelFormatEnum::RGBA8888).expect(SURFACE_ERROR);
        let mut surface_target: usize = 0;

        surface.with_lock_mut(|bitmap| {
            for row in self.rows.iter() {
                let mut current_width = 0;
                for run_pair in row.iter() {
                    surface_target += run_pair.offset as usize * 4;
                    for pixel in run_pair.run.iter() {
                        let (r, g, b, a) = pixel.to_rgba();
                        bitmap[surface_target] = a;
                        bitmap[surface_target + 1] = b;
                        bitmap[surface_target + 2] = g;
                        bitmap[surface_target + 3] = r;
                        surface_target += 4;
                    }
                    current_width += run_pair.offset  + run_pair.run.len() as u16;
                    assert!(current_width <= self.width)
                }
                if current_width < self.width {
                    surface_target += (self.width - current_width) as usize * 4;
                }
            };
        });
        surface
    }
}

pub struct Static {
    pub size: u16,
    pub trigger: u16,
    pub width: u16,
    pub height: u16,
    pub rows: Vec<StaticRow>
}

pub enum TileOrStatic {
    Tile(Tile),
    Static(Static)
}

pub struct ArtReader<T: Read + Seek> {
    mul_reader: MulReader<T>
}

impl ArtReader<File> {

    pub fn new(index_path: &Path, mul_path: &Path) -> Result<ArtReader<File>> {
        let mul_reader = try!(MulReader::new(index_path, mul_path));
        Ok(ArtReader {
            mul_reader: mul_reader
        })
    }
}

impl <T: Read + Seek> ArtReader<T> {

    pub fn from_mul(reader: MulReader<T>) -> ArtReader<T> {
        ArtReader {
            mul_reader: reader
        }
    }

    pub fn read(&mut self, id: u32) -> Result<TileOrStatic> {
        let raw = try!(self.mul_reader.read(id));
        let mut reader = Cursor::new(raw.data);
        if id >= STATIC_OFFSET {
            //It's a static, so deal with accordingly
            let size = try!(reader.read_u16::<LittleEndian>());
            let trigger = try!(reader.read_u16::<LittleEndian>());
            let width = try!(reader.read_u16::<LittleEndian>());
            let height = try!(reader.read_u16::<LittleEndian>());
            if width == 0 || height >= 1024 || height == 0 || height >= 1024 {
                Err(Error::new(ErrorKind::Other, format!("Got invalid width and height of {}, {}", width, height)))
            } else {
                //Load our offset table
                let mut offset_table = vec![];
                for _index in 0..height {
                    offset_table.push(try!(reader.read_u16::<LittleEndian>()));
                }

                let data_start_pos = reader.position();
                let mut rows = vec![];

                for &offset in offset_table.iter() {
                    try!(reader.seek(SeekFrom::Start((data_start_pos + offset as u64 * 2))));
                    let mut row = vec![];

                    loop {
                        let x_offset = try!(reader.read_u16::<LittleEndian>());
                        let run_length = try!(reader.read_u16::<LittleEndian>());
                        if x_offset + run_length == 0 {
                            break
                        } else {
                            let mut run = vec![];
                            for _index in 0..run_length {
                                run.push(try!(reader.read_u16::<LittleEndian>()));
                            }

                            row.push(RunPair {
                                offset: x_offset,
                                run: run
                            });
                        }
                    }
                    rows.push(row);
                }

                Ok(TileOrStatic::Static(Static {
                    size: size,
                    trigger: trigger,
                    width: width,
                    height: height,
                    rows: rows
                }))
            }
        } else {
            //It's a map tile
            if raw.length != TILE_SIZE {
                Err(Error::new(ErrorKind::Other, format!("Got tile size of {}, expected {}", raw.length, TILE_SIZE)))
            } else {
                let header = try!(reader.read_u32::<LittleEndian>());
                let mut body = [0; 1022];
                for idx in 0..1022 {
                    body[idx] = try!(reader.read_u16::<LittleEndian>());
                }
                Ok(TileOrStatic::Tile(Tile {
                    header: header, image_data: body
                }))
            }
        }
    }

    pub fn read_tile(&mut self, id: u32) -> Result<Tile> {
        match self.read(id) {
            Ok(TileOrStatic::Tile(tile)) => Ok(tile),
            Ok(_) => Err(Error::new(
                ErrorKind::Other,
                "Index out of bounds"
            )),
            Err(e) => Err(e)
        }
    }

    pub fn read_static(&mut self, id: u32)-> Result<Static> {
        match self.read(id + STATIC_OFFSET) {
            Ok(TileOrStatic::Static(stat)) => Ok(stat),
            Ok(_) => Err(Error::new(
                ErrorKind::Other,
                "Index out of bounds"
            )),
            Err(e) => Err(e)
        }
    }
}
<commit_msg>Static to Image<commit_after>//! Methods for reading tile and static data out of art.mul
//!
//! Tiles and Statics are both traditionally stored in art.mul/artidx.mul
use std::fs::{File};
use mul_reader::MulReader;
use std::io::{Result, Error, ErrorKind, Cursor, SeekFrom, Seek, Write, Read};
use color::{Color, Color16, Color32};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use utils::{MEMWRITER_ERROR, SURFACE_ERROR};
use std::path::Path;

#[cfg(feature = "use-sdl2")]
use sdl2::surface::Surface;
#[cfg(feature = "use-sdl2")]
use sdl2::pixels::PixelFormatEnum;

use image::{Rgba, RgbaImage};

pub trait Art {
    /**
     * Convert to a 32bit array
     *
     * Returns (width, height, colors)
     */
    fn to_32bit(&self) -> (u32, u32, Vec<Color32>);
    fn serialize(&self) -> Vec<u8>;

    #[cfg(feature = "use-sdl2")]
    fn to_surface(&self) -> Surface;

    fn to_image(&self) -> RgbaImage;
}

pub const TILE_SIZE: u32 = 2048;
pub const STATIC_OFFSET: u32 = 0x4000;

pub struct RunPair {
    pub offset: u16,
    pub run: Vec<Color16>
}

impl RunPair {
    fn serialize(&self) -> Vec<u8> {
        let mut writer = vec![];

        writer.write_u16::<LittleEndian>(self.offset).expect(MEMWRITER_ERROR);
        writer.write_u16::<LittleEndian>(self.run.len() as u16).expect(MEMWRITER_ERROR);
        for &color in self.run.iter() {
            writer.write_u16::<LittleEndian>(color).expect(MEMWRITER_ERROR);
        }
        writer
    }
}

pub type StaticRow = Vec<RunPair>;

/// A Map Tile, 44px by 44px
///
/// Map tiles are stored as
/// |Header:u32|Pixels:u16|
/// Where pixels represents a list of rows, length 2, 4, 6, 8 .. 42, 44, 44, 42 .. 8, 6, 4, 2 and are drawn
/// centred
pub struct Tile {
    /// Header information for a tile.  Unused
    pub header: u32,
    /// Individual pixels. These work as rows, of length 2, 4, 6, 8 .. 42, 44, 44, 42 .. 8, 6, 4, 2
    pub image_data: [Color16; 1022]
}

impl Art for Tile {
    fn to_32bit(&self) -> (u32, u32, Vec<Color32>) {
        let mut image: Vec<Color32> = vec![];

        let mut read_idx = 0;

        for i in 0..44 {

            let slice_size = if i >= 22 {
                (44 - i) * 2
            } else {
                (i + 1) * 2
            };

            image.extend_from_slice(vec![0; (22 - (slice_size / 2))].as_slice());
            for _pixel_idx in 0..slice_size {
                let (r, g, b, a) = self.image_data[read_idx].to_rgba();
                image.push(Color::from_rgba(r, g, b, a));
                read_idx += 1;
            }
            image.extend_from_slice(vec![0; (22 - (slice_size / 2))].as_slice());
        };
        (44, 44, image)
    }

    fn serialize(&self) -> Vec<u8> {
        let mut writer = vec![];
        writer.write_u32::<LittleEndian>(self.header).ok().expect(MEMWRITER_ERROR);
        for &pixel in self.image_data.iter() {
            writer.write_u16::<LittleEndian>(pixel).ok().expect(MEMWRITER_ERROR);
        }
        writer
    }

    fn to_image(&self) -> RgbaImage {
        let mut buffer = RgbaImage::new(44, 44);
        let mut read_idx = 0;

        for y in 0..44 {

            let slice_size = if y >= 22 {
                (44 - y) * 2
            } else {
                (y + 1) * 2
            };

            let indent = 22 - (slice_size / 2);

            for x in 0..slice_size {
                let (r, g, b, a) = self.image_data[read_idx].to_rgba();
                buffer.put_pixel(indent + x, y, Rgba([r, g, b, a]));
                read_idx += 1;
            }
        };
        buffer
    }

    #[cfg(feature = "use-sdl2")]
    fn to_surface(&self) -> Surface {
        let mut surface = Surface::new(44, 44, PixelFormatEnum::RGBA8888).expect(SURFACE_ERROR);
        surface.with_lock_mut(|bitmap| {
            let mut read_idx = 0;

            for y in 0..44 {

                let slice_width = if y >= 22 {
                    (44 - y) * 2
                } else {
                    (y + 1) * 2
                };

                let offset_left = 22 - (slice_width / 2);
                for pixel_idx in 0..slice_width {
                    let x = offset_left + pixel_idx;
                    let (r, g, b, a) = self.image_data[read_idx].to_rgba();
                    let target = ((y * 44) + x) * 4;
                    bitmap[target] = a;
                    bitmap[target + 1] = b;
                    bitmap[target + 2] = g;
                    bitmap[target + 3] = r;
                    read_idx += 1;
                }
            };
        });
        surface
    }
}

impl Art for Static {
    fn to_32bit(&self) -> (u32, u32, Vec<Color32>) {
        let mut image: Vec<Color32> = vec![];

        for row in self.rows.iter() {
            let mut current_width = 0;
            for run_pair in row.iter() {
                image.extend_from_slice(vec![0; run_pair.offset as usize].as_slice());
                for pixel in run_pair.run.iter() {
                    let (r, g, b, a) = pixel.to_rgba();
                    image.push(Color::from_rgba(r, g, b, a));
                }
                current_width += run_pair.offset  + run_pair.run.len() as u16;
                assert!(current_width <= self.width)
            }
            if current_width < self.width {
                image.extend_from_slice(vec![0; (self.width - current_width) as usize].as_slice());
            }
        };

        (self.width as u32, self.height as u32, image)
    }

    fn serialize(&self) -> Vec<u8> {
        let mut writer = vec![];
        writer.write_u16::<LittleEndian>(self.size).ok().expect(MEMWRITER_ERROR);
        writer.write_u16::<LittleEndian>(self.trigger).ok().expect(MEMWRITER_ERROR);
        writer.write_u16::<LittleEndian>(self.width).ok().expect(MEMWRITER_ERROR);
        writer.write_u16::<LittleEndian>(self.height).ok().expect(MEMWRITER_ERROR);

        let mut rows = vec![];

        //Write our rows
        for row in self.rows.iter() {
            let mut out = vec![];
            for pair in row.iter() {
                out.write(pair.serialize().as_slice()).ok().expect(MEMWRITER_ERROR);
            }
            //We write a "newline" after each out
            out.write_u16::<LittleEndian>(0).ok().expect(MEMWRITER_ERROR);
            out.write_u16::<LittleEndian>(0).ok().expect(MEMWRITER_ERROR);
            rows.push(out);
        }

        let mut lookup_table = vec![];
        let mut last_position = 0;
        //Generate a lookup table
        for row in rows.iter() {
            lookup_table.write_u16::<LittleEndian>(last_position).ok().expect(MEMWRITER_ERROR);
            last_position += (row.len() / 2) as u16;
        }
        writer.write(lookup_table.as_slice()).ok().expect(MEMWRITER_ERROR);
        for row in rows.iter() {
            writer.write(row.as_slice()).ok().expect(MEMWRITER_ERROR);
        }

        writer
    }

    fn to_image(&self) -> RgbaImage {
        let mut buffer = RgbaImage::new(self.width as u32, self.height as u32);
        for (y, row) in self.rows.iter().enumerate() {
            let mut x: u32 = 0;
            for run_pair in row.iter() {
                x += run_pair.offset as u32;
                for pixel in run_pair.run.iter() {
                    let (r, g, b, a) = pixel.to_rgba();
                    buffer.put_pixel(x, y as u32, Rgba([r, g, b, a]));
                    x += 1;
                }
            }
        };
        buffer
    }

    #[cfg(feature = "use-sdl2")]
    fn to_surface(&self) -> Surface {
        let mut surface = Surface::new(self.width as u32, self.height as u32, PixelFormatEnum::RGBA8888).expect(SURFACE_ERROR);
        let mut surface_target: usize = 0;

        surface.with_lock_mut(|bitmap| {
            for row in self.rows.iter() {
                let mut current_width = 0;
                for run_pair in row.iter() {
                    surface_target += run_pair.offset as usize * 4;
                    for pixel in run_pair.run.iter() {
                        let (r, g, b, a) = pixel.to_rgba();
                        bitmap[surface_target] = a;
                        bitmap[surface_target + 1] = b;
                        bitmap[surface_target + 2] = g;
                        bitmap[surface_target + 3] = r;
                        surface_target += 4;
                    }
                    current_width += run_pair.offset  + run_pair.run.len() as u16;
                    assert!(current_width <= self.width)
                }
                if current_width < self.width {
                    surface_target += (self.width - current_width) as usize * 4;
                }
            };
        });
        surface
    }
}

pub struct Static {
    pub size: u16,
    pub trigger: u16,
    pub width: u16,
    pub height: u16,
    pub rows: Vec<StaticRow>
}

pub enum TileOrStatic {
    Tile(Tile),
    Static(Static)
}

pub struct ArtReader<T: Read + Seek> {
    mul_reader: MulReader<T>
}

impl ArtReader<File> {

    pub fn new(index_path: &Path, mul_path: &Path) -> Result<ArtReader<File>> {
        let mul_reader = try!(MulReader::new(index_path, mul_path));
        Ok(ArtReader {
            mul_reader: mul_reader
        })
    }
}

impl <T: Read + Seek> ArtReader<T> {

    pub fn from_mul(reader: MulReader<T>) -> ArtReader<T> {
        ArtReader {
            mul_reader: reader
        }
    }

    pub fn read(&mut self, id: u32) -> Result<TileOrStatic> {
        let raw = try!(self.mul_reader.read(id));
        let mut reader = Cursor::new(raw.data);
        if id >= STATIC_OFFSET {
            //It's a static, so deal with accordingly
            let size = try!(reader.read_u16::<LittleEndian>());
            let trigger = try!(reader.read_u16::<LittleEndian>());
            let width = try!(reader.read_u16::<LittleEndian>());
            let height = try!(reader.read_u16::<LittleEndian>());
            if width == 0 || height >= 1024 || height == 0 || height >= 1024 {
                Err(Error::new(ErrorKind::Other, format!("Got invalid width and height of {}, {}", width, height)))
            } else {
                //Load our offset table
                let mut offset_table = vec![];
                for _index in 0..height {
                    offset_table.push(try!(reader.read_u16::<LittleEndian>()));
                }

                let data_start_pos = reader.position();
                let mut rows = vec![];

                for &offset in offset_table.iter() {
                    try!(reader.seek(SeekFrom::Start((data_start_pos + offset as u64 * 2))));
                    let mut row = vec![];

                    loop {
                        let x_offset = try!(reader.read_u16::<LittleEndian>());
                        let run_length = try!(reader.read_u16::<LittleEndian>());
                        if x_offset + run_length == 0 {
                            break
                        } else {
                            let mut run = vec![];
                            for _index in 0..run_length {
                                run.push(try!(reader.read_u16::<LittleEndian>()));
                            }

                            row.push(RunPair {
                                offset: x_offset,
                                run: run
                            });
                        }
                    }
                    rows.push(row);
                }

                Ok(TileOrStatic::Static(Static {
                    size: size,
                    trigger: trigger,
                    width: width,
                    height: height,
                    rows: rows
                }))
            }
        } else {
            //It's a map tile
            if raw.length != TILE_SIZE {
                Err(Error::new(ErrorKind::Other, format!("Got tile size of {}, expected {}", raw.length, TILE_SIZE)))
            } else {
                let header = try!(reader.read_u32::<LittleEndian>());
                let mut body = [0; 1022];
                for idx in 0..1022 {
                    body[idx] = try!(reader.read_u16::<LittleEndian>());
                }
                Ok(TileOrStatic::Tile(Tile {
                    header: header, image_data: body
                }))
            }
        }
    }

    pub fn read_tile(&mut self, id: u32) -> Result<Tile> {
        match self.read(id) {
            Ok(TileOrStatic::Tile(tile)) => Ok(tile),
            Ok(_) => Err(Error::new(
                ErrorKind::Other,
                "Index out of bounds"
            )),
            Err(e) => Err(e)
        }
    }

    pub fn read_static(&mut self, id: u32)-> Result<Static> {
        match self.read(id + STATIC_OFFSET) {
            Ok(TileOrStatic::Static(stat)) => Ok(stat),
            Ok(_) => Err(Error::new(
                ErrorKind::Other,
                "Index out of bounds"
            )),
            Err(e) => Err(e)
        }
    }
}
<|endoftext|>


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

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum BinOp {
    And,
    Ge,
    Gt,
    Eql,
    Le,
    Lt,
    Minus,
    Neq,
    Or,
    Plus,
    Slash,
    Star,
}

#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum Precedence {
    Const = 110,
    Sign = 100,
    Inc = 90,
    Mult = 70,
    Add = 60,
    Equality = 50,
    And = 40,
    Or = 30,
}

impl BinOp {
    pub fn precedence(&self) -> Precedence {
        match *self {
            BinOp::And => Precedence::And,
            BinOp::Ge | BinOp::Gt | BinOp::Eql | BinOp::Le | BinOp::Lt |
            BinOp::Neq => Precedence::Equality,
            BinOp::Or => Precedence::Or,
            BinOp::Minus | BinOp::Plus => Precedence::Add,
            BinOp::Slash | BinOp::Star => Precedence::Mult,
        }
    }

    pub fn is_commutative(&self) -> bool {
        match *self {
            BinOp::Minus | BinOp::Slash => false,
            _ => true
        }
    }
}

impl Display for BinOp {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        match *self {
            BinOp::And => write!(fmt, "&&"),
            BinOp::Ge => write!(fmt, ">="),
            BinOp::Gt => write!(fmt, ">"),
            BinOp::Eql => write!(fmt, "=="),
            BinOp::Le => write!(fmt, "<="),
            BinOp::Lt => write!(fmt, "<"),
            BinOp::Minus => write!(fmt, "-"),
            BinOp::Neq => write!(fmt, "!="),
            BinOp::Or => write!(fmt, "||"),
            BinOp::Plus => write!(fmt, "+"),
            BinOp::Slash => write!(fmt, "/"),
            BinOp::Star => write!(fmt, "*"),
        }
    }
}

#[derive(Clone, Debug)]
pub enum Exp {
    BinExp(Box<Exp>, BinOp, Box<Exp>),
    Bool(bool),
    Call(Box<Exp>, Vec<Box<Exp>>),
    Defun(Option<String>, Vec<String>, Box<Stmt>),
    Float(f64),
    InstanceVar(Box<Exp>, String),
    Neg(Box<Exp>),
    Null,
    NewObject(Box<Exp>, Vec<Box<Exp>>),
    Object(Vec<(String, Box<Exp>)>),
    Pos(Box<Exp>),
    PostDec(Box<Exp>),
    PostInc(Box<Exp>),
    PreDec(Box<Exp>),
    PreInc(Box<Exp>),
    Undefined,
    Var(String),
}

impl Exp {
    pub fn precedence(&self) -> Precedence {
        match *self {
            Exp::BinExp(_, ref o, _) => o.precedence(),
            Exp::Bool(_) | Exp::Call(..) | Exp::Defun(..) | Exp::Float(_) | Exp::InstanceVar(..) |
            Exp::NewObject(..) | Exp::Null | Exp::Object(_) | Exp::Undefined |
            Exp::Var(_) => Precedence::Const,
            Exp::Neg(_) | Exp::Pos(_) => Precedence::Sign,
            Exp::PostDec(_) | Exp::PostInc(_) | Exp::PreDec(_) | Exp::PreInc(_) => Precedence::Inc,
        }
    }
}

macro_rules! group {
    ($e:expr, $p:expr) => {
        if $e.precedence() < $p {
            format!("({})", $e)
        } else {
            format!("{}", $e)
        }
    }
}

impl Exp {
    fn fmt_helper(&self, mut fmt: &mut Formatter, indent_level: i32) -> Result<(), Error> {
        match *self {
            Exp::BinExp(ref e1, ref o, ref e2) => {
                let prec = self.precedence();

                // Put grouping parentheses if the left subexpression has a lower-precedence
                // operator, e.g. (1 + 2) * 3
                let left = if prec > e1.precedence() {
                    format!("({})", e1)
                } else {
                    format!("{}", e1)
                };

                let right_prec = e2.precedence();

                // Put grouping parentheses around the right subexpression if it has a
                // lower-precedence operator,  __OR__ if `o` is not commutative and the precedence
                // is the same, e.g. (1 + 2) * 3 __OR__ 1 - (2 + 3)
                let right = if prec > right_prec || (!o.is_commutative() && prec == right_prec) {
                    format!("({})", e2)
                } else {
                    format!("{}", e2)
                };

                write!(fmt, "{} {} {}", left, o, right)
            }
            Exp::Bool(b) => write!(fmt, "{}", b),
            Exp::Call(ref func, ref args) => {
                try!(write!(fmt, "{}(", func));

                for (i, arg) in args.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", arg));
                }

                write!(fmt, ")")
            }
            Exp::Defun(ref opt, ref params, ref body) => {
                try!(write!(fmt, "function"));

                if let &Some(ref func) = opt {
                    try!(write!(fmt, " {}", func));
                }

                try!(write!(fmt, "("));

                for (i, param) in params.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", param));
                }

                try!(write!(fmt, ") {{\n"));
                try!(body.fmt_helper(&mut fmt, indent_level + 2));

                let indent : String = (0..indent_level).map(|_| " ").collect();

                write!(fmt, "{}}}", indent)
            }
            Exp::Float(f) => write!(fmt, "{}", f),
            Exp::InstanceVar(ref obj, ref name) => write!(fmt, "{}.{}", obj, name),
            Exp::Neg(ref e) => write!(fmt, "-{}", group!(e, Precedence::Sign)),
            Exp::NewObject(ref name, ref args) => {
                try!(write!(fmt, "new {}(", name));

                for (i, arg) in args.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", arg))
                }

                write!(fmt, ")")
            }
            Exp::Null => write!(fmt, "null"),
            Exp::Object(ref properties) => {
                if properties.is_empty() {
                    return write!(fmt, "{{}}");
                }

                try!(writeln!(fmt, "{{"));

                let indent : String = (0..indent_level + 2).map(|_| " ").collect();

                for (i, &(ref name, ref prop)) in properties.iter().enumerate() {
                    if i != 0 {
                        try!(writeln!(fmt, ","));
                    }

                    try!(write!(fmt, "{}{}: ", indent, name));
                    try!(prop.fmt_helper(&mut fmt, indent_level + 2));
                }

                write!(fmt, "\n}}")
            }
            Exp::Pos(ref e) => write!(fmt, "+{}", group!(e, Precedence::Sign)),
            Exp::PostDec(ref e) => write!(fmt, "{}--", group!(e, Precedence::Inc)),
            Exp::PostInc(ref e) => write!(fmt, "{}++", group!(e, Precedence::Inc)),
            Exp::PreDec(ref e) => write!(fmt, "--{}", group!(e, Precedence::Inc)),
            Exp::PreInc(ref e) => write!(fmt, "++{}", group!(e, Precedence::Inc)),
            Exp::Undefined => write!(fmt, "undefined"),
            Exp::Var(ref v) => write!(fmt, "{}", v),
        }
    }
}

impl Display for Exp {
    fn fmt(&self, mut fmt: &mut Formatter) -> Result<(), Error> {
        self.fmt_helper(&mut fmt, 0)
    }
}

#[derive(Clone, Debug)]
pub enum Stmt {
    Assign(String, Exp),
    BareExp(Exp),
    Decl(String, Exp),
    If(Exp, Box<Stmt>, Option<Box<Stmt>>),
    Ret(Exp),
    Seq(Box<Stmt>, Box<Stmt>),
    While(Exp, Box<Stmt>),
}

impl Stmt {
    fn fmt_helper(&self, mut fmt: &mut Formatter, indent_level: i32) -> Result<(), Error> {
        macro_rules! indented_stmt {
            ($stmt:expr) => {
                try!($stmt.fmt_helper(&mut fmt, indent_level + 2))
            }
        }

        macro_rules! exp_semi {
            ($exp:expr) => {{
                try!($exp.fmt_helper(&mut fmt, indent_level));
                writeln!(fmt, ";")
            }}
        }

        let indent : String = (0..indent_level).map(|_| " ").collect();

        match *self {
            Stmt::Assign(ref v, ref exp) => {
                try!(write!(fmt, "{}{} = ", indent, v));
                exp_semi!(exp)
            }
            Stmt::BareExp(ref exp) => {
                try!(write!(fmt, "{}", indent));
                exp_semi!(exp)
            }
            Stmt::Decl(ref v, ref exp) => {
                try!(write!(fmt, "{}var {} = ", indent, v));
                exp_semi!(exp)
            }
            Stmt::If(ref e, ref s, ref els) => {
                try!(write!(fmt, "{}if (", indent));
                try!(e.fmt_helper(&mut fmt, indent_level + 2));
                try!(writeln!(fmt, ") {{\n"));
                indented_stmt!(s);

                if let &Some(ref stmt) = els {
                    try!(write!(fmt, "{}else {{\n", indent));
                    indented_stmt!(stmt);
                    try!(write!(fmt, "{}}}\n", indent));
                }

                Ok(())
            }
            Stmt::Ret(ref e) => {
                try!(write!(fmt, "{}return ", indent));
                exp_semi!(e)
            }
            Stmt::Seq(ref s1, ref s2) => {
                try!(s1.fmt_helper(&mut fmt, indent_level));
                s2.fmt_helper(&mut fmt, indent_level)
            }
            Stmt::While(ref exp, ref stmt) => {
                try!(write!(fmt, "{}while ({}) {{\n", indent, exp));
                try!(stmt.fmt_helper(&mut fmt, indent_level + 2));
                write!(fmt, "{}}}\n", indent)
            }
        }
    }
}

impl Display for Stmt {
    fn fmt(&self, mut fmt: &mut Formatter) -> Result<(), Error> {
        self.fmt_helper(&mut fmt, 0)
    }
}
<commit_msg>add AST nodes for `throw` and `typeof`<commit_after>use std::fmt::{Display, Error, Formatter};

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum BinOp {
    And,
    Ge,
    Gt,
    Eql,
    Le,
    Lt,
    Minus,
    Neq,
    Or,
    Plus,
    Slash,
    Star,
}

#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum Precedence {
    Const = 110,
    Sign = 100,
    Inc = 90,
    Mult = 70,
    Add = 60,
    Equality = 50,
    And = 40,
    Or = 30,
}

impl BinOp {
    pub fn precedence(&self) -> Precedence {
        match *self {
            BinOp::And => Precedence::And,
            BinOp::Ge | BinOp::Gt | BinOp::Eql | BinOp::Le | BinOp::Lt |
            BinOp::Neq => Precedence::Equality,
            BinOp::Or => Precedence::Or,
            BinOp::Minus | BinOp::Plus => Precedence::Add,
            BinOp::Slash | BinOp::Star => Precedence::Mult,
        }
    }

    pub fn is_commutative(&self) -> bool {
        match *self {
            BinOp::Minus | BinOp::Slash => false,
            _ => true
        }
    }
}

impl Display for BinOp {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        match *self {
            BinOp::And => write!(fmt, "&&"),
            BinOp::Ge => write!(fmt, ">="),
            BinOp::Gt => write!(fmt, ">"),
            BinOp::Eql => write!(fmt, "=="),
            BinOp::Le => write!(fmt, "<="),
            BinOp::Lt => write!(fmt, "<"),
            BinOp::Minus => write!(fmt, "-"),
            BinOp::Neq => write!(fmt, "!="),
            BinOp::Or => write!(fmt, "||"),
            BinOp::Plus => write!(fmt, "+"),
            BinOp::Slash => write!(fmt, "/"),
            BinOp::Star => write!(fmt, "*"),
        }
    }
}

#[derive(Clone, Debug)]
pub enum Exp {
    BinExp(Box<Exp>, BinOp, Box<Exp>),
    Bool(bool),
    Call(Box<Exp>, Vec<Box<Exp>>),
    Defun(Option<String>, Vec<String>, Box<Stmt>),
    Float(f64),
    InstanceVar(Box<Exp>, String),
    Neg(Box<Exp>),
    Null,
    NewObject(Box<Exp>, Vec<Box<Exp>>),
    Object(Vec<(String, Box<Exp>)>),
    Pos(Box<Exp>),
    PostDec(Box<Exp>),
    PostInc(Box<Exp>),
    PreDec(Box<Exp>),
    PreInc(Box<Exp>),
    TypeOf(Box<Exp>),
    Undefined,
    Var(String),
}

impl Exp {
    pub fn precedence(&self) -> Precedence {
        match *self {
            Exp::BinExp(_, ref o, _) => o.precedence(),
            Exp::Bool(_) | Exp::Call(..) | Exp::Defun(..) | Exp::Float(_) | Exp::InstanceVar(..) |
            Exp::NewObject(..) | Exp::Null | Exp::Object(_) | Exp::TypeOf(_) | Exp::Undefined |
            Exp::Var(_) => Precedence::Const,
            Exp::Neg(_) | Exp::Pos(_) => Precedence::Sign,
            Exp::PostDec(_) | Exp::PostInc(_) | Exp::PreDec(_) | Exp::PreInc(_) => Precedence::Inc,
        }
    }
}

macro_rules! group {
    ($e:expr, $p:expr) => {
        if $e.precedence() < $p {
            format!("({})", $e)
        } else {
            format!("{}", $e)
        }
    }
}

impl Exp {
    fn fmt_helper(&self, mut fmt: &mut Formatter, indent_level: i32) -> Result<(), Error> {
        match *self {
            Exp::BinExp(ref e1, ref o, ref e2) => {
                let prec = self.precedence();

                // Put grouping parentheses if the left subexpression has a lower-precedence
                // operator, e.g. (1 + 2) * 3
                let left = if prec > e1.precedence() {
                    format!("({})", e1)
                } else {
                    format!("{}", e1)
                };

                let right_prec = e2.precedence();

                // Put grouping parentheses around the right subexpression if it has a
                // lower-precedence operator,  __OR__ if `o` is not commutative and the precedence
                // is the same, e.g. (1 + 2) * 3 __OR__ 1 - (2 + 3)
                let right = if prec > right_prec || (!o.is_commutative() && prec == right_prec) {
                    format!("({})", e2)
                } else {
                    format!("{}", e2)
                };

                write!(fmt, "{} {} {}", left, o, right)
            }
            Exp::Bool(b) => write!(fmt, "{}", b),
            Exp::Call(ref func, ref args) => {
                try!(write!(fmt, "{}(", func));

                for (i, arg) in args.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", arg));
                }

                write!(fmt, ")")
            }
            Exp::Defun(ref opt, ref params, ref body) => {
                try!(write!(fmt, "function"));

                if let &Some(ref func) = opt {
                    try!(write!(fmt, " {}", func));
                }

                try!(write!(fmt, "("));

                for (i, param) in params.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", param));
                }

                try!(write!(fmt, ") {{\n"));
                try!(body.fmt_helper(&mut fmt, indent_level + 2));

                let indent : String = (0..indent_level).map(|_| " ").collect();

                write!(fmt, "{}}}", indent)
            }
            Exp::Float(f) => write!(fmt, "{}", f),
            Exp::InstanceVar(ref obj, ref name) => write!(fmt, "{}.{}", obj, name),
            Exp::Neg(ref e) => write!(fmt, "-{}", group!(e, Precedence::Sign)),
            Exp::NewObject(ref name, ref args) => {
                try!(write!(fmt, "new {}(", name));

                for (i, arg) in args.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", arg))
                }

                write!(fmt, ")")
            }
            Exp::Null => write!(fmt, "null"),
            Exp::Object(ref properties) => {
                if properties.is_empty() {
                    return write!(fmt, "{{}}");
                }

                try!(writeln!(fmt, "{{"));

                let indent : String = (0..indent_level + 2).map(|_| " ").collect();

                for (i, &(ref name, ref prop)) in properties.iter().enumerate() {
                    if i != 0 {
                        try!(writeln!(fmt, ","));
                    }

                    try!(write!(fmt, "{}{}: ", indent, name));
                    try!(prop.fmt_helper(&mut fmt, indent_level + 2));
                }

                write!(fmt, "\n}}")
            }
            Exp::Pos(ref e) => write!(fmt, "+{}", group!(e, Precedence::Sign)),
            Exp::PostDec(ref e) => write!(fmt, "{}--", group!(e, Precedence::Inc)),
            Exp::PostInc(ref e) => write!(fmt, "{}++", group!(e, Precedence::Inc)),
            Exp::PreDec(ref e) => write!(fmt, "--{}", group!(e, Precedence::Inc)),
            Exp::PreInc(ref e) => write!(fmt, "++{}", group!(e, Precedence::Inc)),
            Exp::TypeOf(ref e) => write!(fmt, "typeof {}", e),
            Exp::Undefined => write!(fmt, "undefined"),
            Exp::Var(ref v) => write!(fmt, "{}", v),
        }
    }
}

impl Display for Exp {
    fn fmt(&self, mut fmt: &mut Formatter) -> Result<(), Error> {
        self.fmt_helper(&mut fmt, 0)
    }
}

#[derive(Clone, Debug)]
pub enum Stmt {
    Assign(String, Exp),
    BareExp(Exp),
    Decl(String, Exp),
    If(Exp, Box<Stmt>, Option<Box<Stmt>>),
    Ret(Exp),
    Seq(Box<Stmt>, Box<Stmt>),
    Throw(Box<Exp>),
    While(Exp, Box<Stmt>),
}

impl Stmt {
    fn fmt_helper(&self, mut fmt: &mut Formatter, indent_level: i32) -> Result<(), Error> {
        macro_rules! indented_stmt {
            ($stmt:expr) => {
                try!($stmt.fmt_helper(&mut fmt, indent_level + 2))
            }
        }

        macro_rules! exp_semi {
            ($exp:expr) => {{
                try!($exp.fmt_helper(&mut fmt, indent_level));
                writeln!(fmt, ";")
            }}
        }

        let indent : String = (0..indent_level).map(|_| " ").collect();

        match *self {
            Stmt::Assign(ref v, ref exp) => {
                try!(write!(fmt, "{}{} = ", indent, v));
                exp_semi!(exp)
            }
            Stmt::BareExp(ref exp) => {
                try!(write!(fmt, "{}", indent));
                exp_semi!(exp)
            }
            Stmt::Decl(ref v, ref exp) => {
                try!(write!(fmt, "{}var {} = ", indent, v));
                exp_semi!(exp)
            }
            Stmt::If(ref e, ref s, ref els) => {
                try!(write!(fmt, "{}if (", indent));
                try!(e.fmt_helper(&mut fmt, indent_level + 2));
                try!(writeln!(fmt, ") {{\n"));
                indented_stmt!(s);

                if let &Some(ref stmt) = els {
                    try!(write!(fmt, "{}else {{\n", indent));
                    indented_stmt!(stmt);
                    try!(write!(fmt, "{}}}\n", indent));
                }

                Ok(())
            }
            Stmt::Ret(ref e) => {
                try!(write!(fmt, "{}return ", indent));
                exp_semi!(e)
            }
            Stmt::Seq(ref s1, ref s2) => {
                try!(s1.fmt_helper(&mut fmt, indent_level));
                s2.fmt_helper(&mut fmt, indent_level)
            }
            Stmt::Throw(ref e) => {
                write!(fmt, "{}throw {}", indent, e)
            }
            Stmt::While(ref exp, ref stmt) => {
                try!(write!(fmt, "{}while ({}) {{\n", indent, exp));
                try!(stmt.fmt_helper(&mut fmt, indent_level + 2));
                write!(fmt, "{}}}\n", indent)
            }
        }
    }
}

impl Display for Stmt {
    fn fmt(&self, mut fmt: &mut Formatter) -> Result<(), Error> {
        self.fmt_helper(&mut fmt, 0)
    }
}
<|endoftext|>