<commit_before>//! This exposes the command line interface that the binary uses
use std::fs;
use std::io;
use std::env;
use std::process;
use std::sync::Mutex;

use clap::{App, Arg, SubCommand, ArgMatches, AppSettings};
use chrono::UTC;
use log;

use super::{Result, ResultExt, Error};
use super::sdk::{Sdk, DumpOptions};
use super::config::Config;
use super::memdb::stash::{MemDbStash, SyncOptions};
use super::api::server::{ApiServer, BindOptions};

struct SimpleLogger<W: ?Sized> {
    f: Mutex<Box<W>>,
}

impl<W: io::Write + Send + ?Sized> log::Log for SimpleLogger<W> {

    fn enabled(&self, metadata: &log::LogMetadata) -> bool {
        metadata.level() <= log::LogLevel::Info
    }

    fn log(&self, record: &log::LogRecord) {
        let mut f = self.f.lock().unwrap();
        if self.enabled(record.metadata()) {
            writeln!(f, "[{}] [{}] {}: {}",
                     UTC::now(),
                     record.level(),
                     record.target().split(':').next().unwrap(),
                     record.args()).ok();
        }
    }
}

fn setup_logging(config: &Config) -> Result<()> {
    let filter = config.get_log_level_filter()?;
    if filter >= log::LogLevel::Debug {
        env::set_var("RUST_BACKTRACE", "1");
    }

    let f : Box<io::Write + Send> = match config.get_log_filename()? {
        Some(path) => Box::new(fs::File::open(path)?),
        None => Box::new(io::stdout()),
    };
    log::set_logger(|max_log_level| {
        max_log_level.set(filter);
        Box::new(SimpleLogger {
            f: Mutex::new(f),
        })
    }).unwrap();
    Ok(())
}

/// Main entry point that starts the CLI
pub fn main() {
    match execute() {
        Ok(()) => {},
        Err(err) => {
            use std::error::Error;
            println!("error: {}", err);
            let mut cause = err.cause();
            while let Some(the_cause) = cause {
                println!("  caused by: {}", the_cause);
                cause = the_cause.cause();
            }
            if let Some(backtrace) = err.backtrace() {
                debug!("  Traceback: {:?}", backtrace);
            }
            process::exit(1);
        }
    }
}

fn config_from_matches(matches: &ArgMatches) -> Result<Config> {
    let mut cfg = if let Some(config_path) = matches.value_of("config") {
        Config::load_file(config_path)?
    } else {
        Config::load_default()?
    };

    if let Some(value) = matches.value_of("log_level") {
        let filter = value.parse()
            .map_err(|_| Error::from("Invalid value for log level"))?;
        cfg.set_log_level_filter(filter);
    };

    if let Some(value) = matches.value_of("symbol_dir") {
        cfg.set_symbol_dir(value);
    }

    if let Some(value) = matches.value_of("aws_bucket_url") {
        cfg.set_aws_bucket_url(value);
    }

    if let Some(value) = matches.value_of("aws_region") {
        let region = value.parse()
            .map_err(|_| Error::from("Invalid AWS region"))?;
        cfg.set_aws_region(region);
    }

    Ok(cfg)
}

fn execute() -> Result<()> {
    let app = App::new("sentry-symbolserver")
        .about("This tool implements an Apple SDK processor and server.")
        .setting(AppSettings::SubcommandRequiredElseHelp)
        .setting(AppSettings::ColorNever)
        .arg(Arg::with_name("config")
             .long("config")
             .value_name("FILE")
             .help("The path to the config file"))
        .arg(Arg::with_name("log_level")
             .short("l")
             .long("log-level")
             .value_name("LEVEL")
             .help("Overrides the log level from the config"))
        .arg(Arg::with_name("symbol_dir")
             .short("p")
             .long("symbol-dir")
             .value_name("PATH")
             .help("The path to the symbol directory"))
        .arg(Arg::with_name("aws_bucket_url")
             .long("aws-bucket-url")
             .value_name("URL")
             .help("The bucket URL the sync tool should pull from"))
        .arg(Arg::with_name("aws_region")
             .long("aws-region")
             .value_name("REGION")
             .help("Sets the AWS region the bucket is located in"))
        .subcommand(
            SubCommand::with_name("sync")
                .about("Updates symbols from S3"))
        .subcommand(
            SubCommand::with_name("run")
                .about("Runs the symbol server")
                .arg(Arg::with_name("disable_sync")
                     .long("disable-sync")
                     .help("Disables the background synching"))
                .arg(Arg::with_name("bind")
                     .long("bind")
                     .value_name("ADDR")
                     .help("Bind to a specific address (ip:port)"))
                .arg(Arg::with_name("bind_fd")
                     .long("bind-fd")
                     .value_name("FD")
                     .help("Bind to a specific file descriptor"))
                .arg(Arg::with_name("threads")
                     .long("threads")
                     .short("t")
                     .value_name("COUNT")
                     .help("Overrides the default listener thread count")))
        .subcommand(
            SubCommand::with_name("convert-sdk")
                .about("Converts an SDK into a memdb file")
                .arg(Arg::with_name("path")
                     .index(1)
                     .value_name("PATH")
                     .required(true)
                     .multiple(true)
                     .help("Path to the support folder"))
                .arg(Arg::with_name("compress")
                     .short("c")
                     .long("compress")
                     .help("Write compressed files instead."))
                .arg(Arg::with_name("output-path")
                     .short("o")
                     .long("output")
                     .help("Where the result should be stored")));
    let matches = app.get_matches();

    let cfg = config_from_matches(&matches)?;
    setup_logging(&cfg)?;

    if let Some(matches) = matches.subcommand_matches("convert-sdk") {
        convert_sdk_action(matches.values_of("path").unwrap().collect(),
                           matches.value_of("output-path").unwrap_or("."),
                           matches.is_present("compress"))?;
    } else if let Some(matches) = matches.subcommand_matches("run") {
        run_action(&cfg, matches)?;
    } else if let Some(_matches) = matches.subcommand_matches("sync") {
        sync_action(&cfg)?;
    }

    Ok(())
}

fn convert_sdk_action(paths: Vec<&str>, output_path: &str, compress: bool)
    -> Result<()>
{
    let dst_base = env::current_dir().unwrap().join(output_path);

    for (idx, path) in paths.iter().enumerate() {
        if idx > 0 {
            println!("");
        }
        let sdk = Sdk::new(&path)?;
        let mut dst = dst_base.join(sdk.info().memdb_filename());
        if compress {
            dst.set_extension("memdbz");
        }

        println!("SDK {} ({} {}):", sdk.info().name(),
                 sdk.info().version(), sdk.info().build().unwrap_or("UNKNONW"));

        // make sure we close the file at the end, in case we want to
        // re-open it for compressing.
        let f = fs::File::create(&dst)?;
        let options = DumpOptions {
            show_progress_bar: true,
            compress: compress,
            ..Default::default()
        };
        sdk.dump_memdb(f, options)?;
    }

    Ok(())
}

fn sync_action(config: &Config) -> Result<()> {
    let stash = MemDbStash::new(config)?;
    stash.sync(SyncOptions {
        user_facing: true,
        ..Default::default()
    })?;
    Ok(())
}

fn run_action(config: &Config, matches: &ArgMatches) -> Result<()> {
    let api_server = ApiServer::new(config)?;

    if !matches.is_present("disable_sync") {
        api_server.spawn_sync_thread()?;
    }

    let threads: usize = if let Some(threads) = matches.value_of("threads") {
        threads.parse().chain_err(|| "invalid value for threads")?
    } else {
        config.get_server_threads()?
    };

    api_server.run(threads, if let Some(addr) = matches.value_of("bind") {
        BindOptions::BindToAddr(addr)
    } else if let Some(fd) = matches.value_of("bind_fd") {
        BindOptions::BindToFd(fd.parse().chain_err(|| "invalid value for file descriptor")?)
    } else {
        BindOptions::UseConfig
    })?;

    Ok(())
}
<commit_msg>Improved log format<commit_after>//! This exposes the command line interface that the binary uses
use std::fs;
use std::io;
use std::env;
use std::process;
use std::sync::Mutex;

use clap::{App, Arg, SubCommand, ArgMatches, AppSettings};
use chrono::UTC;
use log;

use super::{Result, ResultExt, Error};
use super::sdk::{Sdk, DumpOptions};
use super::config::Config;
use super::memdb::stash::{MemDbStash, SyncOptions};
use super::api::server::{ApiServer, BindOptions};

struct SimpleLogger<W: ?Sized> {
    f: Mutex<Box<W>>,
}

impl<W: io::Write + Send + ?Sized> log::Log for SimpleLogger<W> {

    fn enabled(&self, metadata: &log::LogMetadata) -> bool {
        metadata.level() <= log::LogLevel::Info
    }

    fn log(&self, record: &log::LogRecord) {
        let mut f = self.f.lock().unwrap();
        if self.enabled(record.metadata()) {
            writeln!(f, "[{}] {} | {}{}",
                     UTC::now(),
                     record.target().split(':').next().unwrap(),
                     match record.level() {
                         log::LogLevel::Error => "ERROR: ",
                         log::LogLevel::Warn => "WARNING: ",
                         _ => "",
                     },
                     record.args()).ok();
        }
    }
}

fn setup_logging(config: &Config) -> Result<()> {
    let filter = config.get_log_level_filter()?;
    if filter >= log::LogLevel::Debug {
        env::set_var("RUST_BACKTRACE", "1");
    }

    let f : Box<io::Write + Send> = match config.get_log_filename()? {
        Some(path) => Box::new(fs::File::open(path)?),
        None => Box::new(io::stdout()),
    };
    log::set_logger(|max_log_level| {
        max_log_level.set(filter);
        Box::new(SimpleLogger {
            f: Mutex::new(f),
        })
    }).unwrap();
    Ok(())
}

/// Main entry point that starts the CLI
pub fn main() {
    match execute() {
        Ok(()) => {},
        Err(err) => {
            use std::error::Error;
            println!("error: {}", err);
            let mut cause = err.cause();
            while let Some(the_cause) = cause {
                println!("  caused by: {}", the_cause);
                cause = the_cause.cause();
            }
            if let Some(backtrace) = err.backtrace() {
                debug!("  Traceback: {:?}", backtrace);
            }
            process::exit(1);
        }
    }
}

fn config_from_matches(matches: &ArgMatches) -> Result<Config> {
    let mut cfg = if let Some(config_path) = matches.value_of("config") {
        Config::load_file(config_path)?
    } else {
        Config::load_default()?
    };

    if let Some(value) = matches.value_of("log_level") {
        let filter = value.parse()
            .map_err(|_| Error::from("Invalid value for log level"))?;
        cfg.set_log_level_filter(filter);
    };

    if let Some(value) = matches.value_of("symbol_dir") {
        cfg.set_symbol_dir(value);
    }

    if let Some(value) = matches.value_of("aws_bucket_url") {
        cfg.set_aws_bucket_url(value);
    }

    if let Some(value) = matches.value_of("aws_region") {
        let region = value.parse()
            .map_err(|_| Error::from("Invalid AWS region"))?;
        cfg.set_aws_region(region);
    }

    Ok(cfg)
}

