<commit_before>#![allow(unused_variables, unused_imports)]
use tdo_core::*;
use tdo_export;
use std::fs::File;
use std::io::{Write, Read, stdin, stdout};
use super::exit;
use super::colored::*;

pub fn print_out(tdo: &super::tdo_core::tdo::Tdo, all: bool) {
    match tdo_export::render_terminal_output(tdo, all) {
        Some(printlines) => {
            for item in printlines.iter() {
                println!("{}", item);
            }
        }
        None => {
            if tdo.get_highest_id() > 0 {
                println!("No undone todos");
            } else {
                println!("No todos yet");
            }
        }
    }
}

pub fn add(tdo: &mut tdo::Tdo, new_todo: &str, in_list: Option<&str>) {
    let todo = todo::Todo::new(tdo.get_highest_id() + 1, new_todo);
    match tdo.add_todo(in_list, todo) {
        Err(e) => errorprint!(e.description()),
        _ => {}
    }
}

pub fn edit(tdo: &mut tdo::Tdo, id: u32) {
    let list = match tdo.find_id(id) {
        Ok(list_id) => list_id,
        Err(e) => {
            errorprint!(e.description());
            exit(1);
        }
    };
    let position = match tdo.lists[list].contains_id(id) {
        Ok(position) => position,
        Err(e) => {
            errorprint!(e.description());
            exit(1);
        }
    };
    println!("Task #{}: {}", id, tdo.lists[list].list[position].name);
    println!("Enter your new task description (leave blank for abort)");
    let mut new_task = String::new();
    stdin().read_line(&mut new_task).unwrap();
    match new_task.trim() {
        "" => {}
        _ => tdo.lists[list].list[position].edit(&new_task.trim()),
    };
}

pub fn done(tdo: &mut tdo::Tdo, id: u32) {
    match tdo.done_id(id) {
        Ok(()) => {}
        Err(e) => errorprint!(e.description()),
    }
}

pub fn newlist(tdo: &mut tdo::Tdo, new_list: &str) {
    match tdo.add_list(list::TodoList::new(new_list)) {
        Ok(()) => {}
        Err(e) => errorprint!(e.description()),
    }
}

pub fn remove(tdo: &mut tdo::Tdo, list_name: &str) {
    println!("remove", );
}

pub fn clean(tdo: &mut tdo::Tdo) {
    tdo.clean_lists();
}

pub fn lists(tdo: &tdo::Tdo) {
    println!("Your todo collection currently encompasses the following lists:\n");

    for list in tdo.lists.iter() {
        let done = list.list
            .iter()
            .fold(0, |acc, &ref item| if item.done { acc + 1 } else { acc });
        let undone: u64 = (list.list.len() - done) as u64;
        println!("    [{undone}|{done}] {name}",
                 undone = undone.to_string().red(),
                 done = (done as u64).to_string().green(),
                 name = &list.name);
    }
}

pub fn export(tdo: &tdo::Tdo, destination: &str, undone: bool) {
    // TODO: check/create path; check for overwrite
    match File::create(destination) {
        Ok(mut file) => {
            file.write(&tdo_export::gen_tasks_md(tdo, true).unwrap().into_bytes())
                .unwrap();
        }
        Err(e) => errorprint!(e),
    }
}

pub fn reset(tdo: &mut tdo::Tdo) -> Option<tdo::Tdo> {
    println!("{}",
             "[WARNING] Are you sure you want to delete all todos and lists? [y/N] ".red());
    let mut answer = String::new();
    stdin().read_line(&mut answer).unwrap();
    let should_delete = match answer.to_lowercase().trim() {
        "y" | "yes" => true,
        "n" | "no" | "" => false,
        _ => {
            errorprint!("No valid answer given. Defaulting to \"no\"");
            false
        }
    };
    if should_delete {
        Some(tdo::Tdo::new())
    } else {
        None
    }
}
<commit_msg>Implemented list removal<commit_after>#![allow(unused_variables, unused_imports)]
use tdo_core::*;
use tdo_export;
use std::fs::File;
use std::io::{Write, Read, stdin, stdout};
use super::exit;
use super::colored::*;

pub fn print_out(tdo: &super::tdo_core::tdo::Tdo, all: bool) {
    match tdo_export::render_terminal_output(tdo, all) {
        Some(printlines) => {
            for item in printlines.iter() {
                println!("{}", item);
            }
        }
        None => {
            if tdo.get_highest_id() > 0 {
                println!("No undone todos");
            } else {
                println!("No todos yet");
            }
        }
    }
}

pub fn add(tdo: &mut tdo::Tdo, new_todo: &str, in_list: Option<&str>) {
    let todo = todo::Todo::new(tdo.get_highest_id() + 1, new_todo);
    match tdo.add_todo(in_list, todo) {
        Err(e) => errorprint!(e.description()),
        _ => {}
    }
}

pub fn edit(tdo: &mut tdo::Tdo, id: u32) {
    let list = match tdo.find_id(id) {
        Ok(list_id) => list_id,
        Err(e) => {
            errorprint!(e.description());
            exit(1);
        }
    };
    let position = match tdo.lists[list].contains_id(id) {
        Ok(position) => position,
        Err(e) => {
            errorprint!(e.description());
            exit(1);
        }
    };
    println!("Task #{}: {}", id, tdo.lists[list].list[position].name);
    println!("Enter your new task description (leave blank for abort)");
    let mut new_task = String::new();
    stdin().read_line(&mut new_task).unwrap();
    match new_task.trim() {
        "" => {}
        _ => tdo.lists[list].list[position].edit(&new_task.trim()),
    };
}

pub fn done(tdo: &mut tdo::Tdo, id: u32) {
    match tdo.done_id(id) {
        Ok(()) => {}
        Err(e) => errorprint!(e.description()),
    }
}

pub fn newlist(tdo: &mut tdo::Tdo, new_list: &str) {
    match tdo.add_list(list::TodoList::new(new_list)) {
        Ok(()) => { println!("Created a new list named '{}'", new_list); }
        Err(e) => errorprint!(e.description()),
    }
}

pub fn remove(tdo: &mut tdo::Tdo, list_name: &str) {
    match tdo.remove_list(list_name) {
        Ok(()) => { println!("Removed the list '{}'", list_name); }
        Err(e) => errorprint!(e),
    }
}

pub fn clean(tdo: &mut tdo::Tdo) {
    tdo.clean_lists();
}

pub fn lists(tdo: &tdo::Tdo) {
    println!("Your todo collection currently encompasses the following lists:\n");

    for list in tdo.lists.iter() {
        let done = list.list
            .iter()
            .fold(0, |acc, &ref item| if item.done { acc + 1 } else { acc });
        let undone: u64 = (list.list.len() - done) as u64;
        println!("    [{undone}|{done}] {name}",
                 undone = undone.to_string().red(),
                 done = (done as u64).to_string().green(),
                 name = &list.name);
    }
}

pub fn export(tdo: &tdo::Tdo, destination: &str, undone: bool) {
    // TODO: check/create path; check for overwrite
    match File::create(destination) {
        Ok(mut file) => {
            file.write(&tdo_export::gen_tasks_md(tdo, true).unwrap().into_bytes())
                .unwrap();
        }
        Err(e) => errorprint!(e),
    }
}

pub fn reset(tdo: &mut tdo::Tdo) -> Option<tdo::Tdo> {
    println!("{}",
             "[WARNING] Are you sure you want to delete all todos and lists? [y/N] ".red());
    let mut answer = String::new();
    stdin().read_line(&mut answer).unwrap();
    let should_delete = match answer.to_lowercase().trim() {
        "y" | "yes" => true,
        "n" | "no" | "" => false,
        _ => {
            errorprint!("No valid answer given. Defaulting to \"no\"");
            false
        }
    };
    if should_delete {
        Some(tdo::Tdo::new())
    } else {
        None
    }
}
<|endoftext|>


<commit_before>
use {Field, Borrowed, Value};
use vecmath::{rotate_radians, multiply, translate, scale, shear};
use {Transform2d, Matrix2d};
use rectangle_context::RectangleContext;

/// Drawing 2d context.
pub struct Context<'a> {
    /// Base/original transformation.
    pub base: Field<'a, Matrix2d>,
    /// Current transformation.
    pub transform: Field<'a, Matrix2d>,
}

impl<'a> Transform2d<'a> for Context<'a> {
    #[inline(always)]
    fn trans(&'a self, x: f64, y: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let trans = translate(x, y);
                 multiply(&trans, self.transform.get())
            }),
        }
    }

    #[inline(always)]
    fn rot_rad(&'a self, angle: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let rot = rotate_radians(angle);
                multiply(&rot, self.transform.get())
            }),
        }
    }

    #[inline(always)]
    fn scale(&'a self, sx: f64, sy: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let scale = scale(sx, sy);
                multiply(&scale, self.transform.get())
            }),
        }
    }

    #[inline(always)]
    fn shear(&'a self, sx: f64, sy: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let shear = shear(sx, sy);
                multiply(&shear, self.transform.get())
            }),
        }
    }
}

impl<'a> Context<'a> {
    /// Creates a new drawing context.
    pub fn new() -> Context {
        Context {
            base:  Value([1.0, 0.0, 0.0,
                          0.0, 1.0, 0.0]),
            transform: Value([1.0, 0.0, 0.0,
                          0.0, 1.0, 0.0]),
        }
    }

    /// Creates a rectangle context.
    pub fn rect(&'a self, x: f64, y: f64, w: f64, h: f64) -> RectangleContext<'a> {
        RectangleContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            rect: Value([x, y, w, h]),
        }
    }
}

#[test]
fn test_context() {
    let c = Context::new();
    {
        let d = c.trans(20.0, 40.0);
        let d = d.trans(10.0, 10.0);
        assert_eq!(d.transform.get()[2], 30.0);
        assert_eq!(d.transform.get()[5], 50.0);
    }
    assert_eq!(c.transform.get()[2], 0.0);
    assert_eq!(c.transform.get()[5], 0.0);

    let c = c.rot_deg(90.0);
    assert!((c.transform.get()[0] - 0.0).abs() < 0.00001);
    assert!((c.transform.get()[1] - 1.0).abs() < 0.00001);
}

#[test]
fn test_scale() {
    let c = Context::new();
    let c = c.scale(2.0, 3.0);
    assert!((c.transform.get()[0] - 2.0).abs() < 0.00001);
    assert!((c.transform.get()[4] - 3.0).abs() < 0.00001);
}
<commit_msg>Added unit test for rect.<commit_after>
use {Field, Borrowed, Value};
use vecmath::{rotate_radians, multiply, translate, scale, shear};
use {Transform2d, Matrix2d};
use rectangle_context::RectangleContext;

/// Drawing 2d context.
pub struct Context<'a> {
    /// Base/original transformation.
    pub base: Field<'a, Matrix2d>,
    /// Current transformation.
    pub transform: Field<'a, Matrix2d>,
}