fn execute() -> Result<()> {
    let app = App::new("sentry-symbolserver")
        .about("This tool implements an Apple SDK processor and server.")
        .setting(AppSettings::SubcommandRequiredElseHelp)
        .setting(AppSettings::ColorNever)
        .arg(Arg::with_name("config")
             .long("config")
             .value_name("FILE")
             .help("The path to the config file"))
        .arg(Arg::with_name("log_level")
             .short("l")
             .long("log-level")
             .value_name("LEVEL")
             .help("Overrides the log level from the config"))
        .arg(Arg::with_name("symbol_dir")
             .short("p")
             .long("symbol-dir")
             .value_name("PATH")
             .help("The path to the symbol directory"))
        .arg(Arg::with_name("aws_bucket_url")
             .long("aws-bucket-url")
             .value_name("URL")
             .help("The bucket URL the sync tool should pull from"))
        .arg(Arg::with_name("aws_region")
             .long("aws-region")
             .value_name("REGION")
             .help("Sets the AWS region the bucket is located in"))
        .subcommand(
            SubCommand::with_name("sync")
                .about("Updates symbols from S3"))
        .subcommand(
            SubCommand::with_name("run")
                .about("Runs the symbol server")
                .arg(Arg::with_name("disable_sync")
                     .long("disable-sync")
                     .help("Disables the background synching"))
                .arg(Arg::with_name("bind")
                     .long("bind")
                     .value_name("ADDR")
                     .help("Bind to a specific address (ip:port)"))
                .arg(Arg::with_name("bind_fd")
                     .long("bind-fd")
                     .value_name("FD")
                     .help("Bind to a specific file descriptor"))
                .arg(Arg::with_name("threads")
                     .long("threads")
                     .short("t")
                     .value_name("COUNT")
                     .help("Overrides the default listener thread count")))
        .subcommand(
            SubCommand::with_name("convert-sdk")
                .about("Converts an SDK into a memdb file")
                .arg(Arg::with_name("path")
                     .index(1)
                     .value_name("PATH")
                     .required(true)
                     .multiple(true)
                     .help("Path to the support folder"))
                .arg(Arg::with_name("compress")
                     .short("c")
                     .long("compress")
                     .help("Write compressed files instead."))
                .arg(Arg::with_name("output-path")
                     .short("o")
                     .long("output")
                     .help("Where the result should be stored")));
    let matches = app.get_matches();

    let cfg = config_from_matches(&matches)?;
    setup_logging(&cfg)?;

    if let Some(matches) = matches.subcommand_matches("convert-sdk") {
        convert_sdk_action(matches.values_of("path").unwrap().collect(),
                           matches.value_of("output-path").unwrap_or("."),
                           matches.is_present("compress"))?;
    } else if let Some(matches) = matches.subcommand_matches("run") {
        run_action(&cfg, matches)?;
    } else if let Some(_matches) = matches.subcommand_matches("sync") {
        sync_action(&cfg)?;
    }

    Ok(())
}

fn convert_sdk_action(paths: Vec<&str>, output_path: &str, compress: bool)
    -> Result<()>
{
    let dst_base = env::current_dir().unwrap().join(output_path);

    for (idx, path) in paths.iter().enumerate() {
        if idx > 0 {
            println!("");
        }
        let sdk = Sdk::new(&path)?;
        let mut dst = dst_base.join(sdk.info().memdb_filename());
        if compress {
            dst.set_extension("memdbz");
        }

        println!("SDK {} ({} {}):", sdk.info().name(),
                 sdk.info().version(), sdk.info().build().unwrap_or("UNKNONW"));

        // make sure we close the file at the end, in case we want to
        // re-open it for compressing.
        let f = fs::File::create(&dst)?;
        let options = DumpOptions {
            show_progress_bar: true,
            compress: compress,
            ..Default::default()
        };
        sdk.dump_memdb(f, options)?;
    }

    Ok(())
}

fn sync_action(config: &Config) -> Result<()> {
    let stash = MemDbStash::new(config)?;
    stash.sync(SyncOptions {
        user_facing: true,
        ..Default::default()
    })?;
    Ok(())
}

fn run_action(config: &Config, matches: &ArgMatches) -> Result<()> {
    let api_server = ApiServer::new(config)?;

    if !matches.is_present("disable_sync") {
        api_server.spawn_sync_thread()?;
    }

    let threads: usize = if let Some(threads) = matches.value_of("threads") {
        threads.parse().chain_err(|| "invalid value for threads")?
    } else {
        config.get_server_threads()?
    };

    api_server.run(threads, if let Some(addr) = matches.value_of("bind") {
        BindOptions::BindToAddr(addr)
    } else if let Some(fd) = matches.value_of("bind_fd") {
        BindOptions::BindToFd(fd.parse().chain_err(|| "invalid value for file descriptor")?)
    } else {
        BindOptions::UseConfig
    })?;

    Ok(())
}
<|endoftext|>


<commit_before>use cgmath::Matrix4;
use cgmath;
use character::controls::CharacterInputState;
use graphics::orientation::{Orientation, Stance};
use graphics::{Dimensions, get_orientation, is_collision};
use graphics::camera::CameraInputState;
use data;
use game::constants::{ASPECT_RATIO, RUN_SPRITE_OFFSET, CHARSHEET_TOTAL_WIDTH, SPRITE_OFFSET};
use shaders::{pipe, VertexData, CharacterSheet, Position, Projection};
use gfx;
use gfx_app::graphics::load_texture;
use gfx_app::mouse_controls::MouseInputState;
use gfx_app::{ColorFormat, DepthFormat};
use critter::{CharacterSprite, CritterData};
use specs;
use specs::{WriteStorage, Fetch};

mod audio;
pub mod controls;

const SHADER_VERT: &'static [u8] = include_bytes!("../shaders/character.v.glsl");
const SHADER_FRAG: &'static [u8] = include_bytes!("../shaders/character.f.glsl");

pub struct CharacterDrawable {
  projection: Projection,
  position: Position,
  orientation: Orientation,
  pub stance: Stance,
  direction: Orientation,
  audio: audio::CharacterAudio,
  pub is_collision: bool,
}

impl CharacterDrawable {
  pub fn new(view: Matrix4<f32>) -> CharacterDrawable {
    CharacterDrawable {
      projection: Projection {
        model: view.into(),
        view: view.into(),
        proj: cgmath::perspective(cgmath::Deg(60.0f32), ASPECT_RATIO, 0.1, 4000.0).into(),
      },
      position: Position {
        position: [0.0, 0.0],
      },
      orientation: Orientation::Right,
      stance: Stance::Walking,
      direction: Orientation::Right,
      audio: audio::CharacterAudio::new(),
      is_collision: false,
    }
  }

  pub fn update(&mut self, world_to_clip: &Projection, ci: &CharacterInputState, cs: &mut CharacterSprite, mouse_input: &mut MouseInputState) {
    self.projection = *world_to_clip;
    let new_position = Position {
      position: [ci.x_movement, ci.y_movement]
    };

    if mouse_input.left_click_point.is_some() {
      self.stance = Stance::Firing;
      self.orientation = get_orientation(mouse_input);
      if cs.character_fire_idx == 1 {
        self.audio.play_pistol();
      }
    } else {
      self.stance = Stance::Walking;
      let dx = new_position.position[0] - self.position.position[0];
      let dy = new_position.position[1] - self.position.position[1];
      self.orientation =
        if dx == 0.0 && dy < 0.0       { Orientation::Down }
        else if dx > 0.0 && dy < 0.0   { Orientation::DownRight }
        else if dx < 0.0 && dy < 0.0   { Orientation::DownLeft }
        else if dx == 0.0 && dy == 0.0 { Orientation::Still }
        else if dx > 0.0 && dy == 0.0  { Orientation::Right }
        else if dx < 0.0 && dy == 0.0  { Orientation::Left }
        else if dx == 0.0 && dy > 0.0  { Orientation::Up }
        else if dx > 0.0 && dy > 0.0   { Orientation::UpRight }
        else if dx < 0.0 && dy > 0.0   { Orientation::UpLeft }
        else { unreachable!() };

      if is_collision(new_position.position) {
        self.position = new_position;
        self.is_collision = false;
      } else {
        self.is_collision = true;
      }
    }
  }
}

impl specs::Component for CharacterDrawable {
  type Storage = specs::VecStorage<CharacterDrawable>;
}

pub struct CharacterDrawSystem<R: gfx::Resources> {
  bundle: gfx::pso::bundle::Bundle<R, pipe::Data<R>>,
  data: Vec<CritterData>,
}

impl<R: gfx::Resources> CharacterDrawSystem<R> {
  pub fn new<F>(factory: &mut F,
                rtv: gfx::handle::RenderTargetView<R, ColorFormat>,
                dsv: gfx::handle::DepthStencilView<R, DepthFormat>) -> CharacterDrawSystem<R>
    where F: gfx::Factory<R> {
    use gfx::traits::FactoryExt;

    let charter_bytes = &include_bytes!("../../assets/character.png")[..];

    let vertex_data: Vec<VertexData> =
      vec![
        VertexData::new([-20.0, -28.0, 0.0], [0.0, 1.0]),
        VertexData::new([20.0, -28.0, 0.0], [1.0, 1.0]),
        VertexData::new([20.0, 28.0, 0.0], [1.0, 0.0]),
        VertexData::new([-20.0, -28.0, 0.0], [0.0, 1.0]),
        VertexData::new([20.0, 28.0, 0.0], [1.0, 0.0]),
        VertexData::new([-20.0, 28.0, 0.0], [0.0, 0.0]),
      ];

    let (vertex_buf, slice) = factory.create_vertex_buffer_with_slice(&vertex_data, ());

    let char_texture = load_texture(factory, charter_bytes).unwrap();
    let pso = factory
      .create_pipeline_simple(SHADER_VERT,
                              SHADER_FRAG,
                              pipe::new())
      .unwrap();

    let pipeline_data = pipe::Data {
      vbuf: vertex_buf,
      projection_cb: factory.create_constant_buffer(1),
      position_cb: factory.create_constant_buffer(1),
      character_sprite_cb: factory.create_constant_buffer(1),
      charactersheet: (char_texture, factory.create_sampler_linear()),
      out_color: rtv,
      out_depth: dsv,
    };

    let data = data::load_character();

    CharacterDrawSystem {
      bundle: gfx::Bundle::new(slice, pso, pipeline_data),
      data
    }
  }

  fn get_next_sprite(&self, character_idx: usize, character_fire_idx: usize, drawable: &mut CharacterDrawable) -> CharacterSheet {
    let char_sprite =
      if drawable.orientation == Orientation::Still && drawable.stance == Stance::Walking {
        let sprite_idx = (drawable.direction as usize * 28 + RUN_SPRITE_OFFSET) as usize;
        (&self.data[sprite_idx], sprite_idx)
      } else if drawable.stance == Stance::Walking {
        drawable.direction = drawable.orientation;
        let sprite_idx = (drawable.orientation as usize * 28 + character_idx + RUN_SPRITE_OFFSET) as usize;
        (&self.data[sprite_idx], sprite_idx)
      } else {
        let sprite_idx = (drawable.orientation as usize * 8 + character_fire_idx) as usize;
        (&self.data[sprite_idx], sprite_idx)
      };

    let elements_x = CHARSHEET_TOTAL_WIDTH / (char_sprite.0.data[2] + SPRITE_OFFSET);
    CharacterSheet {
      div: elements_x,
      index: char_sprite.1 as f32
    }
  }

  pub fn draw<C>(&mut self,
                 mut drawable: &mut CharacterDrawable,
                 character: &CharacterSprite,
                 encoder: &mut gfx::Encoder<R, C>)
    where C: gfx::CommandBuffer<R> {
    encoder.update_constant_buffer(&self.bundle.data.projection_cb, &drawable.projection);
    encoder.update_constant_buffer(&self.bundle.data.position_cb, &drawable.position);
    encoder.update_constant_buffer(&self.bundle.data.character_sprite_cb,
                                   &self.get_next_sprite(character.character_idx,
                                                             character.character_fire_idx,
                                                             &mut drawable));
    self.bundle.encode(encoder);
  }
}

#[derive(Debug)]
pub struct PreDrawSystem;

impl PreDrawSystem {
  pub fn new() -> PreDrawSystem {
    PreDrawSystem {}
  }
}

impl<'a> specs::System<'a> for PreDrawSystem {
  type SystemData = (WriteStorage<'a, CharacterDrawable>,
                     WriteStorage<'a, CameraInputState>,
                     WriteStorage<'a, CharacterInputState>,
                     WriteStorage<'a, CharacterSprite>,
                     WriteStorage<'a, MouseInputState>,
                     Fetch<'a, Dimensions>);

  fn run(&mut self, (mut character, mut terrain_input, mut character_input, mut character_sprite, mut mouse_input, dim): Self::SystemData) {
    use specs::Join;

    for (c, ti, ci, cs, mi) in (&mut character, &mut terrain_input, &mut character_input, &mut character_sprite, &mut mouse_input).join() {
      let world_to_clip = dim.world_to_projection(ti);
      c.update(&world_to_clip, ci, cs, mi);
    }
  }
}
<commit_msg>Remove unnecessary "unreachable!" macro<commit_after>use cgmath::Matrix4;
use cgmath;
use character::controls::CharacterInputState;
use graphics::orientation::{Orientation, Stance};
use graphics::{Dimensions, get_orientation, is_collision};
use graphics::camera::CameraInputState;
use data;
use game::constants::{ASPECT_RATIO, RUN_SPRITE_OFFSET, CHARSHEET_TOTAL_WIDTH, SPRITE_OFFSET};
use shaders::{pipe, VertexData, CharacterSheet, Position, Projection};
use gfx;
use gfx_app::graphics::load_texture;
use gfx_app::mouse_controls::MouseInputState;
use gfx_app::{ColorFormat, DepthFormat};
use critter::{CharacterSprite, CritterData};
use specs;
use specs::{WriteStorage, Fetch};

mod audio;
pub mod controls;

const SHADER_VERT: &'static [u8] = include_bytes!("../shaders/character.v.glsl");
const SHADER_FRAG: &'static [u8] = include_bytes!("../shaders/character.f.glsl");

pub struct CharacterDrawable {
  projection: Projection,
  position: Position,
  orientation: Orientation,
  pub stance: Stance,
  direction: Orientation,
  audio: audio::CharacterAudio,
  pub is_collision: bool,
}

impl CharacterDrawable {
  pub fn new(view: Matrix4<f32>) -> CharacterDrawable {
    CharacterDrawable {
      projection: Projection {
        model: view.into(),
        view: view.into(),
        proj: cgmath::perspective(cgmath::Deg(60.0f32), ASPECT_RATIO, 0.1, 4000.0).into(),
      },
      position: Position {
        position: [0.0, 0.0],
      },
      orientation: Orientation::Right,
      stance: Stance::Walking,
      direction: Orientation::Right,
      audio: audio::CharacterAudio::new(),
      is_collision: false,
    }
  }

  pub fn update(&mut self, world_to_clip: &Projection, ci: &CharacterInputState, cs: &mut CharacterSprite, mouse_input: &mut MouseInputState) {
    self.projection = *world_to_clip;
    let new_position = Position {
      position: [ci.x_movement, ci.y_movement]
    };

    if mouse_input.left_click_point.is_some() {
      self.stance = Stance::Firing;
      self.orientation = get_orientation(mouse_input);
      if cs.character_fire_idx == 1 {
        self.audio.play_pistol();
      }
    } else {
      self.stance = Stance::Walking;
      let dx = new_position.position[0] - self.position.position[0];
      let dy = new_position.position[1] - self.position.position[1];
      self.orientation =
        if dx == 0.0 && dy < 0.0       { Orientation::Down }
        else if dx > 0.0 && dy < 0.0   { Orientation::DownRight }
        else if dx < 0.0 && dy < 0.0   { Orientation::DownLeft }
        else if dx == 0.0 && dy == 0.0 { Orientation::Still }
        else if dx > 0.0 && dy == 0.0  { Orientation::Right }
        else if dx < 0.0 && dy == 0.0  { Orientation::Left }
        else if dx == 0.0 && dy > 0.0  { Orientation::Up }
        else if dx > 0.0 && dy > 0.0   { Orientation::UpRight }
        else if dx < 0.0 && dy > 0.0   { Orientation::UpLeft }
        else { Orientation::Still };

      if is_collision(new_position.position) {
        self.position = new_position;
        self.is_collision = false;
      } else {
        self.is_collision = true;
      }
    }
  }
}

impl specs::Component for CharacterDrawable {
  type Storage = specs::VecStorage<CharacterDrawable>;
}

pub struct CharacterDrawSystem<R: gfx::Resources> {
  bundle: gfx::pso::bundle::Bundle<R, pipe::Data<R>>,
  data: Vec<CritterData>,
}

impl<R: gfx::Resources> CharacterDrawSystem<R> {
  pub fn new<F>(factory: &mut F,
                rtv: gfx::handle::RenderTargetView<R, ColorFormat>,
                dsv: gfx::handle::DepthStencilView<R, DepthFormat>) -> CharacterDrawSystem<R>
    where F: gfx::Factory<R> {
    use gfx::traits::FactoryExt;

    let charter_bytes = &include_bytes!("../../assets/character.png")[..];

    let vertex_data: Vec<VertexData> =
      vec![
        VertexData::new([-20.0, -28.0, 0.0], [0.0, 1.0]),
        VertexData::new([20.0, -28.0, 0.0], [1.0, 1.0]),
        VertexData::new([20.0, 28.0, 0.0], [1.0, 0.0]),
        VertexData::new([-20.0, -28.0, 0.0], [0.0, 1.0]),
        VertexData::new([20.0, 28.0, 0.0], [1.0, 0.0]),
        VertexData::new([-20.0, 28.0, 0.0], [0.0, 0.0]),
      ];

    let (vertex_buf, slice) = factory.create_vertex_buffer_with_slice(&vertex_data, ());

    let char_texture = load_texture(factory, charter_bytes).unwrap();
    let pso = factory
      .create_pipeline_simple(SHADER_VERT,
                              SHADER_FRAG,
                              pipe::new())
      .unwrap();

    let pipeline_data = pipe::Data {
      vbuf: vertex_buf,
      projection_cb: factory.create_constant_buffer(1),
      position_cb: factory.create_constant_buffer(1),
      character_sprite_cb: factory.create_constant_buffer(1),
      charactersheet: (char_texture, factory.create_sampler_linear()),
      out_color: rtv,
      out_depth: dsv,
    };

    let data = data::load_character();

    CharacterDrawSystem {
      bundle: gfx::Bundle::new(slice, pso, pipeline_data),
      data
    }
  }

  fn get_next_sprite(&self, character_idx: usize, character_fire_idx: usize, drawable: &mut CharacterDrawable) -> CharacterSheet {
    let char_sprite =
      if drawable.orientation == Orientation::Still && drawable.stance == Stance::Walking {
        let sprite_idx = (drawable.direction as usize * 28 + RUN_SPRITE_OFFSET) as usize;
        (&self.data[sprite_idx], sprite_idx)
      } else if drawable.stance == Stance::Walking {
        drawable.direction = drawable.orientation;
        let sprite_idx = (drawable.orientation as usize * 28 + character_idx + RUN_SPRITE_OFFSET) as usize;
        (&self.data[sprite_idx], sprite_idx)
      } else {
        let sprite_idx = (drawable.orientation as usize * 8 + character_fire_idx) as usize;
        (&self.data[sprite_idx], sprite_idx)
      };

    let elements_x = CHARSHEET_TOTAL_WIDTH / (char_sprite.0.data[2] + SPRITE_OFFSET);
    CharacterSheet {
      div: elements_x,
      index: char_sprite.1 as f32
    }
  }

  pub fn draw<C>(&mut self,
                 mut drawable: &mut CharacterDrawable,
                 character: &CharacterSprite,
                 encoder: &mut gfx::Encoder<R, C>)
    where C: gfx::CommandBuffer<R> {
    encoder.update_constant_buffer(&self.bundle.data.projection_cb, &drawable.projection);
    encoder.update_constant_buffer(&self.bundle.data.position_cb, &drawable.position);
    encoder.update_constant_buffer(&self.bundle.data.character_sprite_cb,
                                   &self.get_next_sprite(character.character_idx,
                                                             character.character_fire_idx,
                                                             &mut drawable));
    self.bundle.encode(encoder);
  }
}

#[derive(Debug)]
pub struct PreDrawSystem;

impl PreDrawSystem {
  pub fn new() -> PreDrawSystem {
    PreDrawSystem {}
  }
}

impl<'a> specs::System<'a> for PreDrawSystem {
  type SystemData = (WriteStorage<'a, CharacterDrawable>,
                     WriteStorage<'a, CameraInputState>,
                     WriteStorage<'a, CharacterInputState>,
                     WriteStorage<'a, CharacterSprite>,
                     WriteStorage<'a, MouseInputState>,
                     Fetch<'a, Dimensions>);

  fn run(&mut self, (mut character, mut terrain_input, mut character_input, mut character_sprite, mut mouse_input, dim): Self::SystemData) {
    use specs::Join;

    for (c, ti, ci, cs, mi) in (&mut character, &mut terrain_input, &mut character_input, &mut character_sprite, &mut mouse_input).join() {
      let world_to_clip = dim.world_to_projection(ti);
      c.update(&world_to_clip, ci, cs, mi);
    }
  }
}
<|endoftext|>


<commit_before>use std::path::Path;
use error::ProbeError;
use super::Result;

/// Measurement of cpu stats at a certain time
#[derive(Debug,PartialEq)]
pub struct CpuMeasurement {
    pub precise_time_ns: u64,
    pub user: u64,
    pub nice: u64,
    pub system: u64,
    pub idle: u64,
    pub iowait: u64
}

impl CpuMeasurement {
    /// Calculate the cpu stats based on this measurement and a measurement in the future.
    /// It is advisable to make the next measurement roughly a minute from this one for the
    /// most reliable result.
    pub fn calculate_per_minute(&self, next_measurement: &CpuMeasurement) -> Result<CpuStat> {
        if next_measurement.precise_time_ns < self.precise_time_ns {
            return Err(ProbeError::InvalidInput("time of next measurement was before time of this one".to_string()))
        }

        let time_difference = next_measurement.precise_time_ns - self.precise_time_ns;

        Ok(CpuStat {
            user: try!(super::time_adjusted(next_measurement.user, self.user, time_difference)),
            nice: try!(super::time_adjusted(next_measurement.nice, self.nice, time_difference)),
            system: try!(super::time_adjusted(next_measurement.system, self.system, time_difference)),
            idle: try!(super::time_adjusted(next_measurement.idle, self.idle, time_difference)),
            iowait: try!(super::time_adjusted(next_measurement.iowait, self.iowait, time_difference))
        })
    }
}

/// Cpu stats for a minute
#[derive(Debug,PartialEq)]
pub struct CpuStat {
    pub user: u64,
    pub nice: u64,
    pub system: u64,
    pub idle: u64,
    pub iowait: u64
}

#[cfg(target_os = "linux")]
pub fn read() -> Result<CpuMeasurement> {
    // columns: user nice system idle iowait irq softirq
    os::read_proc_cpu_stat(&Path::new("/proc/stat"))
}

#[cfg(target_os = "linux")]
mod os {
    use std::path::Path;
    use std::io::BufRead;
    use time;
    use super::super::{Result,file_to_buf_reader};
    use super::CpuMeasurement;
    use error::ProbeError;

    pub fn read_proc_cpu_stat(path: &Path) -> Result<CpuMeasurement> {
        let mut line = String::new();
        let mut reader = try!(file_to_buf_reader(path));
        let time = time::precise_time_ns();
        try!(reader.read_line(&mut line));

        let stats: Vec<&str> = line
            .split_whitespace()
            .skip(1)
            .collect();

        if stats.len() < 5 {
            return Err(ProbeError::UnexpectedContent("Incorrect number of stats".to_owned()));
        }

        Ok(CpuMeasurement {
            precise_time_ns: time,
            user: try!(parse_stat(stats[0])),
            nice: try!(parse_stat(stats[1])),
            system: try!(parse_stat(stats[2])),
            idle: try!(parse_stat(stats[3])),
            iowait: try!(parse_stat(stats[4]))
        })
    }

    fn parse_stat(stat: &str) -> Result<u64> {
        stat.parse().map_err(|_| {
            ProbeError::UnexpectedContent(format!("Could not parse stat {:?}", stat).to_owned())
        })
    }
}

#[cfg(test)]
mod test {
    use super::{CpuMeasurement,CpuStat};
    use super::os::read_proc_cpu_stat;
    use std::path::Path;
    use error::ProbeError;

    #[test]
    fn test_read_cpu_measurement() {
        let measurement = read_proc_cpu_stat(&Path::new("fixtures/linux/cpu_stat/proc_cpu_stat")).unwrap();
        assert_eq!(measurement.user, 0);
        assert_eq!(measurement.nice, 1);
        assert_eq!(measurement.system, 2);
        assert_eq!(measurement.idle, 3);
        assert_eq!(measurement.iowait, 4);
    }