impl<'a> Transform2d<'a> for Context<'a> {
    #[inline(always)]
    fn trans(&'a self, x: f64, y: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let trans = translate(x, y);
                 multiply(&trans, self.transform.get())
            }),
        }
    }

    #[inline(always)]
    fn rot_rad(&'a self, angle: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let rot = rotate_radians(angle);
                multiply(&rot, self.transform.get())
            }),
        }
    }

    #[inline(always)]
    fn scale(&'a self, sx: f64, sy: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let scale = scale(sx, sy);
                multiply(&scale, self.transform.get())
            }),
        }
    }

    #[inline(always)]
    fn shear(&'a self, sx: f64, sy: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let shear = shear(sx, sy);
                multiply(&shear, self.transform.get())
            }),
        }
    }
}

impl<'a> Context<'a> {
    /// Creates a new drawing context.
    pub fn new() -> Context {
        Context {
            base:  Value([1.0, 0.0, 0.0,
                          0.0, 1.0, 0.0]),
            transform: Value([1.0, 0.0, 0.0,
                          0.0, 1.0, 0.0]),
        }
    }

    /// Creates a rectangle context.
    pub fn rect(&'a self, x: f64, y: f64, w: f64, h: f64) -> RectangleContext<'a> {
        RectangleContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            rect: Value([x, y, w, h]),
        }
    }
}

#[test]
fn test_context() {
    let c = Context::new();
    {
        let d = c.trans(20.0, 40.0);
        let d = d.trans(10.0, 10.0);
        assert_eq!(d.transform.get()[2], 30.0);
        assert_eq!(d.transform.get()[5], 50.0);
    }
    assert_eq!(c.transform.get()[2], 0.0);
    assert_eq!(c.transform.get()[5], 0.0);

    let c = c.rot_deg(90.0);
    assert!((c.transform.get()[0] - 0.0).abs() < 0.00001);
    assert!((c.transform.get()[1] - 1.0).abs() < 0.00001);
}

#[test]
fn test_scale() {
    let c = Context::new();
    let c = c.scale(2.0, 3.0);
    assert!((c.transform.get()[0] - 2.0).abs() < 0.00001);
    assert!((c.transform.get()[4] - 3.0).abs() < 0.00001);
}

#[test]
fn test_rect() {
    let c = Context::new();
    let d = c.rect(0.0, 0.0, 100.0, 50.0);
    assert_eq!(d.rect.get()[2], 100.0);
}
<|endoftext|>


<commit_before>pub struct ExecInfo {
    stub: bool,
}
pub struct DecodeInfo {
    addr_init: u16,
    addr_intermediate: u16,
    addr_final: u16,

    value_init: u8,
    value_intermediate: u8,
    value_final: u8,

    info: ExecInfo,
}

#[allow(non_snake_case)]
pub struct CpuState {
    pc:u16,
    sp: u8,
    a:  u8,
    x:  u8,
    y:  u8,

    // flags
    C: bool, // carry
    Z: bool, // zero
    I: bool, // interrupt
    D: bool, // decimal
    B: bool, // break
             // bit 5 is not used by the nes and is always 1
    V: bool, // overflow
    S: bool, // sign/negative

    // these are not strictly 6502 registers, but are useful for modeling the cpu
    instruction_register: u16,
    decode_register:DecodeInfo,
}

impl CpuState {
  fn unpack_flags(self: &CpuState) -> u8 {
        ( (self.C as u8) << 0)
      | ( (self.Z as u8) << 1)
      | ( (self.I as u8) << 2)
      | ( (self.D as u8) << 3)
      | ( (self.B as u8) << 4)
      | ( (1           ) << 5) // flag 5 is unused
      | ( (self.V as u8) << 6)
      | ( (self.S as u8) << 7)
  }
  fn pack_flags(self: &mut CpuState,flags:u8) {
    self.C        = ( (flags >> 0) & 1) == 1;
    self.Z        = ( (flags >> 1) & 1) == 1;
    self.I        = ( (flags >> 2) & 1) == 1;
    self.D        = ( (flags >> 3) & 1) == 1;
    self.B        = ( (flags >> 4) & 1) == 1;
    // flags 5 is unused
    self.V        = ( (flags >> 6) & 1) == 1;
    self.S        = ( (flags >> 7) & 1) == 1;
  }
}
<commit_msg>added DebugInfo stub<commit_after>pub struct DebugInfo {
    stub: bool,
}
pub struct ExecInfo {
    stub: bool,
}
pub struct DecodeInfo {
    addr_init: u16,
    addr_intermediate: u16,
    addr_final: u16,

    value_init: u8,
    value_intermediate: u8,
    value_final: u8,

    info: ExecInfo,
}

#[allow(non_snake_case)]
pub struct CpuState {
    pc:u16,
    sp: u8,
    a:  u8,
    x:  u8,
    y:  u8,

    // flags
    C: bool, // carry
    Z: bool, // zero
    I: bool, // interrupt
    D: bool, // decimal
    B: bool, // break
             // bit 5 is not used by the nes and is always 1
    V: bool, // overflow
    S: bool, // sign/negative

    // these are not strictly 6502 registers, but are useful for modeling the cpu
    instruction_register: u16,
    decode_register:DecodeInfo,
}

impl CpuState {
  fn unpack_flags(self: &CpuState) -> u8 {
        ( (self.C as u8) << 0)
      | ( (self.Z as u8) << 1)
      | ( (self.I as u8) << 2)
      | ( (self.D as u8) << 3)
      | ( (self.B as u8) << 4)
      | ( (1           ) << 5) // flag 5 is unused
      | ( (self.V as u8) << 6)
      | ( (self.S as u8) << 7)
  }
  fn pack_flags(self: &mut CpuState,flags:u8) {
    self.C        = ( (flags >> 0) & 1) == 1;
    self.Z        = ( (flags >> 1) & 1) == 1;
    self.I        = ( (flags >> 2) & 1) == 1;
    self.D        = ( (flags >> 3) & 1) == 1;
    self.B        = ( (flags >> 4) & 1) == 1;
    // flags 5 is unused
    self.V        = ( (flags >> 6) & 1) == 1;
    self.S        = ( (flags >> 7) & 1) == 1;
  }
}
<|endoftext|>


<commit_before>//! The initializer module parses arguments and verfies commands are valid
//! The creator module handles creating the muxed directory and project files.
#![allow(experimental)]

use std::io::{File,fs};
//use std::io::process::Command;
use std::path::posix::Path;
use std::os::{homedir};
#[cfg(test)] use std::rand::random;
#[cfg(test)] use std::finally::Finally;

static TEMPLATE: &'static str = include_str!("creator/template.yml");
static DEFAULT_MUXED_DIR: &'static str = "muxed";

pub fn new(name: &str) {
    let muxed_dir = if muxed_dir_exists(&DEFAULT_MUXED_DIR.to_string()) {
      Path::new(format!("{}/.{}/", homedir_string(), &DEFAULT_MUXED_DIR.to_string()))
    } else {
      create_muxed_dir(&DEFAULT_MUXED_DIR.to_string())
    };

    let path = &Path::new(format!("{}/{}", muxed_dir.display(), name));
    if !path.exists() {
      create_project_file(path)
    } else {
      println!("Project already exists.");
    }
}

/// Copy and create the new project file from a template. Attempt to open the
/// users default editor to make changes.
fn create_project_file(path: &Path) {
    match File::create(path).write(TEMPLATE.as_bytes()) {
        Ok(()) => (), // succeeded
        Err(_e) => println!("Failed to create project {}", path.filename()),
    }
//    Command::new("vim").arg(format!("{}", path.display())).detached();
}

/// Create the muxed directory and return the path if creation is successful.
fn create_muxed_dir(name: &String) -> Path {
    let path = &Path::new(format!("{}/.{}", homedir_string(), name));
    match fs::mkdir(path, ::std::io::UserRWX) {
        Ok(()) => (), // succeeded
        Err(_e) => println!("Failed to create project {}", path.filename()),
    }

    path.clone()
}

/// Return a boolean if the ~/.muxed/ dir exists.
fn muxed_dir_exists(name: &String) -> bool {
    let path = &Path::new(format!("{}/.{}", homedir_string(), name));
    path.exists()
}

/// Return the users current homedir as a string.
fn homedir_string() -> String {
    let home_unwrap = homedir().unwrap();
    format!("{}", home_unwrap.display())
}

/// Test helper to standardize how random files and directories are generated.
#[cfg(test)]
fn random_name() -> String {
  format!("test_{}", random::<f64>())
}

#[test]
fn muxed_dir_exists_returns_false() {
  assert!(!muxed_dir_exists(&random_name()));
}

#[test]
fn muxed_dir_exists_returns_true() {
  let dir = random_name();
  create_muxed_dir(&dir);
  assert!(muxed_dir_exists(&dir));

  let muxed_path  = &Path::new(format!("{}/.{}/", homedir_string(), dir));
  match fs::rmdir_recursive(muxed_path) {
      Ok(()) => (), // succeeded
      Err(e) => println!("Failed to remove the path {} with error {}", muxed_path.display(), e),
  }
}

#[test]
fn creates_muxed_dir() {
    let dir = random_name();
    let muxed_path  = &Path::new(format!("{}/.{}/", homedir_string(), dir));
    create_muxed_dir(&dir);
    assert!(muxed_path.exists());
    match fs::rmdir_recursive(muxed_path) {
        Ok(()) => (), // succeeded
        Err(e) => println!("Failed to remove the path {} with error {}", muxed_path.display(), e),
    }
}

#[test]
fn new_writes_file_to_muxed_dir() {
    let name = random_name();
    let path = &Path::new(format!("{}/.muxed/{}", homedir_string(), name));
    new(name.as_slice());
    assert!(path.exists());
    match fs::unlink(path) {
        Ok(()) => (), // succeeded
        Err(e) => println!("Failed to unlink the path {} with error {}", path.display(), e),
    }
}

#[test]
// TODO: Fix this test so it verifies something better.
fn new_doesnt_overwrite_existing_file() {
    let name = random_name();
    let path = &Path::new(format!("{}/.muxed/{}", homedir_string(), name));
    new(name.as_slice());
    (|| {
        new(name.as_slice());
    }).finally(|| {
        match fs::unlink(path) {
            Ok(()) => (), // succeeded
            Err(e) => println!("Failed to unlink the path {} with error {}", path.display(), e),
        }
    })
}
<commit_msg>More spacing.<commit_after>//! The initializer module parses arguments and verfies commands are valid
//! The creator module handles creating the muxed directory and project files.
#![allow(experimental)]

use std::io::{File,fs};
//use std::io::process::Command;
use std::path::posix::Path;
use std::os::{homedir};
#[cfg(test)] use std::rand::random;
#[cfg(test)] use std::finally::Finally;

static TEMPLATE: &'static str = include_str!("creator/template.yml");
static DEFAULT_MUXED_DIR: &'static str = "muxed";

pub fn new(name: &str) {
    let muxed_dir = if muxed_dir_exists(&DEFAULT_MUXED_DIR.to_string()) {
        Path::new(format!("{}/.{}/", homedir_string(), &DEFAULT_MUXED_DIR.to_string()))
    } else {
        create_muxed_dir(&DEFAULT_MUXED_DIR.to_string())
    };

    let path = &Path::new(format!("{}/{}", muxed_dir.display(), name));
    if !path.exists() {
        create_project_file(path)
    } else {
        println!("Project already exists.");
    }
}