    #[test]
    fn test_wrong_path() {
        match read_proc_cpu_stat(&Path::new("bananas")) {
            Err(ProbeError::IO(_)) => (),
            r => panic!("Unexpected result: {:?}", r)
        }
    }

    #[test]
    fn test_incomplete() {
        match read_proc_cpu_stat(&Path::new("fixtures/linux/cpu_stat/proc_cpu_stat_incomplete")) {
            Err(ProbeError::UnexpectedContent(_)) => (),
            r => panic!("Unexpected result: {:?}", r)
        }
    }

    #[test]
    fn test_read_and_parse_cpu_stat_garbage() {
        let path = Path::new("fixtures/linux/cpu_stat/proc_cpu_stat_garbage");
        match read_proc_cpu_stat(&path) {
            Err(ProbeError::UnexpectedContent(_)) => (),
            r => panic!("Unexpected result: {:?}", r)
        }
    }

    #[test]
    fn test_calculate_per_minute_wrong_times() {
        let measurement1 = CpuMeasurement {
            precise_time_ns: 90_000_000,
            user: 0,
            nice: 0,
            system: 0,
            idle: 0,
            iowait: 0
        };

        let measurement2 = CpuMeasurement {
            precise_time_ns: 60_000_000,
            user: 0,
            nice: 0,
            system: 0,
            idle: 0,
            iowait: 0
        };

        match measurement1.calculate_per_minute(&measurement2) {
            Err(ProbeError::InvalidInput(_)) => (),
            r => panic!("Unexpected result: {:?}", r)
        }
    }

    #[test]
    fn test_calculate_per_minute_full_minute() {
        let measurement1 = CpuMeasurement {
            precise_time_ns: 60_000_000,
            user: 1000,
            nice: 1100,
            system: 1200,
            idle: 1300,
            iowait: 1400
        };

        let measurement2 = CpuMeasurement {
            precise_time_ns: 120_000_000,
            user: 1006,
            nice: 1106,
            system: 1206,
            idle: 1306,
            iowait: 1406
        };

        let expected = CpuStat {
            user: 6,
            nice: 6,
            system: 6,
            idle: 6,
            iowait: 6
        };

        let stat = measurement1.calculate_per_minute(&measurement2).unwrap();

        assert_eq!(stat, expected);
    }

    #[test]
    fn test_calculate_per_minute_partial_minute() {
        let measurement1 = CpuMeasurement {
            precise_time_ns: 60_000_000,
            user: 1000,
            nice: 1100,
            system: 1200,
            idle: 1300,
            iowait: 1400
        };

        let measurement2 = CpuMeasurement {
            precise_time_ns: 90_000_000,
            user: 1006,
            nice: 1106,
            system: 1206,
            idle: 1306,
            iowait: 1406
        };

        let expected = CpuStat {
            user: 3,
            nice: 3,
            system: 3,
            idle: 3,
            iowait: 3
        };

        let stat = measurement1.calculate_per_minute(&measurement2).unwrap();

        assert_eq!(stat, expected);
    }

    #[test]
    fn test_calculate_per_minute_values_lower() {
        let measurement1 = CpuMeasurement {
            precise_time_ns: 60_000_000,
            user: 1000,
            nice: 1100,
            system: 1200,
            idle: 1300,
            iowait: 1400
        };

        let measurement2 = CpuMeasurement {
            precise_time_ns: 90_000_000,
            user: 106,
            nice: 116,
            system: 126,
            idle: 136,
            iowait: 146
        };

        match measurement1.calculate_per_minute(&measurement2) {
            Err(ProbeError::UnexpectedContent(_)) => (),
            r => panic!("Unexpected result: {:?}", r)
        }
    }
}
<commit_msg>Calculate cpu stats in percentages<commit_after>use std::path::Path;
use error::ProbeError;
use super::Result;

/// Measurement of cpu stats at a certain time
#[derive(Debug,PartialEq)]
pub struct CpuMeasurement {
    pub precise_time_ns: u64,
    pub user: u64,
    pub nice: u64,
    pub system: u64,
    pub idle: u64,
    pub iowait: u64
}

impl CpuMeasurement {
    /// Calculate the cpu stats based on this measurement and a measurement in the future.
    /// It is advisable to make the next measurement roughly a minute from this one for the
    /// most reliable result.
    pub fn calculate_per_minute(&self, next_measurement: &CpuMeasurement) -> Result<CpuStat> {
        if next_measurement.precise_time_ns < self.precise_time_ns {
            return Err(ProbeError::InvalidInput("time of next measurement was before time of this one".to_string()))
        }

        let time_difference = next_measurement.precise_time_ns - self.precise_time_ns;

        Ok(CpuStat {
            user: try!(super::time_adjusted(next_measurement.user, self.user, time_difference)),
            nice: try!(super::time_adjusted(next_measurement.nice, self.nice, time_difference)),
            system: try!(super::time_adjusted(next_measurement.system, self.system, time_difference)),
            idle: try!(super::time_adjusted(next_measurement.idle, self.idle, time_difference)),
            iowait: try!(super::time_adjusted(next_measurement.iowait, self.iowait, time_difference))
        })
    }
}

/// Cpu stats for a minute
#[derive(Debug,PartialEq)]
pub struct CpuStat {
    pub user: u64,
    pub nice: u64,
    pub system: u64,
    pub idle: u64,
    pub iowait: u64
}

impl CpuStat {
    /// Calculate the weight of the various components in percentages
    pub fn in_percentages(&self) -> CpuStatPercentages {
        let total = (self.user + self.system + self.idle) as f64;

        CpuStatPercentages {
            user: Self::percentage_of_total(self.user, total),
            nice: Self::percentage_of_total(self.nice, total),
            system: Self::percentage_of_total(self.system, total),
            idle: Self::percentage_of_total(self.idle, total),
            iowait: Self::percentage_of_total(self.iowait, total)
        }
    }

    fn percentage_of_total(value: u64, total: f64) -> f32 {
        (value as f64 / total * 100.0) as f32
    }
}

/// Cpu stats converted to percentages
#[derive(Debug,PartialEq)]
pub struct CpuStatPercentages {
    pub user: f32,
    pub nice: f32,
    pub system: f32,
    pub idle: f32,
    pub iowait: f32
}

#[cfg(target_os = "linux")]
pub fn read() -> Result<CpuMeasurement> {
    // columns: user nice system idle iowait irq softirq
    os::read_proc_cpu_stat(&Path::new("/proc/stat"))
}

#[cfg(target_os = "linux")]
mod os {
    use std::path::Path;
    use std::io::BufRead;
    use time;
    use super::super::{Result,file_to_buf_reader};
    use super::CpuMeasurement;
    use error::ProbeError;

    pub fn read_proc_cpu_stat(path: &Path) -> Result<CpuMeasurement> {
        let mut line = String::new();
        let mut reader = try!(file_to_buf_reader(path));
        let time = time::precise_time_ns();
        try!(reader.read_line(&mut line));

        let stats: Vec<&str> = line
            .split_whitespace()
            .skip(1)
            .collect();

        if stats.len() < 5 {
            return Err(ProbeError::UnexpectedContent("Incorrect number of stats".to_owned()));
        }

        Ok(CpuMeasurement {
            precise_time_ns: time,
            user: try!(parse_stat(stats[0])),
            nice: try!(parse_stat(stats[1])),
            system: try!(parse_stat(stats[2])),
            idle: try!(parse_stat(stats[3])),
            iowait: try!(parse_stat(stats[4]))
        })
    }

    fn parse_stat(stat: &str) -> Result<u64> {
        stat.parse().map_err(|_| {
            ProbeError::UnexpectedContent(format!("Could not parse stat {:?}", stat).to_owned())
        })
    }
}

#[cfg(test)]
mod test {
    use super::{CpuMeasurement,CpuStat,CpuStatPercentages};
    use super::os::read_proc_cpu_stat;
    use std::path::Path;
    use error::ProbeError;

    #[test]
    fn test_read_cpu_measurement() {
        let measurement = read_proc_cpu_stat(&Path::new("fixtures/linux/cpu_stat/proc_cpu_stat")).unwrap();
        assert_eq!(measurement.user, 0);
        assert_eq!(measurement.nice, 1);
        assert_eq!(measurement.system, 2);
        assert_eq!(measurement.idle, 3);
        assert_eq!(measurement.iowait, 4);
    }

    #[test]
    fn test_wrong_path() {
        match read_proc_cpu_stat(&Path::new("bananas")) {
            Err(ProbeError::IO(_)) => (),
            r => panic!("Unexpected result: {:?}", r)
        }
    }

    #[test]
    fn test_incomplete() {
        match read_proc_cpu_stat(&Path::new("fixtures/linux/cpu_stat/proc_cpu_stat_incomplete")) {
            Err(ProbeError::UnexpectedContent(_)) => (),
            r => panic!("Unexpected result: {:?}", r)
        }
    }

    #[test]
    fn test_read_and_parse_cpu_stat_garbage() {
        let path = Path::new("fixtures/linux/cpu_stat/proc_cpu_stat_garbage");
        match read_proc_cpu_stat(&path) {
            Err(ProbeError::UnexpectedContent(_)) => (),
            r => panic!("Unexpected result: {:?}", r)
        }
    }

    #[test]
    fn test_calculate_per_minute_wrong_times() {
        let measurement1 = CpuMeasurement {
            precise_time_ns: 90_000_000,
            user: 0,
            nice: 0,
            system: 0,
            idle: 0,
            iowait: 0
        };

        let measurement2 = CpuMeasurement {
            precise_time_ns: 60_000_000,
            user: 0,
            nice: 0,
            system: 0,
            idle: 0,
            iowait: 0
        };

        match measurement1.calculate_per_minute(&measurement2) {
            Err(ProbeError::InvalidInput(_)) => (),
            r => panic!("Unexpected result: {:?}", r)
        }
    }

    #[test]
    fn test_calculate_per_minute_full_minute() {
        let measurement1 = CpuMeasurement {
            precise_time_ns: 60_000_000,
            user: 1000,
            nice: 1100,
            system: 1200,
            idle: 1300,
            iowait: 1400
        };

        let measurement2 = CpuMeasurement {
            precise_time_ns: 120_000_000,
            user: 1006,
            nice: 1106,
            system: 1206,
            idle: 1306,
            iowait: 1406
        };

        let expected = CpuStat {
            user: 6,
            nice: 6,
            system: 6,
            idle: 6,
            iowait: 6
        };

        let stat = measurement1.calculate_per_minute(&measurement2).unwrap();

        assert_eq!(stat, expected);
    }

    #[test]
    fn test_calculate_per_minute_partial_minute() {
        let measurement1 = CpuMeasurement {
            precise_time_ns: 60_000_000,
            user: 1000,
            nice: 1100,
            system: 1200,
            idle: 1300,
            iowait: 1400
        };

        let measurement2 = CpuMeasurement {
            precise_time_ns: 90_000_000,
            user: 1006,
            nice: 1106,
            system: 1206,
            idle: 1306,
            iowait: 1406
        };

        let expected = CpuStat {
            user: 3,
            nice: 3,
            system: 3,
            idle: 3,
            iowait: 3
        };

        let stat = measurement1.calculate_per_minute(&measurement2).unwrap();

        assert_eq!(stat, expected);
    }

    #[test]
    fn test_calculate_per_minute_values_lower() {
        let measurement1 = CpuMeasurement {
            precise_time_ns: 60_000_000,
            user: 1000,
            nice: 1100,
            system: 1200,
            idle: 1300,
            iowait: 1400
        };

        let measurement2 = CpuMeasurement {
            precise_time_ns: 90_000_000,
            user: 106,
            nice: 116,
            system: 126,
            idle: 136,
            iowait: 146
        };

        match measurement1.calculate_per_minute(&measurement2) {
            Err(ProbeError::UnexpectedContent(_)) => (),
            r => panic!("Unexpected result: {:?}", r)
        }
    }

    #[test]
    fn test_in_percentages() {
        let stat = CpuStat {
            user: 500,
            nice: 100,
            system: 250,
            idle: 250,
            iowait: 100
        };

        let expected = CpuStatPercentages {
            user: 50.0,
            nice: 10.0,
            system: 25.0,
            idle: 25.0,
            iowait: 10.0
        };

        assert_eq!(stat.in_percentages(), expected);
    }

    #[test]
    fn test_in_percentages_fractions() {
        let stat = CpuStat {
            user: 495,
            nice: 100,
            system: 250,
            idle: 255,
            iowait: 100
        };

        let expected = CpuStatPercentages {
            user: 49.5,
            nice: 10.0,
            system: 25.0,
            idle: 25.5,
            iowait: 10.0
        };

        assert_eq!(stat.in_percentages(), expected);
    }
}
<|endoftext|>


<commit_before>pub use self::imp::*;

#[cfg(not(cross_platform_docs))]
mod imp {
    pub use core::option::Option;
    pub use core::clone::Clone;
    pub use core::marker::Copy;
    pub use core::mem;
}

#[cfg(cross_platform_docs)]
mod imp {
    pub enum Option<T> {
        Some(T),
        None,
    }
    impl<T: Copy> Copy for Option<T> {}
    impl<T: Clone> Clone for Option<T> {
        fn clone(&self) -> Option<T> { loop {} }
    }

    pub trait Clone {
        fn clone(&self) -> Self;
    }

    #[lang = "copy"]
    pub trait Copy {}

    #[lang = "freeze"]
    pub trait Freeze {}

    #[lang = "sync"]
    pub trait Sync {}
    impl<T> Sync for T {}

    #[lang = "sized"]
    pub trait Sized {}

    macro_rules! each_int {
        ($mac:ident) => (
            $mac!(u8);
            $mac!(u16);
            $mac!(u32);
            $mac!(u64);
            $mac!(usize);
            each_signed_int!($mac);
        )
    }

    macro_rules! each_signed_int {
        ($mac:ident) => (
            $mac!(i8);
            $mac!(i16);
            $mac!(i32);
            $mac!(i64);
            $mac!(isize);
        )
    }

    #[lang = "div"]
    pub trait Div<RHS> {
        type Output;
        fn div(self, rhs: RHS) -> Self::Output;
    }

    #[lang = "shl"]
    pub trait Shl<RHS> {
        type Output;
        fn shl(self, rhs: RHS) -> Self::Output;
    }

    #[lang = "mul"]
    pub trait Mul<RHS=Self> {
        type Output;
        fn mul(self, rhs: RHS) -> Self::Output;
    }

    #[lang = "sub"]
    pub trait Sub<RHS=Self> {
        type Output;
        fn sub(self, rhs: RHS) -> Self::Output;
    }

    #[lang = "bitor"]
    pub trait Bitor<RHS=Self> {
        type Output;
        fn bitor(self, rhs: RHS) -> Self::Output;
    }

    #[lang = "neg"]
    pub trait Neg {
        type Output;
        fn neg(self) -> Self::Output;
    }

    #[lang = "not"]
    pub trait Not {
        type Output;
        fn not(self) -> Self::Output;
    }

    #[lang = "add"]
    pub trait Add<RHS = Self> {
        type Output;
        fn add(self, r: RHS) -> Self::Output;
    }

    macro_rules! impl_traits {
        ($($i:ident)*) => ($(
            impl Div<$i> for $i {
                type Output = $i;
                fn div(self, rhs: $i) -> $i { self / rhs }
            }
            impl Shl<$i> for $i {
                type Output = $i;
                fn shl(self, rhs: $i) -> $i { self << rhs }
            }
            impl Mul for $i {
                type Output = $i;
                fn mul(self, rhs: $i) -> $i { self * rhs }
            }

            impl Sub for $i {
                type Output = $i;
                fn sub(self, rhs: $i) -> $i { self - rhs }
            }
            impl Bitor for $i {
                type Output = $i;
                fn bitor(self, rhs: $i) -> $i { self | rhs }
            }
            impl Neg for $i {
                type Output = $i;
                fn neg(self) -> $i { -self }
            }
            impl Not for $i {
                type Output = $i;
                fn not(self) -> $i { !self }
            }
            impl Add<$i> for $i {
                type Output = $i;
                fn add(self, other: $i) -> $i { self + other }
            }
        )*)
    }
    each_int!(impl_traits);

    pub mod mem {
        pub fn size_of_val<T>(_: &T) -> usize { 4 }
        pub fn size_of<T>(_: &T) -> usize { 4 }
    }
}
<commit_msg>Auto merge of #962 - glandium:dox, r=alexcrichton<commit_after>pub use self::imp::*;

#[cfg(not(cross_platform_docs))]
mod imp {
    pub use core::option::Option;
    pub use core::clone::Clone;
    pub use core::marker::Copy;
    pub use core::mem;
}

#[cfg(cross_platform_docs)]
mod imp {
    pub enum Option<T> {
        Some(T),
        None,
    }
    impl<T: Copy> Copy for Option<T> {}
    impl<T: Clone> Clone for Option<T> {
        fn clone(&self) -> Option<T> { loop {} }
    }

    impl<T> Copy for *mut T {}
    impl<T> Clone for *mut T {
        fn clone(&self) -> *mut T { loop {} }
    }

    impl<T> Copy for *const T {}
    impl<T> Clone for *const T {
        fn clone(&self) -> *const T { loop {} }
    }

    pub trait Clone {
        fn clone(&self) -> Self;
    }

    #[lang = "copy"]
    pub trait Copy {}

    #[lang = "freeze"]
    pub trait Freeze {}

    #[lang = "sync"]
    pub trait Sync {}
    impl<T> Sync for T {}

    #[lang = "sized"]
    pub trait Sized {}

    macro_rules! each_int {
        ($mac:ident) => (
            $mac!(u8);
            $mac!(u16);
            $mac!(u32);
            $mac!(u64);
            $mac!(usize);
            each_signed_int!($mac);
        )
    }

    macro_rules! each_signed_int {
        ($mac:ident) => (
            $mac!(i8);
            $mac!(i16);
            $mac!(i32);
            $mac!(i64);
            $mac!(isize);
        )
    }

    #[lang = "div"]
    pub trait Div<RHS> {
        type Output;
        fn div(self, rhs: RHS) -> Self::Output;
    }

    #[lang = "shl"]
    pub trait Shl<RHS> {
        type Output;
        fn shl(self, rhs: RHS) -> Self::Output;
    }

    #[lang = "mul"]
    pub trait Mul<RHS=Self> {
        type Output;
        fn mul(self, rhs: RHS) -> Self::Output;
    }

    #[lang = "sub"]
    pub trait Sub<RHS=Self> {
        type Output;
        fn sub(self, rhs: RHS) -> Self::Output;
    }

    #[lang = "bitor"]
    pub trait Bitor<RHS=Self> {
        type Output;
        fn bitor(self, rhs: RHS) -> Self::Output;
    }

    #[lang = "neg"]
    pub trait Neg {
        type Output;
        fn neg(self) -> Self::Output;
    }

    #[lang = "not"]
    pub trait Not {
        type Output;
        fn not(self) -> Self::Output;
    }

    #[lang = "add"]
    pub trait Add<RHS = Self> {
        type Output;
        fn add(self, r: RHS) -> Self::Output;
    }

    macro_rules! impl_traits {
        ($($i:ident)*) => ($(
            impl Div<$i> for $i {
                type Output = $i;
                fn div(self, rhs: $i) -> $i { self / rhs }
            }
            impl Shl<$i> for $i {
                type Output = $i;
                fn shl(self, rhs: $i) -> $i { self << rhs }
            }
            impl Mul for $i {
                type Output = $i;
                fn mul(self, rhs: $i) -> $i { self * rhs }
            }

            impl Sub for $i {
                type Output = $i;
                fn sub(self, rhs: $i) -> $i { self - rhs }
            }
            impl Bitor for $i {
                type Output = $i;
                fn bitor(self, rhs: $i) -> $i { self | rhs }
            }
            impl Neg for $i {
                type Output = $i;
                fn neg(self) -> $i { -self }
            }
            impl Not for $i {
                type Output = $i;
                fn not(self) -> $i { !self }
            }
            impl Add<$i> for $i {
                type Output = $i;
                fn add(self, other: $i) -> $i { self + other }
            }
            impl Copy for $i {}
            impl Clone for $i {
                fn clone(&self) -> $i { loop {} }
            }
        )*)
    }
    each_int!(impl_traits);

    pub mod mem {
        pub fn size_of_val<T>(_: &T) -> usize { 4 }
        pub fn size_of<T>(_: &T) -> usize { 4 }
    }
}
<|endoftext|>


<commit_before>//types
use std::error::Error;
use std::fs::File;
use std::io::BufReader;
use std::io::BufRead;
use std::env;
//traits
use std::io::Read;

#[allow(non_snake_case)]
#[allow(non_camel_case_types)]
#[allow(dead_code)]
pub struct CPU {
    //Registers

    //Program Counter
    PC: u16,

    //Stack pointer
    S: u8,

    //Processor status
    P: u8,

    //Accumulator
    A: u8,

    //Index register X
    X: u8,

    //Index register Y
    Y: u8,

    //Memory: FFFF, https://en.wikibooks.org/wiki/NES_Programming/Memory_Map
    //Address   Size    Desc.
    //$0000     $800    2KB of work RAM
    //$0800     $800    Mirror of $000-$7FF
    //$1000     $800    Mirror of $000-$7FF
    //$1800     $800    Mirror of $000-$7FF
    //$2000     8       PPU Ctrl Registers
    //$2008     $1FF8   *Mirror of $2000-$2007
    //$4000     $20     Registers (Mostly APU)
    //$4020     $1FDF   Cartridge Expansion ROM
    //$6000     $2000   SRAM
    //$8000     $4000   PRG-ROM
    //$C000     $4000   PRG-ROM
    //
    //this size is without any mirrors
    mem: Vec<u8>,

    //Debug string
    debug: String,
}

#[allow(non_camel_case_types)]
#[allow(dead_code)]
enum mem_map {
    internal_ram,
    ppu_registers,
    apu_io_registers,
    cartridge_space,
}

/*struct instruction {
    //Short form instruction name
    name: &'static str,

    //Opcode
    opcode: u8,

    //Cycles to fully decode instruction
    length: u8,

    //Cycles to complete instruction
    cycles: u8,

    //Closure that executes the instruction
    execute: ||,
}*/

#[allow(non_snake_case)]
#[allow(dead_code)]
impl CPU {
    pub fn new() -> CPU {
        let mut _mem = Vec::with_capacity(0xFFFF);
        for _ in 0..0xFFFF {
            _mem.push(0);
        }
        let mut _PC = 0;
        let mut _S = 0xFD;
        let mut _P = 0;
        let mut _A = 0;
        let mut _X = 0;
        let mut _Y = 0;
        let mut _debug :String = "".to_owned();

        CPU {
            PC: _PC,
            S: _S,
            P: _P,
            A: _A,
            X: _X,
            Y: _Y,
            mem: _mem,
            debug: _debug,
        }
    }

    // run a program
    pub fn test_load(&mut self, program: &str) {
        let path = env::current_dir().unwrap().join(program);
        let f = match File::open(&path) {
            Err(why) => panic!("Couldn't open {:?}: {}", path, Error::description(&why)),
            Ok(file) => file,
        };

        let mut i = 0;
        let mut program_mem: Vec<u8> = Vec::new();
        for byte in f.bytes() {
            let curr = match byte {
                Err(_) => return, //EOF
                Ok(byte) => byte,
            };

            i = i + 1;
            //skip the header information
            //only the PRG ROM for testing CPU
            if i > 16 && i <= 16400 {
                program_mem.push(curr);
            }
        }
        self.set_mem(mem_map::cartridge_space, &mut program_mem);
        self.PC = 0xC000;
        self.P = 0x24;
    }

    pub fn test_run(&mut self, log: &str) {
        //for some reason cargo indents the first line of output
        println!("");

        let path = env::current_dir().unwrap().join(log);
        let f = match File::open(&log) {
            Err(why) => panic!("Couldn't open {:?}: {}", path, Error::description(&why)),
            Ok(file) => file,
        };

        let file = BufReader::new(&f);

        for line in file.lines() {
            let mut curr_line = match line {
                Err(why) => panic!("Couldn't read line from {:?}: {}", path, Error::description(&why)),
                Ok(line) => line,
            };

            let instr = self.fetch_instr();
            self.execute_instr(&instr);

            curr_line.truncate(73);
            //println!("Log   line:{}", curr_line);
            //println!("Debug line:{}", self.debug);
            assert_eq!(self.debug, curr_line);
        }
    }