/// Copy and create the new project file from a template. Attempt to open the
/// users default editor to make changes.
fn create_project_file(path: &Path) {
    match File::create(path).write(TEMPLATE.as_bytes()) {
        Ok(()) => (), // succeeded
        Err(_e) => println!("Failed to create project {}", path.filename()),
    }
    //Command::new("vim").arg(format!("{}", path.display())).detached();
}

/// Create the muxed directory and return the path if creation is successful.
fn create_muxed_dir(name: &String) -> Path {
    let path = &Path::new(format!("{}/.{}", homedir_string(), name));
    match fs::mkdir(path, ::std::io::UserRWX) {
        Ok(()) => (), // succeeded
        Err(_e) => println!("Failed to create project {}", path.filename()),
    }

    path.clone()
}

/// Return a boolean if the ~/.muxed/ dir exists.
fn muxed_dir_exists(name: &String) -> bool {
    let path = &Path::new(format!("{}/.{}", homedir_string(), name));
    path.exists()
}

/// Return the users current homedir as a string.
fn homedir_string() -> String {
    let home_unwrap = homedir().unwrap();
    format!("{}", home_unwrap.display())
}

/// Test helper to standardize how random files and directories are generated.
#[cfg(test)]
fn random_name() -> String {
    format!("test_{}", random::<f64>())
}

#[test]
fn muxed_dir_exists_returns_false() {
    assert!(!muxed_dir_exists(&random_name()));
}

#[test]
fn muxed_dir_exists_returns_true() {
    let dir = random_name();
    create_muxed_dir(&dir);
    assert!(muxed_dir_exists(&dir));

    let muxed_path  = &Path::new(format!("{}/.{}/", homedir_string(), dir));
    match fs::rmdir_recursive(muxed_path) {
        Ok(()) => (), // succeeded
        Err(e) => println!("Failed to remove the path {} with error {}", muxed_path.display(), e),
    }
}

#[test]
fn creates_muxed_dir() {
    let dir = random_name();
    let muxed_path  = &Path::new(format!("{}/.{}/", homedir_string(), dir));
    create_muxed_dir(&dir);
    assert!(muxed_path.exists());
    match fs::rmdir_recursive(muxed_path) {
        Ok(()) => (), // succeeded
        Err(e) => println!("Failed to remove the path {} with error {}", muxed_path.display(), e),
    }
}

#[test]
fn new_writes_file_to_muxed_dir() {
    let name = random_name();
    let path = &Path::new(format!("{}/.muxed/{}", homedir_string(), name));
    new(name.as_slice());
    assert!(path.exists());
    match fs::unlink(path) {
        Ok(()) => (), // succeeded
        Err(e) => println!("Failed to unlink the path {} with error {}", path.display(), e),
    }
}

#[test]
// TODO: Fix this test so it verifies something better.
fn new_doesnt_overwrite_existing_file() {
    let name = random_name();
    let path = &Path::new(format!("{}/.muxed/{}", homedir_string(), name));
    new(name.as_slice());
    (|| {
        new(name.as_slice());
    }).finally(|| {
        match fs::unlink(path) {
            Ok(()) => (), // succeeded
            Err(e) => println!("Failed to unlink the path {} with error {}", path.display(), e),
        }
    })
}
<|endoftext|>


<commit_before>use av_format::error::*;
use std::io::SeekFrom;
use av_data::packet::Packet;
use av_data::timeinfo::TimeInfo;
use av_data::params::*;
use av_format::stream::Stream;
use av_format::buffer::Buffered;
use av_format::demuxer::{Demuxer, Event};
use av_format::demuxer::{Descr, Descriptor};
use av_format::common::GlobalInfo;
use std::collections::VecDeque;
use rational::Rational64;

use ebml::{ebml_header, EBMLHeader};
use elements::{segment, segment_element, Cluster, SeekHead, Info, Tracks, TrackEntry,
               SegmentElement, simple_block};
use nom::{self, Err, IResult, Offset};

#[derive(Debug, Clone, PartialEq)]
pub struct MkvDemuxer {
    pub header: Option<EBMLHeader>,
    pub seek_head: Option<SeekHead>,
    pub info: Option<Info>,
    pub tracks: Option<Tracks>,
    pub queue: VecDeque<Event>,
    pub blockstream: Vec<u8>,
}

impl MkvDemuxer {
    pub fn new() -> MkvDemuxer {
        MkvDemuxer {
            header: None,
            seek_head: None,
            info: None,
            tracks: None,
            queue: VecDeque::new(),
            blockstream: Vec::new(),
        }
    }

    pub fn parse_until_tracks<'a>(&mut self, original_input: &'a [u8]) -> IResult<&'a [u8], ()> {
        let (i1, header) = try_parse!(original_input, ebml_header);

        self.header = Some(header);

        let (mut input, _) = try_parse!(i1, segment);

        self.seek_head = None;
        self.info = None;
        self.tracks = None;

        loop {
            if self.seek_head.is_some() && self.info.is_some() && self.tracks.is_some() {
                return Ok((input, ()));
            }

            // println!("offset: {}", original_input.offset(input));

            let (i3, element) = try_parse!(input, segment_element);

            match element {
                SegmentElement::SeekHead(s) => {
                    // println!("got seek head: {:#?}", s);
                    if self.seek_head.is_some() {
                        return Err(Err::Error(error_position!(input, nom::ErrorKind::Custom(1))));
                    } else {
                        self.seek_head = Some(s);
                    }
                }
                SegmentElement::Info(i) => {
                    // println!("got info: {:#?}", i);
                    if self.info.is_some() {
                        return Err(Err::Error(error_position!(input, nom::ErrorKind::Custom(1))));
                    } else {
                        self.info = Some(i);
                    }
                }
                SegmentElement::Tracks(t) => {
                    // println!("got tracks: {:#?}", t);
                    if self.tracks.is_some() {
                        return Err(Err::Error(error_position!(input, nom::ErrorKind::Custom(1))));
                    } else {
                        self.tracks = Some(t);
                    }
                }
                el => {
                    println!("got element: {:#?}", el);
                }
            }

            input = i3;
        }
    }
}

use nom::Needed;

impl Demuxer for MkvDemuxer {
    fn read_headers(&mut self, buf: &Box<Buffered>, info: &mut GlobalInfo) -> Result<SeekFrom> {
        match self.parse_until_tracks(buf.data()) {
            Ok((i, _)) => {
                info.duration = self.info.as_ref().and_then(|info| info.duration).map(|d| d as u64);
                if let Some(ref t) = self.tracks {
                    info.streams = t.tracks.iter().map(|tr| {
                        track_to_stream(self.info.as_ref().unwrap(), tr)
                    }).collect();
                }
                Ok(SeekFrom::Current(buf.data().offset(i) as i64))
            },
            Err(Err::Incomplete(needed)) => {
                let sz = match needed {
                    Needed::Size(size) => buf.data().len() + size,
                    _ => 1024,
                };
                Err(Error::MoreDataNeeded(sz))
            },
            e => {
                println!("error reading headers: {:?}", e);
                Err(Error::InvalidData)
            }
        }
    }

    fn read_event(&mut self, buf: &Box<Buffered>) -> Result<(SeekFrom, Event)> {
        if let Some(event) = self.queue.pop_front() {
            Ok((SeekFrom::Current(0), event))
        } else {
            // println!("no more stored packet, parsing a new one");
            match segment_element(buf.data()) {
                Ok((i, element)) => {
                    let seek = SeekFrom::Current(buf.data().offset(i) as i64);
                    match element {
                        SegmentElement::Cluster(c) => {
                            //self.clusters.push(c);
                            // println!("got cluster element at timecode: {}", c.timecode);
                            let mut packets = c.generate_packets();
                            self.queue.extend(packets.drain(..));
                            if let Some(event) = self.queue.pop_front() {
                                return Ok((seek, event));
                            }
                        }
                        _el => {
                            // println!("got element: {:#?}", el);
                        }
                    }
                    Ok((seek, Event::MoreDataNeeded(0)))
                },
                Err(Err::Incomplete(Needed::Size(size))) => {
                    Err(Error::MoreDataNeeded(size))
                },
                e => {
                    println!("parsing issue: {:?}", e);
                    Err(Error::InvalidData)
                }
            }
        }
    }
}

fn track_entry_codec_id(t: &TrackEntry) -> Option<String> {
    // TODO: Support V_QUICKTIME and V_MS/VFW/FOURCC
    match t.codec_id.as_ref() {
        "A_OPUS"   => Some("opus".to_owned()),
        "A_VORBIS" => Some("vorbis".to_owned()),
        "V_AV1"    => Some("av1".to_owned()),
        "V_VP8"    => Some("vp8".to_owned()),
        "V_VP9"    => Some("vp9".to_owned()),
        _ => None,
    }
}

fn track_entry_video_kind(t: &TrackEntry) -> Option<MediaKind> {
    // TODO: Validate that a track::video exists for track::type video before.
    if let Some(ref video) = t.video {
        let v = VideoInfo {
            width: video.pixel_width as usize,
            height: video.pixel_height as usize,
            // TODO parse Colour and/or CodecPrivate to extract the format
            format: None,
        };
        Some(MediaKind::Video(v))
    } else {
        None
    }
}

fn track_entry_audio_kind(t: &TrackEntry) -> Option<MediaKind> {
    // TODO: Validate that a track::video exists for track::type video before.
    if let Some(ref audio) = t.audio {
        let rate = if let Some(r) = audio.output_sampling_frequency {
            r
        } else {
            audio.sampling_frequency
        };
        // TODO: complete it
        let a = AudioInfo {
            rate: rate as usize,
            map: None,
            format: None,
        };
        Some(MediaKind::Audio(a))
    } else {
        None
    }
}

fn track_entry_media_kind(t: &TrackEntry) -> Option<MediaKind> {
    // TODO: Use an enum for the track type
    match t.track_type {
        0x1 => track_entry_video_kind(t),
        0x2 => track_entry_audio_kind(t),
        _ => None,
    }
}

// TODO: make sure the timecode_scale isn't 0
pub fn track_to_stream(info: &Info, t: &TrackEntry) -> Stream {
    let num = if let Some(ts) = t.track_timecode_scale  {
        (ts * info.timecode_scale as f64) as i64
    } else {
        info.timecode_scale as i64
    };

    Stream {
        id: t.track_uid as usize,
        index: t.track_number as usize,
        start: None,
        duration: t.default_duration,
        timebase: Rational64::new(num, 1000 * 1000 * 1000),
        // TODO: Extend CodecParams and fill it with the remaining information
        params: CodecParams {
            extradata: t.codec_private.clone(),
            bit_rate: 0,
            delay: t.codec_delay.unwrap_or(0) as usize,
            convergence_window: t.seek_pre_roll.unwrap_or(0) as usize,
            codec_id: track_entry_codec_id(t),
            kind: track_entry_media_kind(t),
        },
    }
}