    pub fn run(&mut self) {
        loop {
            let instr = self.fetch_instr();
            self.execute_instr(&instr);
        }
    }

    fn fetch_instr(&mut self) -> u8 {
        let instr = self.mem[self.PC as usize];
        self.debug = format!("{:04X}  {:02X} ", self.PC, instr);
        self.PC = self.PC + 1;
        instr
    }

    fn execute_instr(&mut self, instr: &u8) {
        match *instr {
            0x4C => {
                let operand = self.read_absolute();
                self.debug.push_str(&format!("{:02X} {:02X}  JMP ${:04X}                       ", operand as u8, operand >> 8 as u8, operand));
                self.print_registers();
                self.JMP(&operand);
            },
            0x86 => {
                let operand = self.read_zeropage();
                self.debug.push_str(&format!("{:02X}     STX ${:02X} = {:02X}                    ", operand, operand, self.X));
                self.print_registers();
                self.STX(&operand);
            },
            0xA2 => {
                let operand = self.read_immediate();
                self.debug.push_str(&format!("{:02X}     LDX #${:02X}                        ", operand, operand));
                self.print_registers();
                self.LDX(&operand);
            },
            _ => {
                println!("NOT IMPLEMENTED YET");
            },
        }
    }

    fn print_registers(&mut self) {
        self.debug.push_str(&format!("A:{:02X} X:{:02X} Y:{:02X} P:{:02X} SP:{:02X}", self.A, self.X, self.Y, self.P, self.S));
    }

    fn set_zero_flag(&mut self) {
        self.P |= 0x02;
    }

    fn set_neg_flag(&mut self) {
        self.P |= 0x080;
    }

    fn read_absolute(&mut self) -> u16 {
        let mem = (self.mem[self.PC as usize] as u16) | ((self.mem[(self.PC + 1) as usize]) as u16 ) << 8;
        self.PC = self.PC + 2;
        mem
    }

    fn read_immediate(&mut self) -> u8 {
        let mem = self.mem[self.PC as usize];
        self.PC = self.PC + 1;
        mem
    }

    fn read_zeropage(&mut self) -> u8 {
        let mem = self.mem[self.PC as usize];
        self.PC = self.PC + 1;
        mem
    }

    fn set_mem(&mut self, start_addr: mem_map, program_mem: &mut Vec<u8>) {
        match start_addr {
            mem_map::internal_ram => {
                let start_addr = 0x0000;
                for i in 0..program_mem.len() {
                    self.mem[start_addr + i] = program_mem[i];
                }
            },
            mem_map::ppu_registers => {
                let start_addr = 0x2000;
                for i in 0..program_mem.len() {
                    self.mem[start_addr + i] = program_mem[i];
                }
            },
            mem_map::apu_io_registers => {
                let start_addr = 0x4000;
                for i in 0..program_mem.len() {
                    self.mem[start_addr + i] = program_mem[i];
                }
            },
            mem_map::cartridge_space => {
                let start_addr = 0xC000;
                for i in 0..program_mem.len() {
                    if (0xC000 + i) < 0xFFFF {
                        self.mem[start_addr + i] = program_mem[i];
                    }
                }
            },
        }
    }

    /*fn initialize(&self) {
    }*/

    // ADd with Carry
    fn ADC(&self) {

    }

    // bitwise AND with accumulator
    fn AND(&self) {

    }

    // Arithmetic Shift Left
    fn ASL(&self) {

    }

    // test BITs
    fn BIT(&self) {

    }

    // Branch on PLus
    fn BPL(&self) {

    }

    // Branch on MInus
    fn BMI(&self) {

    }

    // Branch on oVerflow Clear
    fn BVC(&self) {

    }

    // Branch on oVerflow Set
    fn BVS(&self) {

    }

    // Branch on Carry Clear
    fn BCC(&self) {

    }

    // Branch on Carry Set
    fn BCS(&self) {

    }

    // Branch on Not Equal
    fn BNE(&self) {

    }

    // Branch on EQual
    fn BEQ(&self) {

    }

    //BReaK
    fn BRK(&self) {

    }

    // CoMPare accumulator
    fn CMP(&self) {

    }

    // ComPare X register
    fn CPX(&self) {

    }

    // ComPare Y register
    fn CPY(&self)
    {

    }

    // DECrement Memory
    fn DEC(&self)
    {

    }

    // bitwise Exclusive org
    fn EOR(&self) {

    }

    // CLear Carry
    fn CLC(&self) {

    }

    // SEt Carry
    fn SEC(&self) {

    }

    // CLear Interrupt
    fn CLI(&self) {

    }

    // SEt Interrupt
    fn SEI(&self) {

    }

    // CLear oVerflow
    fn CLV(&self) {

    }

    // CLear Decimal
    fn CLD(&self) {

    }

    // SEt Decimal
    fn SED(&self) {

    }

    // INCrement Memory
    fn INC(&self) {

    }

    // JuMP
    fn JMP(&mut self, operand: &u16) {
        self.PC = *operand;
    }

    // Jump to SubRoutine
    fn JSR(&self) {

    }

    // LoaD Accumulator
    fn LDA(&self) {

    }

    // LoaD X register
    fn LDX(&mut self, operand: &u8) {
        self.X = *operand;
        if self.X == 0 {
            self.set_zero_flag();
        }
        if self.X & 0x80 > 0 {
            self.set_neg_flag();
        }
    }

    // LoaD Y register
    fn LDY(&self) {

    }

    // Logical Shift Right
    fn LSR(&self) {

    }

    // No OPeration
    fn NOP(&self) {

    }

    // bitwise OR with Accumulator
    fn ORA(&self) {

    }

    // Transfer A to X
    fn TAX(&self)
    {

    }

    // Transfer X to A
    fn TXA(&self)
    {

    }

    // DEcrement X
    fn DEX(&self) {

    }

    // INcrement X
    fn INX(&self) {

    }

    // Transfer A to Y
    fn TAY(&self) {

    }

    // Transfer Y to A
    fn TYA(&self) {

    }

    // DEcrement Y
    fn DEY(&self) {

    }

    // INcrement Y
    fn INY(&self) {

    }

    // ROtate Left
    fn ROL(&self) {

    }

    // ROtate Right
    fn ROR(&self) {

    }

    // ReTurn from Interrupt
    fn RTI(&self) {

    }

    // ReTurn from Subroutine
    fn RTS(&self) {

    }

    // SuBtract with Carry
    fn SBC(&self) {

    }

    // STore Accumulator
    fn STA(&self)
    {

    }

    // Transfer X to Stack ptr
    fn TXS(&self) {

    }

    // Transfer Stack ptr to X
    fn TSX(&self) {

    }

    // PusH Accumulator
    fn PHA(&self) {

    }

    // PuLl Accumulator
    fn PLA(&self) {

    }

    // PusH Processor status
    fn PHP(&self) {

    }

    // PuLl Processor status
    fn PLP(&self) {

    }

    // STore X register
    fn STX(&mut self, operand: &u8) {
        self.mem[*operand as usize] = self.X;
    }

    // STore Y register
    fn STY(&self) {

    }
}
<commit_msg>Add more instructions.<commit_after>//types
use std::error::Error;
use std::fs::File;
use std::io::BufReader;
use std::io::BufRead;
use std::env;
//traits
use std::io::Read;

#[allow(non_snake_case)]
#[allow(non_camel_case_types)]
#[allow(dead_code)]
pub struct CPU {
    //Registers

    //Program Counter
    PC: u16,

    //Stack pointer
    S: u8,

    //Processor status
    P: u8,

    //Accumulator
    A: u8,

    //Index register X
    X: u8,

    //Index register Y
    Y: u8,

    //Memory: FFFF, https://en.wikibooks.org/wiki/NES_Programming/Memory_Map
    //Address   Size    Desc.
    //$0000     $800    2KB of work RAM
    //$0800     $800    Mirror of $000-$7FF
    //$1000     $800    Mirror of $000-$7FF
    //$1800     $800    Mirror of $000-$7FF
    //$2000     8       PPU Ctrl Registers
    //$2008     $1FF8   *Mirror of $2000-$2007
    //$4000     $20     Registers (Mostly APU)
    //$4020     $1FDF   Cartridge Expansion ROM
    //$6000     $2000   SRAM
    //$8000     $4000   PRG-ROM
    //$C000     $4000   PRG-ROM
    //
    //this size is without any mirrors
    mem: Vec<u8>,

    //Debug string
    debug: String,
}

#[allow(non_camel_case_types)]
#[allow(dead_code)]
enum mem_map {
    internal_ram,
    ppu_registers,
    apu_io_registers,
    cartridge_space,
}

/*struct instruction {
    //Short form instruction name
    name: &'static str,

    //Opcode
    opcode: u8,

    //Cycles to fully decode instruction
    length: u8,

    //Cycles to complete instruction
    cycles: u8,

    //Closure that executes the instruction
    execute: ||,
}*/

#[allow(non_snake_case)]
#[allow(dead_code)]
impl CPU {
    pub fn new() -> CPU {
        let mut _mem = Vec::with_capacity(0xFFFF);
        for _ in 0..0xFFFF {
            _mem.push(0);
        }
        let mut _PC = 0;
        let mut _S = 0xFD;
        let mut _P = 0;
        let mut _A = 0;
        let mut _X = 0;
        let mut _Y = 0;
        let mut _debug :String = "".to_owned();

        CPU {
            PC: _PC,
            S: _S,
            P: _P,
            A: _A,
            X: _X,
            Y: _Y,
            mem: _mem,
            debug: _debug,
        }
    }

    // run a program
    pub fn test_load(&mut self, program: &str) {
        let path = env::current_dir().unwrap().join(program);
        let f = match File::open(&path) {
            Err(why) => panic!("Couldn't open {:?}: {}", path, Error::description(&why)),
            Ok(file) => file,
        };

        let mut i = 0;
        let mut program_mem: Vec<u8> = Vec::new();
        for byte in f.bytes() {
            let curr = match byte {
                Err(_) => return, //EOF
                Ok(byte) => byte,
            };

            i = i + 1;
            //skip the header information
            //only the PRG ROM for testing CPU
            if i > 16 && i <= 16400 {
                program_mem.push(curr);
            }
        }
        self.set_mem(mem_map::cartridge_space, &mut program_mem);
        self.PC = 0xC000;
        self.P = 0x24;
    }

    pub fn test_run(&mut self, log: &str) {
        //for some reason cargo indents the first line of output
        println!("");

        let path = env::current_dir().unwrap().join(log);
        let f = match File::open(&log) {
            Err(why) => panic!("Couldn't open {:?}: {}", path, Error::description(&why)),
            Ok(file) => file,
        };

        let file = BufReader::new(&f);

        for line in file.lines() {
            let mut curr_line = match line {
                Err(why) => panic!("Couldn't read line from {:?}: {}", path, Error::description(&why)),
                Ok(line) => line,
            };

            let instr = self.fetch_instr();
            self.execute_instr(&instr);

            curr_line.truncate(73);
            //println!("Log   line:{}", curr_line);
            //println!("Debug line:{}", self.debug);
            if curr_line != self.debug {
                println!("{}", curr_line);
            }
            assert_eq!(self.debug, curr_line);
        }
    }

    pub fn run(&mut self) {
        loop {
            let instr = self.fetch_instr();
            self.execute_instr(&instr);
        }
    }

    fn fetch_instr(&mut self) -> u8 {
        let instr = self.mem[self.PC as usize];
        self.debug = format!("{:04X}  {:02X} ", self.PC, instr);
        self.PC = self.PC + 1;
        instr
    }