impl<'a> Cluster<'a> {
    pub fn generate_packets(&self) -> Vec<Event> {
        let mut v = Vec::new();

        for block_data in self.simple_block.iter() {
            if let Ok((i, block)) = simple_block(block_data) {
                //println!("parsing simple block: {:?}", block);
                let packet = Packet {
                    data: i.into(),
                    t: TimeInfo {
                        pts: Some(block.timecode as i64),
                        dts: None,
                        duration: None,
                        timebase: None,
                    },
                    pos: None,
                    stream_index: block.track_number as isize,
                    is_key: block.keyframe,
                    is_corrupted: false,
                };

                v.push(Event::NewPacket(packet));
            } else {
                println!("error parsing simple block");
            }
        }

        v
    }
}

struct Des {
    d: Descr,
}

impl Descriptor for Des {
    fn create(&self) -> Box<Demuxer> {
        Box::new(MkvDemuxer::new())
    }
    fn describe<'a>(&'a self) -> &'a Descr {
        &self.d
    }
    fn probe(&self, data: &[u8]) -> u8 {
        match ebml_header(&data[..100]) {
            Ok(_) => 100,
            _ => 0,
        }
    }
}

pub const MKV_DESC: &Descriptor = &Des {
    d: Descr {
        name: "matroska",
        demuxer: "mkv",
        description: "Nom-based Matroska demuxer",
        extensions: &["mkv", "webm", "mka"],
        mime: &["video/x-matroska", "audio/x-matroska"],
    }
};

#[cfg(test)]
#[allow(non_upper_case_globals)]
mod tests {
    use super::*;
    use std::io::Cursor;
    use nom::Offset;
    use av_format::demuxer::Context;
    use av_format::buffer::*;

    const webm: &'static [u8] = include_bytes!("../assets/bbb-vp9-opus.webm");

    #[test]
    fn parse_headers() {
        let mut demuxer = MkvDemuxer::new();

        let res = demuxer.parse_until_tracks(webm);
        println!("got parsing res: {:?}", res);
        match res {
            Ok((i, _)) => {
                println!("offset: {} bytes", webm.offset(i));
            }
            e => {
                println!("could not parse: {:?}", e);
            }
        }

        println!("demuxer: {:#?}", demuxer);
    }

    #[test]
    fn parse_headers_incremental_buffer() {
        let mut demuxer = MkvDemuxer::new();

        for n in 100..2000 {
            let res = demuxer.parse_until_tracks(&webm[0..n]);
            match res {
                Ok(_) => println!("Size {} ok", n),
                Err(Err::Incomplete(needed)) => println!("Incomplete {} needs {:?}", n, needed),
                Err(e) => {
                    panic!("Error at size {}: {:?}", n, e);
                }
            }
        }
    }

    #[test]
    fn context() {
        let mut context = Context::new(Box::new(MkvDemuxer::new()),
                                       Box::new(AccReader::new(Cursor::new(webm))));
        println!("DEMUXER CONTEXT read headers: {:?}", context.read_headers().unwrap());
        println!("DEMUXER CONTEXT streams: {:?}", context.info.streams);
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
    }
}
<commit_msg>Update to the current API<commit_after>use av_format::error::*;
use std::io::SeekFrom;
use av_data::packet::Packet;
use av_data::timeinfo::TimeInfo;
use av_data::params::*;
use av_format::stream::Stream;
use av_format::buffer::Buffered;
use av_format::demuxer::{Demuxer, Event};
use av_format::demuxer::{Descr, Descriptor};
use av_format::common::GlobalInfo;
use std::collections::VecDeque;
use rational::Rational64;

use ebml::{ebml_header, EBMLHeader};
use elements::{segment, segment_element, Cluster, SeekHead, Info, Tracks, TrackEntry,
               SegmentElement, simple_block};
use nom::{self, Err, IResult, Offset};

#[derive(Debug, Clone, PartialEq)]
pub struct MkvDemuxer {
    pub header: Option<EBMLHeader>,
    pub seek_head: Option<SeekHead>,
    pub info: Option<Info>,
    pub tracks: Option<Tracks>,
    pub queue: VecDeque<Event>,
    pub blockstream: Vec<u8>,
}

impl MkvDemuxer {
    pub fn new() -> MkvDemuxer {
        MkvDemuxer {
            header: None,
            seek_head: None,
            info: None,
            tracks: None,
            queue: VecDeque::new(),
            blockstream: Vec::new(),
        }
    }

    pub fn parse_until_tracks<'a>(&mut self, original_input: &'a [u8]) -> IResult<&'a [u8], ()> {
        let (i1, header) = try_parse!(original_input, ebml_header);

        self.header = Some(header);

        let (mut input, _) = try_parse!(i1, segment);

        self.seek_head = None;
        self.info = None;
        self.tracks = None;

        loop {
            if self.seek_head.is_some() && self.info.is_some() && self.tracks.is_some() {
                return Ok((input, ()));
            }

            // println!("offset: {}", original_input.offset(input));

            let (i3, element) = try_parse!(input, segment_element);

            match element {
                SegmentElement::SeekHead(s) => {
                    // println!("got seek head: {:#?}", s);
                    if self.seek_head.is_some() {
                        return Err(Err::Error(error_position!(input, nom::ErrorKind::Custom(1))));
                    } else {
                        self.seek_head = Some(s);
                    }
                }
                SegmentElement::Info(i) => {
                    // println!("got info: {:#?}", i);
                    if self.info.is_some() {
                        return Err(Err::Error(error_position!(input, nom::ErrorKind::Custom(1))));
                    } else {
                        self.info = Some(i);
                    }
                }
                SegmentElement::Tracks(t) => {
                    // println!("got tracks: {:#?}", t);
                    if self.tracks.is_some() {
                        return Err(Err::Error(error_position!(input, nom::ErrorKind::Custom(1))));
                    } else {
                        self.tracks = Some(t);
                    }
                }
                el => {
                    println!("got element: {:#?}", el);
                }
            }

            input = i3;
        }
    }
}

use nom::Needed;

impl Demuxer for MkvDemuxer {
    fn read_headers(&mut self, buf: &Box<Buffered>, info: &mut GlobalInfo) -> Result<SeekFrom> {
        match self.parse_until_tracks(buf.data()) {
            Ok((i, _)) => {
                info.duration = self.info.as_ref().and_then(|info| info.duration).map(|d| d as u64);
                if let Some(ref t) = self.tracks {
                    info.streams = t.tracks.iter().map(|tr| {
                        track_to_stream(self.info.as_ref().unwrap(), tr)
                    }).collect();
                }
                Ok(SeekFrom::Current(buf.data().offset(i) as i64))
            },
            Err(Err::Incomplete(needed)) => {
                let sz = match needed {
                    Needed::Size(size) => buf.data().len() + size,
                    _ => 1024,
                };
                Err(Error::MoreDataNeeded(sz))
            },
            e => {
                println!("error reading headers: {:?}", e);
                Err(Error::InvalidData)
            }
        }
    }

    fn read_event(&mut self, buf: &Box<Buffered>) -> Result<(SeekFrom, Event)> {
        if let Some(event) = self.queue.pop_front() {
            Ok((SeekFrom::Current(0), event))
        } else {
            // println!("no more stored packet, parsing a new one");
            match segment_element(buf.data()) {
                Ok((i, element)) => {
                    let seek = SeekFrom::Current(buf.data().offset(i) as i64);
                    match element {
                        SegmentElement::Cluster(c) => {
                            //self.clusters.push(c);
                            // println!("got cluster element at timecode: {}", c.timecode);
                            let mut packets = c.generate_packets();
                            self.queue.extend(packets.drain(..));
                            if let Some(event) = self.queue.pop_front() {
                                return Ok((seek, event));
                            }
                        }
                        _el => {
                            // println!("got element: {:#?}", el);
                        }
                    }
                    Ok((seek, Event::MoreDataNeeded(0)))
                },
                Err(Err::Incomplete(Needed::Size(size))) => {
                    Err(Error::MoreDataNeeded(size))
                },
                e => {
                    println!("parsing issue: {:?}", e);
                    Err(Error::InvalidData)
                }
            }
        }
    }
}

fn track_entry_codec_id(t: &TrackEntry) -> Option<String> {
    // TODO: Support V_QUICKTIME and V_MS/VFW/FOURCC
    match t.codec_id.as_ref() {
        "A_OPUS"   => Some("opus".to_owned()),
        "A_VORBIS" => Some("vorbis".to_owned()),
        "V_AV1"    => Some("av1".to_owned()),
        "V_VP8"    => Some("vp8".to_owned()),
        "V_VP9"    => Some("vp9".to_owned()),
        _ => None,
    }
}

fn track_entry_video_kind(t: &TrackEntry) -> Option<MediaKind> {
    // TODO: Validate that a track::video exists for track::type video before.
    if let Some(ref video) = t.video {
        let v = VideoInfo {
            width: video.pixel_width as usize,
            height: video.pixel_height as usize,
            // TODO parse Colour and/or CodecPrivate to extract the format
            format: None,
        };
        Some(MediaKind::Video(v))
    } else {
        None
    }
}

fn track_entry_audio_kind(t: &TrackEntry) -> Option<MediaKind> {
    // TODO: Validate that a track::video exists for track::type video before.
    if let Some(ref audio) = t.audio {
        let rate = if let Some(r) = audio.output_sampling_frequency {
            r
        } else {
            audio.sampling_frequency
        };
        // TODO: complete it
        let a = AudioInfo {
            rate: rate as usize,
            map: None,
            format: None,
        };
        Some(MediaKind::Audio(a))
    } else {
        None
    }
}

fn track_entry_media_kind(t: &TrackEntry) -> Option<MediaKind> {
    // TODO: Use an enum for the track type
    match t.track_type {
        0x1 => track_entry_video_kind(t),
        0x2 => track_entry_audio_kind(t),
        _ => None,
    }
}

// TODO: make sure the timecode_scale isn't 0
pub fn track_to_stream(info: &Info, t: &TrackEntry) -> Stream {
    let num = if let Some(ts) = t.track_timecode_scale  {
        (ts * info.timecode_scale as f64) as i64
    } else {
        info.timecode_scale as i64
    };

    Stream {
        id: t.track_uid as isize,
        index: t.track_number as usize,
        start: None,
        duration: t.default_duration,
        timebase: Rational64::new(num, 1000 * 1000 * 1000),
        // TODO: Extend CodecParams and fill it with the remaining information
        params: CodecParams {
            extradata: t.codec_private.clone(),
            bit_rate: 0,
            delay: t.codec_delay.unwrap_or(0) as usize,
            convergence_window: t.seek_pre_roll.unwrap_or(0) as usize,
            codec_id: track_entry_codec_id(t),
            kind: track_entry_media_kind(t),
        },
    }
}