    fn execute_instr(&mut self, instr: &u8) {
        match *instr {
            0x18 => {
                self.debug.push_str(&format!("       CLC                             "));
                self.print_registers();
                self.CLC();
            },
            0x20 => {
                let operand = self.read_absolute();
                self.debug.push_str(&format!("{:02X} {:02X}  JSR ${:04X}                       ", operand as u8, operand >> 8 as u8, operand));
                self.print_registers();
                self.JSR(&operand);
            },
            0x38 => {
                self.debug.push_str(&format!("       SEC                             "));
                self.print_registers();
                self.SEC();
            },
            0x4C => {
                let operand = self.read_absolute();
                self.debug.push_str(&format!("{:02X} {:02X}  JMP ${:04X}                       ", operand as u8, operand >> 8 as u8, operand));
                self.print_registers();
                self.JMP(&operand);
            },
            0x86 => {
                let operand = self.read_zeropage();
                self.debug.push_str(&format!("{:02X}     STX ${:02X} = {:02X}                    ", operand, operand, self.X));
                self.print_registers();
                self.STX(&operand);
            },
            0xA2 => {
                let operand = self.read_immediate();
                self.debug.push_str(&format!("{:02X}     LDX #${:02X}                        ", operand, operand));
                self.print_registers();
                self.LDX(&operand);
            },
            0xB0 => {
                let operand = self.read_relative();
                let branch_location = (self.PC as i32 + operand as i32) as u16;
                //println!("PC: {:04X}, OFFSET: {}", self.PC, operand);
                self.debug.push_str(&format!("{:02x}     BCS ${:04X}                       ", operand, branch_location));
                self.print_registers();
                //println!("{}", self.debug);
                self.BCS(&operand);
            },
            0xEA => {
                self.debug.push_str(&format!("       NOP                             "));
                self.print_registers();
                self.NOP();
            },
            _ => {
                println!("NOT IMPLEMENTED YET");
            },
        }
    }

    fn print_registers(&mut self) {
        self.debug.push_str(&format!("A:{:02X} X:{:02X} Y:{:02X} P:{:02X} SP:{:02X}", self.A, self.X, self.Y, self.P, self.S));
    }

    fn is_carry_set(&self) -> bool {
        self.P & 0x01 > 0
    }

    fn set_carry_flag(&mut self) {
        self.P |= 0x01;
    }

    fn clear_carry_flag(&mut self) {
        self.P &= !(1 << 0);
    }

    fn set_zero_flag(&mut self) {
        self.P |= 0x02;
    }

    fn set_neg_flag(&mut self) {
        self.P |= 0x080;
    }

    fn read_absolute(&mut self) -> u16 {
        let mem = (self.mem[self.PC as usize] as u16) | ((self.mem[(self.PC + 1) as usize]) as u16 ) << 8;
        self.PC = self.PC + 2;
        mem
    }

    fn read_relative(&mut self) -> i8 {
        let mem = self.mem[self.PC as usize] as i8;
        self.PC = self.PC + 1;
        mem
    }

    fn read_immediate(&mut self) -> u8 {
        let mem = self.mem[self.PC as usize];
        self.PC = self.PC + 1;
        mem
    }

    fn read_zeropage(&mut self) -> u8 {
        let mem = self.mem[self.PC as usize];
        self.PC = self.PC + 1;
        mem
    }

    fn push_to_stack(&mut self, value: &u8) {
        if self.S == 0x00 {
            panic!("Stack overflow!");
        }

        self.mem[(0x0100 + self.S as u16) as usize] = *value;
        self.S = self.S - 1;
    }

    fn pop_from_stack(&mut self) -> u8 {
        if self.S >= 0xFF {
            panic!("Stack underflow!");
        }

        self.S = self.S + 1;
        self.mem[(0x0100 + self.S as u16) as usize]
    }

    fn set_mem(&mut self, start_addr: mem_map, program_mem: &mut Vec<u8>) {
        match start_addr {
            mem_map::internal_ram => {
                let start_addr = 0x0000;
                for i in 0..program_mem.len() {
                    self.mem[start_addr + i] = program_mem[i];
                }
            },
            mem_map::ppu_registers => {
                let start_addr = 0x2000;
                for i in 0..program_mem.len() {
                    self.mem[start_addr + i] = program_mem[i];
                }
            },
            mem_map::apu_io_registers => {
                let start_addr = 0x4000;
                for i in 0..program_mem.len() {
                    self.mem[start_addr + i] = program_mem[i];
                }
            },
            mem_map::cartridge_space => {
                let start_addr = 0xC000;
                for i in 0..program_mem.len() {
                    if (0xC000 + i) < 0xFFFF {
                        self.mem[start_addr + i] = program_mem[i];
                    }
                }
            },
        }
    }

    /*fn initialize(&self) {
    }*/

    // ADd with Carry
    fn ADC(&self) {

    }

    // bitwise AND with accumulator
    fn AND(&self) {

    }

    // Arithmetic Shift Left
    fn ASL(&self) {

    }

    // test BITs
    fn BIT(&self) {

    }

    // Branch on PLus
    fn BPL(&self) {

    }

    // Branch on MInus
    fn BMI(&self) {

    }

    // Branch on oVerflow Clear
    fn BVC(&self) {

    }

    // Branch on oVerflow Set
    fn BVS(&self) {

    }

    // Branch on Carry Clear
    fn BCC(&self) {

    }

    // Branch on Carry Set
    fn BCS(&mut self, operand: &i8) {
        if self.is_carry_set() {
            self.PC = (self.PC as i32 + *operand as i32) as u16;
        }
    }

    // Branch on Not Equal
    fn BNE(&self) {

    }

    // Branch on EQual
    fn BEQ(&self) {

    }

    //BReaK
    fn BRK(&self) {

    }

    // CoMPare accumulator
    fn CMP(&self) {

    }

    // ComPare X register
    fn CPX(&self) {

    }

    // ComPare Y register
    fn CPY(&self)
    {

    }

    // DECrement Memory
    fn DEC(&self)
    {

    }

    // bitwise Exclusive org
    fn EOR(&self) {

    }

    // CLear Carry
    fn CLC(&mut self) {
        self.clear_carry_flag();
    }

    // SEt Carry
    fn SEC(&mut self) {
        self.set_carry_flag();
    }

    // CLear Interrupt
    fn CLI(&self) {

    }

    // SEt Interrupt
    fn SEI(&self) {

    }

    // CLear oVerflow
    fn CLV(&self) {

    }

    // CLear Decimal
    fn CLD(&self) {

    }

    // SEt Decimal
    fn SED(&self) {

    }

    // INCrement Memory
    fn INC(&self) {

    }

    // JuMP
    fn JMP(&mut self, operand: &u16) {
        self.PC = *operand;
    }

    // Jump to SubRoutine
    fn JSR(&mut self, operand: &u16) {
        let PCH: u8 = (self.PC >> 8) as u8;
        let PCL: u8 = self.PC as u8;
        self.push_to_stack(&PCH);
        self.push_to_stack(&PCL);
        self.PC = *operand;
    }

    // LoaD Accumulator
    fn LDA(&self) {

    }

    // LoaD X register
    fn LDX(&mut self, operand: &u8) {
        self.X = *operand;
        if self.X == 0 {
            self.set_zero_flag();
        }
        if self.X & 0x80 > 0 {
            self.set_neg_flag();
        }
    }

    // LoaD Y register
    fn LDY(&self) {

    }

    // Logical Shift Right
    fn LSR(&self) {

    }

    // No OPeration
    fn NOP(&self) {

    }

    // bitwise OR with Accumulator
    fn ORA(&self) {

    }

    // Transfer A to X
    fn TAX(&self)
    {

    }

    // Transfer X to A
    fn TXA(&self)
    {

    }

    // DEcrement X
    fn DEX(&self) {

    }

    // INcrement X
    fn INX(&self) {

    }

    // Transfer A to Y
    fn TAY(&self) {

    }

    // Transfer Y to A
    fn TYA(&self) {

    }

    // DEcrement Y
    fn DEY(&self) {

    }

    // INcrement Y
    fn INY(&self) {

    }

    // ROtate Left
    fn ROL(&self) {

    }

    // ROtate Right
    fn ROR(&self) {

    }

    // ReTurn from Interrupt
    fn RTI(&self) {

    }

    // ReTurn from Subroutine
    fn RTS(&self) {

    }

    // SuBtract with Carry
    fn SBC(&self) {

    }

    // STore Accumulator
    fn STA(&self)
    {

    }

    // Transfer X to Stack ptr
    fn TXS(&self) {

    }

    // Transfer Stack ptr to X
    fn TSX(&self) {

    }

    // PusH Accumulator
    fn PHA(&self) {

    }

    // PuLl Accumulator
    fn PLA(&self) {

    }

    // PusH Processor status
    fn PHP(&self) {

    }

    // PuLl Processor status
    fn PLP(&self) {

    }

    // STore X register
    fn STX(&mut self, operand: &u8) {
        self.mem[*operand as usize] = self.X;
    }

    // STore Y register
    fn STY(&self) {

    }
}
<|endoftext|>


<commit_before>use clap::{ App, Arg, ArgMatches, SubCommand };

pub fn run<'a>() -> ArgMatches<'a> {
    App::new(env!("CARGO_PKG_NAME"))
        .version(env!("CARGO_PKG_VERSION"))
        .author(env!("CARGO_PKG_AUTHORS"))
        .about("Wiz is a package manager.")
        .subcommand(
            SubCommand::with_name("install")
                .about("Installs package.")
                .arg(
                    Arg::with_name("package_name")
                    .help("Specifies package to install")
                )
        )
    .get_matches()
}<commit_msg>A missing arg.<commit_after>use clap::{ App, Arg, ArgMatches, SubCommand };

pub fn run<'a>() -> ArgMatches<'a> {
    App::new(env!("CARGO_PKG_NAME"))
        .version(env!("CARGO_PKG_VERSION"))
        .author(env!("CARGO_PKG_AUTHORS"))
        .about("Wiz is a package manager.")
        .subcommand(
            SubCommand::with_name("install")
                .about("Installs package.")
                .arg(
                    Arg::with_name("package_name")
                    .help("Specifies package to install")
                )
                .arg(
                    Arg::with_name("force")
                    .short("f")
                    .long("force")
                    .help("Forces the installation of the package to commence")
                )
        )
    .get_matches()
}<|endoftext|>


<commit_before>use super::smp::Smp;
use super::dsp::dsp::Dsp;
use super::timer::Timer;
use super::spc::spc::{Spc, RAM_LEN, IPL_ROM_LEN};

static DEFAULT_IPL_ROM: [u8; IPL_ROM_LEN] = [
    0xcd, 0xef, 0xbd, 0xe8, 0x00, 0xc6, 0x1d, 0xd0,
    0xfc, 0x8f, 0xaa, 0xf4, 0x8f, 0xbb, 0xf5, 0x78,
    0xcc, 0xf4, 0xd0, 0xfb, 0x2f, 0x19, 0xeb, 0xf4,
    0xd0, 0xfc, 0x7e, 0xf4, 0xd0, 0x0b, 0xe4, 0xf5,
    0xcb, 0xf4, 0xd7, 0x00, 0xfc, 0xd0, 0xf3, 0xab,
    0x01, 0x10, 0xef, 0x7e, 0xf4, 0x10, 0xeb, 0xba,
    0xf6, 0xda, 0x00, 0xba, 0xf4, 0xc4, 0xf4, 0xdd,
    0x5d, 0xd0, 0xdb, 0x1f, 0x00, 0x00, 0xc0, 0xff];

pub struct Apu {
    ram: Box<[u8; RAM_LEN]>,
    ipl_rom: Box<[u8; IPL_ROM_LEN]>,

    smp: Option<Box<Smp>>,
    dsp: Option<Box<Dsp>>,

    timers: [Timer; 3],

    is_ipl_rom_enabled: bool,
    dsp_reg_address: u8
}

impl Apu {
    pub fn new() -> Box<Apu> {
        let mut ret = Box::new(Apu {
            ram: Box::new([0; RAM_LEN]),
            ipl_rom: Box::new([0; IPL_ROM_LEN]),

            smp: None,
            dsp: None,

            timers: [Timer::new(256), Timer::new(256), Timer::new(32)],

            is_ipl_rom_enabled: true,
            dsp_reg_address: 0
        });
        let ret_ptr = &mut *ret as *mut _;
        ret.smp = Some(Box::new(Smp::new(ret_ptr)));
        ret.dsp = Some(Dsp::new(ret_ptr));
        ret.reset();
        ret
    }