impl<'a> Cluster<'a> {
    pub fn generate_packets(&self) -> Vec<Event> {
        let mut v = Vec::new();

        for block_data in self.simple_block.iter() {
            if let Ok((i, block)) = simple_block(block_data) {
                //println!("parsing simple block: {:?}", block);
                let packet = Packet {
                    data: i.into(),
                    t: TimeInfo {
                        pts: Some(block.timecode as i64),
                        dts: None,
                        duration: None,
                        timebase: None,
                    },
                    pos: None,
                    stream_index: block.track_number as isize,
                    is_key: block.keyframe,
                    is_corrupted: false,
                };

                v.push(Event::NewPacket(packet));
            } else {
                println!("error parsing simple block");
            }
        }

        v
    }
}

struct Des {
    d: Descr,
}

impl Descriptor for Des {
    fn create(&self) -> Box<Demuxer> {
        Box::new(MkvDemuxer::new())
    }
    fn describe<'a>(&'a self) -> &'a Descr {
        &self.d
    }
    fn probe(&self, data: &[u8]) -> u8 {
        match ebml_header(&data[..100]) {
            Ok(_) => 100,
            _ => 0,
        }
    }
}

pub const MKV_DESC: &Descriptor = &Des {
    d: Descr {
        name: "matroska",
        demuxer: "mkv",
        description: "Nom-based Matroska demuxer",
        extensions: &["mkv", "webm", "mka"],
        mime: &["video/x-matroska", "audio/x-matroska"],
    }
};

#[cfg(test)]
#[allow(non_upper_case_globals)]
mod tests {
    use super::*;
    use std::io::Cursor;
    use nom::Offset;
    use av_format::demuxer::Context;
    use av_format::buffer::*;

    const webm: &'static [u8] = include_bytes!("../assets/bbb-vp9-opus.webm");

    #[test]
    fn parse_headers() {
        let mut demuxer = MkvDemuxer::new();

        let res = demuxer.parse_until_tracks(webm);
        println!("got parsing res: {:?}", res);
        match res {
            Ok((i, _)) => {
                println!("offset: {} bytes", webm.offset(i));
            }
            e => {
                println!("could not parse: {:?}", e);
            }
        }

        println!("demuxer: {:#?}", demuxer);
    }

    #[test]
    fn parse_headers_incremental_buffer() {
        let mut demuxer = MkvDemuxer::new();

        for n in 100..2000 {
            let res = demuxer.parse_until_tracks(&webm[0..n]);
            match res {
                Ok(_) => println!("Size {} ok", n),
                Err(Err::Incomplete(needed)) => println!("Incomplete {} needs {:?}", n, needed),
                Err(e) => {
                    panic!("Error at size {}: {:?}", n, e);
                }
            }
        }
    }

    #[test]
    fn context() {
        let mut context = Context::new(Box::new(MkvDemuxer::new()),
                                       Box::new(AccReader::new(Cursor::new(webm))));
        println!("DEMUXER CONTEXT read headers: {:?}", context.read_headers().unwrap());
        println!("DEMUXER CONTEXT streams: {:?}", context.info.streams);
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
    }
}
<|endoftext|>


<commit_before>use crate::audio::SoundSource;
use crate::tests;
use crate::*;

#[test]
fn audio_load_ogg() {
    let (c, _e) = &mut tests::make_context();

    // OGG format
    let _sound = audio::Source::new(c, "/pew.ogg").unwrap();
}

#[test]
fn audio_load_mp3() {
    let (c, _e) = &mut tests::make_context();

    // LAME encoded MP3 format
    let _sound = audio::Source::new(c, "/pew.mp3").unwrap();
}

#[test]
fn audio_load_wav() {
    let (c, _e) = &mut tests::make_context();

    // WAV format
    let _sound = audio::Source::new(c, "/pew.wav").unwrap();
}

#[test]
fn audio_load_flac() {
    let (c, _e) = &mut tests::make_context();

    // FLAC format
    let _sound = audio::Source::new(c, "/pew.flac").unwrap();
}

#[test]
fn fail_when_loading_nonexistent_file() {
    let (c, _e) = &mut tests::make_context();

    // File does not exist
    assert!(audio::Source::new(c, "/does-not-exists.ogg").is_err());
}

#[test]
fn fail_when_loading_non_audio_file() {
    let (c, _e) = &mut tests::make_context();

    assert!(audio::Source::new(c, "/player.png").is_err());
}

#[test]
fn volume_persists_after_stop() {
    let (c, _e) = &mut tests::make_context();
    {
        let volume = 0.8;
        let mut sound = audio::Source::new(c, "/pew.ogg").unwrap();
        sound.set_volume(volume);
        assert_eq!(sound.volume(), volume);
        sound.stop();
        assert_eq!(sound.volume(), volume);
    }
}

#[test]
fn volume_persists_after_stop_for_spatial_source() {
    let (c, _e) = &mut tests::make_context();
    {
        let volume = 0.8;
        let mut sound = audio::Source::new(c, "/pew.ogg").unwrap();
        sound.set_volume(volume);
        assert_eq!(sound.volume(), volume);
        sound.stop();
        assert_eq!(sound.volume(), volume);
    }
}

#[test]
fn volume_persists_after_play() {
    let (c, _e) = &mut tests::make_context();
    {
        let volume = 0.8;
        let mut sound = audio::Source::new(c, "/pew.ogg").unwrap();
        sound.set_volume(volume);
        assert_eq!(sound.volume(), volume);
        sound.play().unwrap();
        assert_eq!(sound.volume(), volume);
    }
}

#[test]
fn volume_persists_after_play_for_spatial_source() {
    let (c, _e) = &mut tests::make_context();
    {
        let volume = 0.8;
        let mut sound = audio::Source::new(c, "/pew.ogg").unwrap();
        sound.set_volume(volume);
        assert_eq!(sound.volume(), volume);
        sound.play().unwrap();
        assert_eq!(sound.volume(), volume);
    }
}
<commit_msg>All audio tests check both Source and SpatialSource<commit_after>use crate::audio::SoundSource;
use crate::tests;
use crate::*;

#[test]
fn audio_load_ogg() {
    let (c, _e) = &mut tests::make_context();

    // OGG format
    let _sound = audio::Source::new(c, "/pew.ogg").unwrap();
    let _sound = audio::SpatialSource::new(c, "/pew.ogg").unwrap();
}

#[test]
fn audio_load_mp3() {
    let (c, _e) = &mut tests::make_context();

    // LAME encoded MP3 format
    let _sound = audio::Source::new(c, "/pew.mp3").unwrap();
    let _sound = audio::SpatialSource::new(c, "/pew.mp3").unwrap();
}

#[test]
fn audio_load_wav() {
    let (c, _e) = &mut tests::make_context();

    // WAV format
    let _sound = audio::Source::new(c, "/pew.wav").unwrap();
    let _sound = audio::SpatialSource::new(c, "/pew.wav").unwrap();
}

#[test]
fn audio_load_flac() {
    let (c, _e) = &mut tests::make_context();

    // FLAC format
    let _sound = audio::Source::new(c, "/pew.flac").unwrap();
    let _sound = audio::SpatialSource::new(c, "/pew.flac").unwrap();
}

#[test]
fn fail_when_loading_nonexistent_file() {
    let (c, _e) = &mut tests::make_context();

    // File does not exist
    assert!(audio::Source::new(c, "/does-not-exists.ogg").is_err());
    assert!(audio::SpatialSource::new(c, "/does-not-exists.ogg").is_err());
}

#[test]
fn fail_when_loading_non_audio_file() {
    let (c, _e) = &mut tests::make_context();

    assert!(audio::Source::new(c, "/player.png").is_err());
    assert!(audio::SpatialSource::new(c, "/player.png").is_err());
}

#[test]
fn volume_persists_after_stop() {
    let (c, _e) = &mut tests::make_context();
    {
        let volume = 0.8;
        let mut sound = audio::Source::new(c, "/pew.ogg").unwrap();
        sound.set_volume(volume);
        assert_eq!(sound.volume(), volume);
        sound.stop();
        assert_eq!(sound.volume(), volume);
    }

    {
        let volume = 0.8;
        let mut sound = audio::SpatialSource::new(c, "/pew.ogg").unwrap();
        sound.set_volume(volume);
        assert_eq!(sound.volume(), volume);
        sound.stop();
        assert_eq!(sound.volume(), volume);
    }
}

#[test]
fn volume_persists_after_play() {
    let (c, _e) = &mut tests::make_context();
    {
        let volume = 0.8;
        let mut sound = audio::Source::new(c, "/pew.ogg").unwrap();
        sound.set_volume(volume);
        assert_eq!(sound.volume(), volume);
        sound.play().unwrap();
        assert_eq!(sound.volume(), volume);
    }

    {
        let volume = 0.8;
        let mut sound = audio::SpatialSource::new(c, "/pew.ogg").unwrap();
        sound.set_volume(volume);
        assert_eq!(sound.volume(), volume);
        sound.play().unwrap();
        assert_eq!(sound.volume(), volume);
    }
}
<|endoftext|>


<commit_before>/// One of the 8 base colors.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum BaseColor {
    /// Black color
    ///
    /// Color #0
    Black,
    /// Red color
    ///
    /// Color #1
    Red,
    /// Green color
    ///
    /// Color #2
    Green,
    /// Yellow color (Red + Green)
    ///
    /// Color #3
    Yellow,
    /// Blue color
    ///
    /// Color #4
    Blue,
    /// Magenta color (Red + Blue)
    ///
    /// Color #5
    Magenta,
    /// Cyan color (Green + Blue)
    ///
    /// Color #6
    Cyan,
    /// White color (Red + Green + Blue)
    ///
    /// Color #7
    White,
}

impl From<u8> for BaseColor {
    fn from(n: u8) -> Self {
        match n % 8 {
            0 => BaseColor::Black,
            1 => BaseColor::Red,
            2 => BaseColor::Green,
            3 => BaseColor::Yellow,
            4 => BaseColor::Blue,
            5 => BaseColor::Magenta,
            6 => BaseColor::Cyan,
            7 => BaseColor::White,
            _ => unreachable!(),
        }
    }
}

/// Represents a color used by the theme.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum Color {
    /// Represents a color, preset by terminal.
    TerminalDefault,

    /// One of the 8 base colors.
    ///
    /// Note: the actual color used depends on the terminal configuration.
    Dark(BaseColor),

    /// Lighter version of a base color.
    ///
    /// Note: the actual color used depends on the terminal configuration.
    Light(BaseColor),

    /// True-color, 24-bit.
    Rgb(u8, u8, u8),

    /// Low-resolution
    ///
    /// Each value should be `<= 5` (you'll get panics otherwise).
    ///
    /// These 216 possible colors are part of the default color palette.
    RgbLowRes(u8, u8, u8),
}

impl Color {
    /// Creates a color from its ID in the 256 colors list.
    ///
    /// * Colors 0-7 are base dark colors.
    /// * Colors 8-15 are base light colors.
    /// * Colors 16-231 are rgb colors with 6 values per channel (216 colors).
    /// * Colors 232-255 are grayscale colors.
    pub fn from_256colors(n: u8) -> Self {
        if n < 8 {
            Color::Dark(BaseColor::from(n))
        } else if n < 16 {
            Color::Light(BaseColor::from(n))
        } else if n >= 232 {
            let n = n - 232;
            let value = 8 + 10 * n;

            // TODO: returns a Grayscale value?
            Color::Rgb(value, value, value)
        } else {
            let n = n - 16;
            // We support 6*6*6 = 216 colors here
            assert!(n < 216);

            let r = n / 36;
            let g = (n % 36) / 6;
            let b = n % 6;

            // Each color is in the range [0, 5] (6 possible values)
            assert!(r < 6);
            assert!(g < 6);
            assert!(b < 6);

            Color::RgbLowRes(r, g, b)
        }
    }