    pub fn reset(&mut self) {
        for i in 0..IPL_ROM_LEN {
            self.ipl_rom[i] = DEFAULT_IPL_ROM[i];
        }

        self.smp.as_mut().unwrap().reset();
        self.dsp.as_mut().unwrap().reset();
        for timer in self.timers.iter_mut() {
            timer.reset();
        }

        self.is_ipl_rom_enabled = true;
        self.dsp_reg_address = 0;
    }

    pub fn render(&mut self, left_buffer: &mut [i16], right_buffer: &mut [i16], num_samples: i32) {
        let smp = self.smp.as_mut().unwrap();
        let dsp = self.dsp.as_mut().unwrap();
        while dsp.output_buffer.get_sample_count() < num_samples {
            smp.run(num_samples * 64);
            dsp.flush();
        }

        dsp.output_buffer.read(left_buffer, right_buffer, num_samples);
    }

    pub fn cpu_cycles_callback(&mut self, num_cycles: i32) {
        self.dsp.as_mut().unwrap().cycles_callback(num_cycles);
        for timer in self.timers.iter_mut() {
            timer.cpu_cycles_callback(num_cycles);
        }
    }

    pub fn read_u8(&mut self, address: u32) -> u8 {
        let address = address & 0xffff;
        if address >= 0xf0 && address < 0x0100 {
            match address {
                0xf0 | 0xf1 => 0,

                0xf2 => self.dsp_reg_address,
                0xf3 => self.dsp.as_mut().unwrap().get_register(self.dsp_reg_address),

                0xfa ... 0xfc => 0,

                0xfd => self.timers[0].read_counter(),
                0xfe => self.timers[1].read_counter(),
                0xff => self.timers[2].read_counter(),

                _ => self.ram[address as usize]
            }
        } else if address >= 0xffc0 && self.is_ipl_rom_enabled {
            self.ipl_rom[(address - 0xffc0) as usize]
        } else {
            self.ram[address as usize]
        }
    }

    pub fn write_u8(&mut self, address: u32, value: u8) {
        let address = address & 0xffff;
        if address >= 0x00f0 && address < 0x0100 {
            match address {
                0xf0 => { self.set_test_reg(value); },
                0xf1 => { self.set_control_reg(value); },
                0xf2 => { self.dsp_reg_address = value; },
                0xf3 => { self.dsp.as_mut().unwrap().set_register(self.dsp_reg_address, value); },

                0xf4 ... 0xf9 => { self.ram[address as usize] = value; },

                0xfa => { self.timers[0].set_target(value); },
                0xfb => { self.timers[1].set_target(value); },
                0xfc => { self.timers[2].set_target(value); },

                _ => () // Do nothing
            }
        } else {
            self.ram[address as usize] = value;
        }
    }

    pub fn set_state(&mut self, spc: &Spc) {
        self.reset();

        for i in 0..RAM_LEN {
            self.ram[i] = spc.ram[i];
        }
        for i in 0..IPL_ROM_LEN {
            self.ipl_rom[i] = spc.ipl_rom[i];
        }

        {
            let smp = self.smp.as_mut().unwrap();
            smp.reg_pc = spc.pc;
            smp.reg_a = spc.a;
            smp.reg_x = spc.x;
            smp.reg_y = spc.y;
            smp.set_psw(spc.psw);
            smp.reg_sp = spc.sp;
        }

        self.dsp.as_mut().unwrap().set_state(spc);

        for i in 0..3 {
            self.timers[i].set_target(self.ram[0xfa + i]);
        }
        let control_reg = self.ram[0xf1];
        self.set_control_reg(control_reg);

        self.dsp_reg_address = self.ram[0xf2];
    }

    pub fn clear_echo_buffer(&mut self) {
        let dsp = self.dsp.as_mut().unwrap();
        let length = dsp.calculate_echo_length();
        let mut end_addr = dsp.get_echo_start_address() as i32 + length;
        if end_addr > RAM_LEN as i32 {
            end_addr = RAM_LEN as i32;
        }
        for i in dsp.get_echo_start_address() as i32..end_addr {
            self.ram[i as usize] = 0xff;
        }
    }

    fn set_test_reg(&self, value: u8) {
        let _ = value;
        panic!("Test reg not yet implemented");
    }

    fn set_control_reg(&mut self, value: u8) {
        self.is_ipl_rom_enabled = (value & 0x80) != 0;
        if (value & 0x20) != 0 {
            self.write_u8(0xf6, 0x00);
            self.write_u8(0xf7, 0x00);
        }
        if (value & 0x10) != 0 {
            self.write_u8(0xf4, 0x00);
            self.write_u8(0xf5, 0x00);
        }
        self.timers[0].set_start_stop_bit((value & 0x01) != 0);
        self.timers[1].set_start_stop_bit((value & 0x02) != 0);
        self.timers[2].set_start_stop_bit((value & 0x04) != 0);
    }
}
<commit_msg>Ram is now cleared on APU reset<commit_after>use super::smp::Smp;
use super::dsp::dsp::Dsp;
use super::timer::Timer;
use super::spc::spc::{Spc, RAM_LEN, IPL_ROM_LEN};

static DEFAULT_IPL_ROM: [u8; IPL_ROM_LEN] = [
    0xcd, 0xef, 0xbd, 0xe8, 0x00, 0xc6, 0x1d, 0xd0,
    0xfc, 0x8f, 0xaa, 0xf4, 0x8f, 0xbb, 0xf5, 0x78,
    0xcc, 0xf4, 0xd0, 0xfb, 0x2f, 0x19, 0xeb, 0xf4,
    0xd0, 0xfc, 0x7e, 0xf4, 0xd0, 0x0b, 0xe4, 0xf5,
    0xcb, 0xf4, 0xd7, 0x00, 0xfc, 0xd0, 0xf3, 0xab,
    0x01, 0x10, 0xef, 0x7e, 0xf4, 0x10, 0xeb, 0xba,
    0xf6, 0xda, 0x00, 0xba, 0xf4, 0xc4, 0xf4, 0xdd,
    0x5d, 0xd0, 0xdb, 0x1f, 0x00, 0x00, 0xc0, 0xff];

pub struct Apu {
    ram: Box<[u8; RAM_LEN]>,
    ipl_rom: Box<[u8; IPL_ROM_LEN]>,

    smp: Option<Box<Smp>>,
    dsp: Option<Box<Dsp>>,

    timers: [Timer; 3],

    is_ipl_rom_enabled: bool,
    dsp_reg_address: u8
}

impl Apu {
    pub fn new() -> Box<Apu> {
        let mut ret = Box::new(Apu {
            ram: Box::new([0; RAM_LEN]),
            ipl_rom: Box::new([0; IPL_ROM_LEN]),

            smp: None,
            dsp: None,

            timers: [Timer::new(256), Timer::new(256), Timer::new(32)],

            is_ipl_rom_enabled: true,
            dsp_reg_address: 0
        });
        let ret_ptr = &mut *ret as *mut _;
        ret.smp = Some(Box::new(Smp::new(ret_ptr)));
        ret.dsp = Some(Dsp::new(ret_ptr));
        ret.reset();
        ret
    }

    pub fn reset(&mut self) {
        for i in 0..RAM_LEN {
            self.ram[i] = 0;
        }

        for i in 0..IPL_ROM_LEN {
            self.ipl_rom[i] = DEFAULT_IPL_ROM[i];
        }

        self.smp.as_mut().unwrap().reset();
        self.dsp.as_mut().unwrap().reset();
        for timer in self.timers.iter_mut() {
            timer.reset();
        }

        self.is_ipl_rom_enabled = true;
        self.dsp_reg_address = 0;
    }

    pub fn render(&mut self, left_buffer: &mut [i16], right_buffer: &mut [i16], num_samples: i32) {
        let smp = self.smp.as_mut().unwrap();
        let dsp = self.dsp.as_mut().unwrap();
        while dsp.output_buffer.get_sample_count() < num_samples {
            smp.run(num_samples * 64);
            dsp.flush();
        }

        dsp.output_buffer.read(left_buffer, right_buffer, num_samples);
    }

    pub fn cpu_cycles_callback(&mut self, num_cycles: i32) {
        self.dsp.as_mut().unwrap().cycles_callback(num_cycles);
        for timer in self.timers.iter_mut() {
            timer.cpu_cycles_callback(num_cycles);
        }
    }

    pub fn read_u8(&mut self, address: u32) -> u8 {
        let address = address & 0xffff;
        if address >= 0xf0 && address < 0x0100 {
            match address {
                0xf0 | 0xf1 => 0,

                0xf2 => self.dsp_reg_address,
                0xf3 => self.dsp.as_mut().unwrap().get_register(self.dsp_reg_address),

                0xfa ... 0xfc => 0,

                0xfd => self.timers[0].read_counter(),
                0xfe => self.timers[1].read_counter(),
                0xff => self.timers[2].read_counter(),

                _ => self.ram[address as usize]
            }
        } else if address >= 0xffc0 && self.is_ipl_rom_enabled {
            self.ipl_rom[(address - 0xffc0) as usize]
        } else {
            self.ram[address as usize]
        }
    }

    pub fn write_u8(&mut self, address: u32, value: u8) {
        let address = address & 0xffff;
        if address >= 0x00f0 && address < 0x0100 {
            match address {
                0xf0 => { self.set_test_reg(value); },
                0xf1 => { self.set_control_reg(value); },
                0xf2 => { self.dsp_reg_address = value; },
                0xf3 => { self.dsp.as_mut().unwrap().set_register(self.dsp_reg_address, value); },

                0xf4 ... 0xf9 => { self.ram[address as usize] = value; },

                0xfa => { self.timers[0].set_target(value); },
                0xfb => { self.timers[1].set_target(value); },
                0xfc => { self.timers[2].set_target(value); },

                _ => () // Do nothing
            }
        } else {
            self.ram[address as usize] = value;
        }
    }

    pub fn set_state(&mut self, spc: &Spc) {
        self.reset();

        for i in 0..RAM_LEN {
            self.ram[i] = spc.ram[i];
        }
        for i in 0..IPL_ROM_LEN {
            self.ipl_rom[i] = spc.ipl_rom[i];
        }

        {
            let smp = self.smp.as_mut().unwrap();
            smp.reg_pc = spc.pc;
            smp.reg_a = spc.a;
            smp.reg_x = spc.x;
            smp.reg_y = spc.y;
            smp.set_psw(spc.psw);
            smp.reg_sp = spc.sp;
        }

        self.dsp.as_mut().unwrap().set_state(spc);

        for i in 0..3 {
            self.timers[i].set_target(self.ram[0xfa + i]);
        }
        let control_reg = self.ram[0xf1];
        self.set_control_reg(control_reg);

        self.dsp_reg_address = self.ram[0xf2];
    }

    pub fn clear_echo_buffer(&mut self) {
        let dsp = self.dsp.as_mut().unwrap();
        let length = dsp.calculate_echo_length();
        let mut end_addr = dsp.get_echo_start_address() as i32 + length;
        if end_addr > RAM_LEN as i32 {
            end_addr = RAM_LEN as i32;
        }
        for i in dsp.get_echo_start_address() as i32..end_addr {
            self.ram[i as usize] = 0xff;
        }
    }

    fn set_test_reg(&self, value: u8) {
        let _ = value;
        panic!("Test reg not yet implemented");
    }

    fn set_control_reg(&mut self, value: u8) {
        self.is_ipl_rom_enabled = (value & 0x80) != 0;
        if (value & 0x20) != 0 {
            self.write_u8(0xf6, 0x00);
            self.write_u8(0xf7, 0x00);
        }
        if (value & 0x10) != 0 {
            self.write_u8(0xf4, 0x00);
            self.write_u8(0xf5, 0x00);
        }
        self.timers[0].set_start_stop_bit((value & 0x01) != 0);
        self.timers[1].set_start_stop_bit((value & 0x02) != 0);
        self.timers[2].set_start_stop_bit((value & 0x04) != 0);
    }
}
<|endoftext|>