    pub(crate) fn parse(value: &str) -> Option<Self> {
        Some(match value {
            "black" => Color::Dark(BaseColor::Black),
            "red" => Color::Dark(BaseColor::Red),
            "green" => Color::Dark(BaseColor::Green),
            "yellow" => Color::Dark(BaseColor::Yellow),
            "blue" => Color::Dark(BaseColor::Blue),
            "magenta" => Color::Dark(BaseColor::Magenta),
            "cyan" => Color::Dark(BaseColor::Cyan),
            "white" => Color::Dark(BaseColor::White),
            "light black" => Color::Light(BaseColor::Black),
            "light red" => Color::Light(BaseColor::Red),
            "light green" => Color::Light(BaseColor::Green),
            "light yellow" => Color::Light(BaseColor::Yellow),
            "light blue" => Color::Light(BaseColor::Blue),
            "light magenta" => Color::Light(BaseColor::Magenta),
            "light cyan" => Color::Light(BaseColor::Cyan),
            "light white" => Color::Light(BaseColor::White),
            "default" => Color::TerminalDefault,
            value => return Color::parse_special(value),
        })
    }

    fn parse_special(value: &str) -> Option<Color> {
        if value.starts_with('#') {
            let value = &value[1..];
            // Compute per-color length, and amplitude
            let (l, multiplier) = match value.len() {
                6 => (2, 1),
                3 => (1, 17),
                _ => panic!("Cannot parse color: {}", value),
            };
            let r = load_hex(&value[0..l]) * multiplier;
            let g = load_hex(&value[l..2 * l]) * multiplier;
            let b = load_hex(&value[2 * l..3 * l]) * multiplier;
            Some(Color::Rgb(r as u8, g as u8, b as u8))
        } else if value.len() == 3 {
            // RGB values between 0 and 5 maybe?
            let rgb: Vec<_> =
                value.chars().map(|c| c as i16 - '0' as i16).collect();
            if rgb.iter().all(|&i| i >= 0 && i < 6) {
                Some(Color::RgbLowRes(
                    rgb[0] as u8,
                    rgb[1] as u8,
                    rgb[2] as u8,
                ))
            } else {
                None
            }
        } else {
            None
        }
    }
}

/// Loads a hexadecimal code
fn load_hex(s: &str) -> u16 {
    let mut sum = 0;
    for c in s.chars() {
        sum *= 16;
        sum += match c {
            n @ '0'...'9' => n as i16 - '0' as i16,
            n @ 'a'...'f' => n as i16 - 'a' as i16 + 10,
            n @ 'A'...'F' => n as i16 - 'A' as i16 + 10,
            _ => 0,
        };
    }

    sum as u16
}
<commit_msg>Add Color::from_256colors test<commit_after>/// One of the 8 base colors.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum BaseColor {
    /// Black color
    ///
    /// Color #0
    Black,
    /// Red color
    ///
    /// Color #1
    Red,
    /// Green color
    ///
    /// Color #2
    Green,
    /// Yellow color (Red + Green)
    ///
    /// Color #3
    Yellow,
    /// Blue color
    ///
    /// Color #4
    Blue,
    /// Magenta color (Red + Blue)
    ///
    /// Color #5
    Magenta,
    /// Cyan color (Green + Blue)
    ///
    /// Color #6
    Cyan,
    /// White color (Red + Green + Blue)
    ///
    /// Color #7
    White,
}

impl From<u8> for BaseColor {
    fn from(n: u8) -> Self {
        match n % 8 {
            0 => BaseColor::Black,
            1 => BaseColor::Red,
            2 => BaseColor::Green,
            3 => BaseColor::Yellow,
            4 => BaseColor::Blue,
            5 => BaseColor::Magenta,
            6 => BaseColor::Cyan,
            7 => BaseColor::White,
            _ => unreachable!(),
        }
    }
}

/// Represents a color used by the theme.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum Color {
    /// Represents a color, preset by terminal.
    TerminalDefault,

    /// One of the 8 base colors.
    ///
    /// Note: the actual color used depends on the terminal configuration.
    Dark(BaseColor),

    /// Lighter version of a base color.
    ///
    /// Note: the actual color used depends on the terminal configuration.
    Light(BaseColor),

    /// True-color, 24-bit.
    Rgb(u8, u8, u8),

    /// Low-resolution
    ///
    /// Each value should be `<= 5` (you'll get panics otherwise).
    ///
    /// These 216 possible colors are part of the default color palette.
    RgbLowRes(u8, u8, u8),
}

impl Color {
    /// Creates a color from its ID in the 256 colors list.
    ///
    /// * Colors 0-7 are base dark colors.
    /// * Colors 8-15 are base light colors.
    /// * Colors 16-231 are rgb colors with 6 values per channel (216 colors).
    /// * Colors 232-255 are grayscale colors.
    pub fn from_256colors(n: u8) -> Self {
        if n < 8 {
            Color::Dark(BaseColor::from(n))
        } else if n < 16 {
            Color::Light(BaseColor::from(n))
        } else if n >= 232 {
            let n = n - 232;
            let value = 8 + 10 * n;

            // TODO: returns a Grayscale value?
            Color::Rgb(value, value, value)
        } else {
            let n = n - 16;
            // We support 6*6*6 = 216 colors here
            assert!(n < 216);

            let r = n / 36;
            let g = (n % 36) / 6;
            let b = n % 6;

            // Each color is in the range [0, 5] (6 possible values)
            assert!(r < 6);
            assert!(g < 6);
            assert!(b < 6);

            Color::RgbLowRes(r, g, b)
        }
    }

    pub(crate) fn parse(value: &str) -> Option<Self> {
        Some(match value {
            "black" => Color::Dark(BaseColor::Black),
            "red" => Color::Dark(BaseColor::Red),
            "green" => Color::Dark(BaseColor::Green),
            "yellow" => Color::Dark(BaseColor::Yellow),
            "blue" => Color::Dark(BaseColor::Blue),
            "magenta" => Color::Dark(BaseColor::Magenta),
            "cyan" => Color::Dark(BaseColor::Cyan),
            "white" => Color::Dark(BaseColor::White),
            "light black" => Color::Light(BaseColor::Black),
            "light red" => Color::Light(BaseColor::Red),
            "light green" => Color::Light(BaseColor::Green),
            "light yellow" => Color::Light(BaseColor::Yellow),
            "light blue" => Color::Light(BaseColor::Blue),
            "light magenta" => Color::Light(BaseColor::Magenta),
            "light cyan" => Color::Light(BaseColor::Cyan),
            "light white" => Color::Light(BaseColor::White),
            "default" => Color::TerminalDefault,
            value => return Color::parse_special(value),
        })
    }

    fn parse_special(value: &str) -> Option<Color> {
        if value.starts_with('#') {
            let value = &value[1..];
            // Compute per-color length, and amplitude
            let (l, multiplier) = match value.len() {
                6 => (2, 1),
                3 => (1, 17),
                _ => panic!("Cannot parse color: {}", value),
            };
            let r = load_hex(&value[0..l]) * multiplier;
            let g = load_hex(&value[l..2 * l]) * multiplier;
            let b = load_hex(&value[2 * l..3 * l]) * multiplier;
            Some(Color::Rgb(r as u8, g as u8, b as u8))
        } else if value.len() == 3 {
            // RGB values between 0 and 5 maybe?
            let rgb: Vec<_> =
                value.chars().map(|c| c as i16 - '0' as i16).collect();
            if rgb.iter().all(|&i| i >= 0 && i < 6) {
                Some(Color::RgbLowRes(
                    rgb[0] as u8,
                    rgb[1] as u8,
                    rgb[2] as u8,
                ))
            } else {
                None
            }
        } else {
            None
        }
    }
}

/// Loads a hexadecimal code
fn load_hex(s: &str) -> u16 {
    let mut sum = 0;
    for c in s.chars() {
        sum *= 16;
        sum += match c {
            n @ '0'...'9' => n as i16 - '0' as i16,
            n @ 'a'...'f' => n as i16 - 'a' as i16 + 10,
            n @ 'A'...'F' => n as i16 - 'A' as i16 + 10,
            _ => 0,
        };
    }

    sum as u16
}

#[cfg(test)]
mod tests {

    #[test]
    fn test_256_colors() {
        // Make sure Color::from_256colors never panics
        use super::Color;

        // TODO: use inclusive range when it gets stable
        for i in 0..256u16 {
            Color::from_256colors(i as u8);
        }
    }
}
<|endoftext|>


<commit_before>use grammar::*;
use grammar::Statement::*;
use grammar::Expression::*;
use grammar::ClassMember::*;
use grammar::OperatorType::*;

pub struct Settings {
    pub transform_block_scope: bool,
    pub transform_arrow: bool,
    pub transform_object: bool,
    pub transform_exponentation: bool,
}

#[inline(always)]
fn bind_this(function: Expression) -> Expression {
    Expression::call(Expression::member(function, "bind"), vec![ThisExpression])
}

impl Settings {
    pub fn target_es5() -> Settings {
        let mut settings = Settings::target_es2015();

        settings.transform_block_scope = true;
        settings.transform_arrow = true;
        settings.transform_object = true;

        settings
    }

    pub fn target_es2015() -> Settings {
        let mut settings = Settings::no_transform();

        settings.transform_exponentation = true;

        settings
    }

    pub fn no_transform() -> Settings {
        Settings {
            transform_block_scope: false,
            transform_arrow: false,
            transform_object: false,
            transform_exponentation: false,
        }
    }
}

/// The `Transformable` trait provides an interface for instances of grammar
/// to alter the AST, either by mutating self, or by returning a new node.
///
/// NOTE: Returning `None` means no changes are necessary!
trait Transformable {
    fn transform(&mut self, _: &Settings) {}

    fn contains_this(&self) -> bool {
        false
    }
}

impl Transformable for Parameter {}

impl Transformable for Expression {
    fn transform(&mut self, settings: &Settings) {
        *self = match *self {
            ArrowFunctionExpression {
                ref mut params,
                ref mut body,
            } => {
                params.transform(settings);
                body.transform(settings);

                // transformation flag check
                if !settings.transform_arrow {
                    return;
                }

                let body = match **body {
                    BlockStatement { ref body }   => body.clone(),
                    ExpressionStatement(ref expr) => vec![
                        ReturnStatement {
                            value: Some(expr.clone())
                        }
                    ],
                    ref statement => {
                        panic!("Invalid arrow function body {:#?}", statement);
                    }
                };

                let bind = body.contains_this();

                let function = FunctionExpression {
                    name: None,
                    params: params.clone(),
                    body: body,
                };

                if bind {
                    bind_this(function)
                } else {
                    function
                }
            },

            ArrayExpression(ref mut items) => {
                items.transform(settings);
                return;
            },

            ObjectExpression(ref mut members) => {
                members.transform(settings);

                // transformation flag check
                if !settings.transform_object {
                    return;
                }

                let (mut computed, literal): (Vec<ObjectMember>, Vec<ObjectMember>)
                = members.drain(..).partition(|member| {
                    match *member {
                        ObjectMember::Computed { .. } => true,
                        _                             => false,
                    }
                });

                if computed.is_empty() {
                    *members = literal;
                    return;
                }

                let mut body = Vec::new();

                body.push(VariableDeclarationStatement {
                    kind: VariableDeclarationKind::Var,
                    declarators: vec![
                        VariableDeclarator {
                            name: "___".to_string(),
                            value: Some(ObjectExpression(literal)),
                        }
                    ]
                });

                for member in computed.drain(..) {
                    if let ObjectMember::Computed { key, value } = member {
                        body.push(ExpressionStatement(BinaryExpression {
                            left: Box::new(MemberExpression {
                                object: Box::new(Expression::ident("___")),
                                property: Box::new(
                                    MemberKey::Computed(key)
                                )
                            }),
                            operator: Assign,
                            right: Box::new(value),
                        }));
                    }
                }

                body.push(ReturnStatement {
                    value: Some(Expression::ident("___"))
                });

                Expression::call(FunctionExpression {
                    name: None,
                    params: Vec::new(),
                    body: body,
                }, Vec::new())
            },

            CallExpression {
                ref mut callee,
                ref mut arguments,
            } => {
                callee.transform(settings);
                arguments.transform(settings);
                return;
            },

            BinaryExpression {
                ref mut left,
                ref mut operator,
                ref mut right,
            } => {
                left.transform(settings);
                right.transform(settings);

                if !settings.transform_exponentation {
                    return;
                }

                match *operator {
                    Exponent => Expression::call(
                        Expression::member(Expression::ident("Math"), "pow"),
                        vec![*left.clone(), *right.clone()]
                    ),

                    ExponentAssign => {
                        *operator = Assign;
                        *right = Box::new(Expression::call(
                            Expression::member(Expression::ident("Math"), "pow"),
                            vec![*left.clone(), *right.clone()]
                        ));
                        return;
                    },

                    _ => return,
                }
            }

            _ => return,
        }
    }

    fn contains_this(&self) -> bool {
        match *self {
            ThisExpression => true,

            ArrayExpression(ref items) => items.contains_this(),

            ObjectExpression(ref members) => members.contains_this(),

            MemberExpression {
                ref object,
                ..
            } => object.contains_this(),

            CallExpression {
                ref callee,
                ref arguments,
            } => callee.contains_this() || arguments.contains_this(),

            BinaryExpression {
                ref left,
                ref right,
                ..
            } => left.contains_this() || right.contains_this(),

            _ => false,
        }
    }
}

impl Transformable for ObjectMember {
    fn transform(&mut self, settings: &Settings) {
        *self = match *self {

            ObjectMember::Shorthand {
                ref key,
            } => {
                // transformation flag check
                if !settings.transform_object {
                    return;
                }

                ObjectMember::Literal {
                    key: key.clone(),
                    value: IdentifierExpression(key.clone()),
                }
            },

            ObjectMember::Literal {
                ref mut value,
                ..
            } => {
                value.transform(settings);
                return;
            },

            ObjectMember::Computed {
                ref mut key,
                ref mut value,
            } => {
                key.transform(settings);
                value.transform(settings);
                return;
            },

            ObjectMember::Method {
                ref mut name,
                ref mut params,
                ref mut body,
            } => {
                body.transform(settings);
                params.transform(settings);

                // transformation flag check
                if !settings.transform_object {
                    return;
                }

                ObjectMember::Literal {
                    key: name.clone(),
                    value: FunctionExpression {
                        name: Some(name.clone()),
                        params: params.clone(),
                        body: body.clone(),
                    }
                }
            },

            ObjectMember::ComputedMethod {
                ref mut name,
                ref mut params,
                ref mut body,
            } => {
                body.transform(settings);
                params.transform(settings);

                // transformation flag check
                if !settings.transform_object {
                    return;
                }

                ObjectMember::Computed {
                    key: name.clone(),
                    value: FunctionExpression {
                        name: None,
                        params: params.clone(),
                        body: body.clone(),
                    }
                }
            },
        }
    }

    fn contains_this(&self) -> bool {
        match *self {
            ObjectMember::Literal {
                ref value,
                ..
            } => value.contains_this(),

            ObjectMember::Computed {
                ref key,
                ref value,
            } => key.contains_this() || value.contains_this(),

            _ => false,
        }
    }
}

impl Transformable for ClassMember {
    fn transform(&mut self, settings: &Settings) {
        match *self {
            Constructor {
                ref mut params,
                ref mut body,
            } => {
                params.transform(settings);
                body.transform(settings);
            },

            Method {
                ref mut params,
                ref mut body,
                ..
            } => {
                params.transform(settings);
                body.transform(settings);
            },

            Property {
                ref mut value,
                ..
            } => {
                value.transform(settings);
            }
        }
    }
}

impl Transformable for VariableDeclarator {
    fn transform(&mut self, settings: &Settings) {
        match self.value {
            Some(ref mut expression) => expression.transform(settings),
            _                        => {},
        }
    }

    fn contains_this(&self) -> bool {
        match self.value {
            Some(ref expression) => expression.contains_this(),
            _                    => false,
        }
    }
}

impl Transformable for Statement {
    fn transform(&mut self, settings: &Settings) {
        *self = match *self {
            BlockStatement {
                ref mut body,
            } => {
                body.transform(settings);
                return;
            },

            LabeledStatement {
                ref mut body,
                ..
            } => {
                body.transform(settings);
                return;
            },

            VariableDeclarationStatement {
                ref mut kind,
                ref mut declarators,
            } => {
                declarators.transform(settings);

                // transformation flag check
                if !settings.transform_block_scope {
                    return;
                }

                *kind = VariableDeclarationKind::Var;
                return;
            },

            ExpressionStatement(ref mut expression) => {
                expression.transform(settings);
                return;
            },

            IfStatement {
                ref mut test,
                ref mut consequent,
                ref mut alternate,
                ..
            } => {
                test.transform(settings);
                consequent.transform(settings);
                if let Some(ref mut alternate) = *alternate {
                    alternate.transform(settings);
                }
                return;
            },

            ClassStatement {
                ref mut body,
                ..
            } => {
                body.transform(settings);
                return;
            }

            _ => return,
        }
    }

    fn contains_this(&self) -> bool {
        match *self {
            VariableDeclarationStatement {
                ref declarators,
                ..
            } => declarators.contains_this(),

            ExpressionStatement(ref expression) => expression.contains_this(),

            ReturnStatement {
                value: Some(ref expression)
            } => expression.contains_this(),

            _ => false,
        }
    }
}

impl<T: Transformable> Transformable for Vec<T> {
    fn transform(&mut self, settings: &Settings) {
        for item in self.iter_mut() {
            item.transform(settings);
        }
    }

    fn contains_this(&self) -> bool {
        for item in self {
            if item.contains_this() {
                return true;
            }
        }
        return false;
    }
}

pub fn transform(program: &mut Program, settings: Settings) {
    program.body.transform(&settings);
}
<commit_msg>Use `.split_off(0)` instead of `.clone()` for vectors to reduce heap allocation<commit_after>use grammar::*;
use grammar::Statement::*;
use grammar::Expression::*;
use grammar::ClassMember::*;
use grammar::OperatorType::*;

pub struct Settings {
    pub transform_block_scope: bool,
    pub transform_arrow: bool,
    pub transform_object: bool,
    pub transform_exponentation: bool,
}

#[inline(always)]
fn bind_this(function: Expression) -> Expression {
    Expression::call(Expression::member(function, "bind"), vec![ThisExpression])
}

impl Settings {
    pub fn target_es5() -> Settings {
        let mut settings = Settings::target_es2015();

        settings.transform_block_scope = true;
        settings.transform_arrow = true;
        settings.transform_object = true;

        settings
    }

    pub fn target_es2015() -> Settings {
        let mut settings = Settings::no_transform();

        settings.transform_exponentation = true;

        settings
    }

    pub fn no_transform() -> Settings {
        Settings {
            transform_block_scope: false,
            transform_arrow: false,
            transform_object: false,
            transform_exponentation: false,
        }
    }
}

/// The `Transformable` trait provides an interface for instances of grammar
/// to alter the AST, either by mutating self, or by returning a new node.
///
/// NOTE: Returning `None` means no changes are necessary!
trait Transformable {
    fn transform(&mut self, _: &Settings) {}

    fn contains_this(&self) -> bool {
        false
    }
}

impl Transformable for Parameter {}

impl Transformable for Expression {
    fn transform(&mut self, settings: &Settings) {
        *self = match *self {
            ArrowFunctionExpression {
                ref mut params,
                ref mut body,
            } => {
                params.transform(settings);
                body.transform(settings);

                // transformation flag check
                if !settings.transform_arrow {
                    return;
                }

                let body = match **body {
                    BlockStatement { ref mut body } => body.split_off(0),
                    ExpressionStatement(ref expr)   => vec![
                        ReturnStatement {
                            value: Some(expr.clone())
                        }
                    ],
                    ref statement => {
                        panic!("Invalid arrow function body {:#?}", statement);
                    }
                };

                let bind = body.contains_this();

                let function = FunctionExpression {
                    name: None,
                    params: params.split_off(0),
                    body: body,
                };

                if bind {
                    bind_this(function)
                } else {
                    function
                }
            },

            ArrayExpression(ref mut items) => {
                items.transform(settings);
                return;
            },

            ObjectExpression(ref mut members) => {
                members.transform(settings);

                // transformation flag check
                if !settings.transform_object {
                    return;
                }

                let (mut computed, literal): (Vec<ObjectMember>, Vec<ObjectMember>)
                = members.drain(..).partition(|member| {
                    match *member {
                        ObjectMember::Computed { .. } => true,
                        _                             => false,
                    }
                });

                if computed.is_empty() {
                    *members = literal;
                    return;
                }

                let mut body = Vec::new();

                body.push(VariableDeclarationStatement {
                    kind: VariableDeclarationKind::Var,
                    declarators: vec![
                        VariableDeclarator {
                            name: "___".to_string(),
                            value: Some(ObjectExpression(literal)),
                        }
                    ]
                });

                for member in computed.drain(..) {
                    if let ObjectMember::Computed { key, value } = member {
                        body.push(ExpressionStatement(BinaryExpression {
                            left: Box::new(MemberExpression {
                                object: Box::new(Expression::ident("___")),
                                property: Box::new(
                                    MemberKey::Computed(key)
                                )
                            }),
                            operator: Assign,
                            right: Box::new(value),
                        }));
                    }
                }

                body.push(ReturnStatement {
                    value: Some(Expression::ident("___"))
                });

                Expression::call(FunctionExpression {
                    name: None,
                    params: Vec::new(),
                    body: body,
                }, Vec::new())
            },

            CallExpression {
                ref mut callee,
                ref mut arguments,
            } => {
                callee.transform(settings);
                arguments.transform(settings);
                return;
            },

            BinaryExpression {
                ref mut left,
                ref mut operator,
                ref mut right,
            } => {
                left.transform(settings);
                right.transform(settings);

                if !settings.transform_exponentation {
                    return;
                }

                match *operator {
                    Exponent => Expression::call(
                        Expression::member(Expression::ident("Math"), "pow"),
                        vec![*left.clone(), *right.clone()]
                    ),

                    ExponentAssign => {
                        *operator = Assign;
                        *right = Box::new(Expression::call(
                            Expression::member(Expression::ident("Math"), "pow"),
                            vec![*left.clone(), *right.clone()]
                        ));
                        return;
                    },

                    _ => return,
                }
            }

            _ => return,
        }
    }

    fn contains_this(&self) -> bool {
        match *self {
            ThisExpression => true,

            ArrayExpression(ref items) => items.contains_this(),

            ObjectExpression(ref members) => members.contains_this(),

            MemberExpression {
                ref object,
                ..
            } => object.contains_this(),

            CallExpression {
                ref callee,
                ref arguments,
            } => callee.contains_this() || arguments.contains_this(),

            BinaryExpression {
                ref left,
                ref right,
                ..
            } => left.contains_this() || right.contains_this(),

            _ => false,
        }
    }
}

impl Transformable for ObjectMember {
    fn transform(&mut self, settings: &Settings) {
        *self = match *self {

            ObjectMember::Shorthand {
                ref key,
            } => {
                // transformation flag check
                if !settings.transform_object {
                    return;
                }

                ObjectMember::Literal {
                    key: key.clone(),
                    value: IdentifierExpression(key.clone()),
                }
            },

            ObjectMember::Literal {
                ref mut value,
                ..
            } => {
                value.transform(settings);
                return;
            },

            ObjectMember::Computed {
                ref mut key,
                ref mut value,
            } => {
                key.transform(settings);
                value.transform(settings);
                return;
            },

            ObjectMember::Method {
                ref mut name,
                ref mut params,
                ref mut body,
            } => {
                body.transform(settings);
                params.transform(settings);

                // transformation flag check
                if !settings.transform_object {
                    return;
                }

                ObjectMember::Literal {
                    key: name.clone(),
                    value: FunctionExpression {
                        name: Some(name.clone()),
                        params: params.split_off(0),
                        body: body.split_off(0),
                    }
                }
            },

            ObjectMember::ComputedMethod {
                ref mut name,
                ref mut params,
                ref mut body,
            } => {
                body.transform(settings);
                params.transform(settings);

                // transformation flag check
                if !settings.transform_object {
                    return;
                }

                ObjectMember::Computed {
                    key: name.clone(),
                    value: FunctionExpression {
                        name: None,
                        params: params.split_off(0),
                        body: body.split_off(0),
                    }
                }
            },
        }
    }

    fn contains_this(&self) -> bool {
        match *self {
            ObjectMember::Literal {
                ref value,
                ..
            } => value.contains_this(),

            ObjectMember::Computed {
                ref key,
                ref value,
            } => key.contains_this() || value.contains_this(),

            _ => false,
        }
    }
}

impl Transformable for ClassMember {
    fn transform(&mut self, settings: &Settings) {
        match *self {
            Constructor {
                ref mut params,
                ref mut body,
            } => {
                params.transform(settings);
                body.transform(settings);
            },

            Method {
                ref mut params,
                ref mut body,
                ..
            } => {
                params.transform(settings);
                body.transform(settings);
            },

            Property {
                ref mut value,
                ..
            } => {
                value.transform(settings);
            }
        }
    }
}

impl Transformable for VariableDeclarator {
    fn transform(&mut self, settings: &Settings) {
        match self.value {
            Some(ref mut expression) => expression.transform(settings),
            _                        => {},
        }
    }

    fn contains_this(&self) -> bool {
        match self.value {
            Some(ref expression) => expression.contains_this(),
            _                    => false,
        }
    }
}

impl Transformable for Statement {
    fn transform(&mut self, settings: &Settings) {
        *self = match *self {
            BlockStatement {
                ref mut body,
            } => {
                body.transform(settings);
                return;
            },

            LabeledStatement {
                ref mut body,
                ..
            } => {
                body.transform(settings);
                return;
            },

            VariableDeclarationStatement {
                ref mut kind,
                ref mut declarators,
            } => {
                declarators.transform(settings);

                // transformation flag check
                if !settings.transform_block_scope {
                    return;
                }

                *kind = VariableDeclarationKind::Var;
                return;
            },

            ExpressionStatement(ref mut expression) => {
                expression.transform(settings);
                return;
            },

            IfStatement {
                ref mut test,
                ref mut consequent,
                ref mut alternate,
                ..
            } => {
                test.transform(settings);
                consequent.transform(settings);
                if let Some(ref mut alternate) = *alternate {
                    alternate.transform(settings);
                }
                return;
            },

            ClassStatement {
                ref mut body,
                ..
            } => {
                body.transform(settings);
                return;
            }

            _ => return,
        }
    }

    fn contains_this(&self) -> bool {
        match *self {
            VariableDeclarationStatement {
                ref declarators,
                ..
            } => declarators.contains_this(),

            ExpressionStatement(ref expression) => expression.contains_this(),

            ReturnStatement {
                value: Some(ref expression)
            } => expression.contains_this(),

            _ => false,
        }
    }
}

impl<T: Transformable> Transformable for Vec<T> {
    fn transform(&mut self, settings: &Settings) {
        for item in self.iter_mut() {
            item.transform(settings);
        }
    }

    fn contains_this(&self) -> bool {
        for item in self {
            if item.contains_this() {
                return true;
            }
        }
        return false;
    }
}

pub fn transform(program: &mut Program, settings: Settings) {
    program.body.transform(&settings);
}
<|endoftext|>


<commit_before>use std::io::Result as IoResult;
use std::io::Write;

/// Splits the incoming data into HTTP chunks.
pub struct ChunksEncoder<W> where W: Write {
    // where to send the result
    output: W,

    // size of each chunk
    chunks_size: usize,

    // data waiting to be sent is stored here
    buffer: Vec<u8>,
}

impl<W> ChunksEncoder<W> where W: Write {
    pub fn new(output: W) -> ChunksEncoder<W> {
        ChunksEncoder::new_with_chunks_size(output, 8192)
    }

    pub fn new_with_chunks_size(output: W, chunks: usize) -> ChunksEncoder<W> {
        ChunksEncoder {
            output: output,
            chunks_size: chunks,
            buffer: Vec::with_capacity(0),
        }
    }
}

fn send<W>(output: &mut W, data: &[u8]) -> IoResult<()> where W: Write {
    try!(write!(output, "{:x}\r\n", data.len()));
    try!(output.write_all(data));
    try!(write!(output, "\r\n"));
    Ok(())
}

impl<W> Write for ChunksEncoder<W> where W: Write {
    fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
        try!(self.buffer.write_all(buf));

        while self.buffer.len() >= self.chunks_size {
            let rest = {
                let (to_send, rest) = self.buffer.split_at_mut(self.chunks_size);
                try!(send(&mut self.output, to_send));
                rest.to_vec()
            };
            self.buffer = rest;
        }

        Ok(buf.len())
    }

    fn flush(&mut self) -> IoResult<()> {
        if self.buffer.len() == 0 {
            return Ok(());
        }

        try!(send(&mut self.output, &self.buffer));
        self.buffer.clear();
        Ok(())
    }
}

impl<W> Drop for ChunksEncoder<W> where W: Write {
    fn drop(&mut self) {
        self.flush().ok();
        send(&mut self.output, &[]).ok();
    }
}

#[cfg(test)]
mod test {
    use std::io;
    use std::io::Write;
    use super::ChunksEncoder;
    use ascii::OwnedAsciiCast;

    #[test]
    fn test() {
        let mut source = io::Cursor::new("hello world".to_string().into_bytes());
        let mut dest: Vec<u8> = vec![];

        {
            let mut encoder = ChunksEncoder::new_with_chunks_size(dest.by_ref(), 5);
            io::copy(&mut source, &mut encoder).unwrap();
        }

        let output = dest.into_ascii().unwrap().to_string();

        assert_eq!(output, "5\r\nhello\r\n5\r\n worl\r\n1\r\nd\r\n0\r\n\r\n");
    }
}
<commit_msg>Remove reliance on ascii<commit_after>use std::io::Result as IoResult;
use std::io::Write;

/// Splits the incoming data into HTTP chunks.
pub struct ChunksEncoder<W> where W: Write {
    // where to send the result
    output: W,

    // size of each chunk
    chunks_size: usize,

    // data waiting to be sent is stored here
    buffer: Vec<u8>,
}

impl<W> ChunksEncoder<W> where W: Write {
    pub fn new(output: W) -> ChunksEncoder<W> {
        ChunksEncoder::new_with_chunks_size(output, 8192)
    }

    pub fn new_with_chunks_size(output: W, chunks: usize) -> ChunksEncoder<W> {
        ChunksEncoder {
            output: output,
            chunks_size: chunks,
            buffer: Vec::with_capacity(0),
        }
    }
}

fn send<W>(output: &mut W, data: &[u8]) -> IoResult<()> where W: Write {
    try!(write!(output, "{:x}\r\n", data.len()));
    try!(output.write_all(data));
    try!(write!(output, "\r\n"));
    Ok(())
}

impl<W> Write for ChunksEncoder<W> where W: Write {
    fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
        try!(self.buffer.write_all(buf));

        while self.buffer.len() >= self.chunks_size {
            let rest = {
                let (to_send, rest) = self.buffer.split_at_mut(self.chunks_size);
                try!(send(&mut self.output, to_send));
                rest.to_vec()
            };
            self.buffer = rest;
        }

        Ok(buf.len())
    }

    fn flush(&mut self) -> IoResult<()> {
        if self.buffer.len() == 0 {
            return Ok(());
        }

        try!(send(&mut self.output, &self.buffer));
        self.buffer.clear();
        Ok(())
    }
}

impl<W> Drop for ChunksEncoder<W> where W: Write {
    fn drop(&mut self) {
        self.flush().ok();
        send(&mut self.output, &[]).ok();
    }
}

#[cfg(test)]
mod test {
    use std::io;
    use std::io::Write;
    use std::str::from_utf8;
    use super::ChunksEncoder;

    #[test]
    fn test() {
        let mut source = io::Cursor::new("hello world".to_string().into_bytes());
        let mut dest: Vec<u8> = vec![];

        {
            let mut encoder = ChunksEncoder::new_with_chunks_size(dest.by_ref(), 5);
            io::copy(&mut source, &mut encoder).unwrap();
        }

        let output = from_utf8(&dest).unwrap();

        assert_eq!(output, "5\r\nhello\r\n5\r\n worl\r\n1\r\nd\r\n0\r\n\r\n");
    }
}
<|endoftext|>