<commit_before>// Take a look at the license at the top of the repository in the LICENSE file.

use crate::{DiskUsage, Pid, ProcessExt, ProcessRefreshKind, ProcessStatus, Signal};

use std::fmt;
use std::path::{Path, PathBuf};

use super::utils::{get_sys_value_str, WrapMap};

#[doc(hidden)]
impl From<libc::c_char> for ProcessStatus {
    fn from(status: libc::c_char) -> ProcessStatus {
        match status {
            libc::SIDL => ProcessStatus::Idle,
            libc::SRUN => ProcessStatus::Run,
            libc::SSLEEP => ProcessStatus::Sleep,
            libc::SSTOP => ProcessStatus::Stop,
            libc::SZOMB => ProcessStatus::Zombie,
            libc::SWAIT => ProcessStatus::Dead,
            libc::SLOCK => ProcessStatus::LockBlocked,
            x => ProcessStatus::Unknown(x as _),
        }
    }
}

impl fmt::Display for ProcessStatus {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(match *self {
            ProcessStatus::Idle => "Idle",
            ProcessStatus::Run => "Runnable",
            ProcessStatus::Sleep => "Sleeping",
            ProcessStatus::Stop => "Stopped",
            ProcessStatus::Zombie => "Zombie",
            ProcessStatus::Dead => "Dead",
            ProcessStatus::LockBlocked => "LockBlocked",
            _ => "Unknown",
        })
    }
}

#[doc = include_str!("../../md_doc/process.md")]
pub struct Process {
    pub(crate) name: String,
    pub(crate) cmd: Vec<String>,
    pub(crate) exe: PathBuf,
    pub(crate) pid: Pid,
    parent: Option<Pid>,
    pub(crate) environ: Vec<String>,
    pub(crate) cwd: PathBuf,
    pub(crate) root: PathBuf,
    pub(crate) memory: u64,
    pub(crate) virtual_memory: u64,
    pub(crate) updated: bool,
    cpu_usage: f32,
    start_time: u64,
    run_time: u64,
    pub(crate) status: ProcessStatus,
    /// User id of the process owner.
    pub uid: libc::uid_t,
    /// Group id of the process owner.
    pub gid: libc::gid_t,
    read_bytes: u64,
    old_read_bytes: u64,
    written_bytes: u64,
    old_written_bytes: u64,
}

impl ProcessExt for Process {
    fn kill_with(&self, signal: Signal) -> Option<bool> {
        let c_signal = super::system::convert_signal(signal)?;
        unsafe { Some(libc::kill(self.pid.0, c_signal) == 0) }
    }

    fn name(&self) -> &str {
        &self.name
    }

    fn cmd(&self) -> &[String] {
        &self.cmd
    }

    fn exe(&self) -> &Path {
        self.exe.as_path()
    }

    fn pid(&self) -> Pid {
        self.pid
    }

    fn environ(&self) -> &[String] {
        &self.environ
    }

    fn cwd(&self) -> &Path {
        self.cwd.as_path()
    }

    fn root(&self) -> &Path {
        self.root.as_path()
    }

    fn memory(&self) -> u64 {
        self.memory
    }

    fn virtual_memory(&self) -> u64 {
        self.virtual_memory
    }

    fn parent(&self) -> Option<Pid> {
        self.parent
    }

    fn status(&self) -> ProcessStatus {
        self.status
    }

    fn start_time(&self) -> u64 {
        self.start_time
    }

    fn run_time(&self) -> u64 {
        self.run_time
    }

    fn cpu_usage(&self) -> f32 {
        self.cpu_usage
    }

    fn disk_usage(&self) -> DiskUsage {
        DiskUsage {
            written_bytes: self.written_bytes.saturating_sub(self.old_written_bytes),
            total_written_bytes: self.written_bytes,
            read_bytes: self.read_bytes.saturating_sub(self.old_read_bytes),
            total_read_bytes: self.read_bytes,
        }
    }
}

pub(crate) unsafe fn get_process_data(
    kproc: &libc::kinfo_proc,
    wrap: &WrapMap,
    page_size: isize,
    fscale: f32,
    now: u64,
    refresh_kind: ProcessRefreshKind,
) -> Result<Option<Process>, ()> {
    if kproc.ki_pid != 1 && (kproc.ki_flag as libc::c_int & libc::P_SYSTEM) != 0 {
        // We filter out the kernel threads.
        return Err(());
    }

    // We now get the values needed for both new and existing process.
    let cpu_usage = if refresh_kind.cpu() {
        (100 * kproc.ki_pctcpu) as f32 / fscale
    } else {
        0.
    };
    // Processes can be reparented apparently?
    let parent = if kproc.ki_ppid != 0 {
        Some(Pid(kproc.ki_ppid))
    } else {
        None
    };
    let status = ProcessStatus::from(kproc.ki_stat);

    // from FreeBSD source /src/usr.bin/top/machine.c
    let virtual_memory = (kproc.ki_size / 1_000) as u64;
    let memory = (kproc.ki_rssize * page_size) as u64 / 1_000;
    // FIXME: This is to get the "real" run time (in micro-seconds).
    // let run_time = (kproc.ki_runtime + 5_000) / 10_000;

    if let Some(proc_) = (*wrap.0.get()).get_mut(&Pid(kproc.ki_pid)) {
        proc_.cpu_usage = cpu_usage;
        proc_.parent = parent;
        proc_.status = status;
        proc_.virtual_memory = virtual_memory;
        proc_.memory = memory;
        proc_.run_time = now.saturating_sub(proc_.start_time);
        proc_.updated = true;

        if refresh_kind.disk_usage() {
            proc_.old_read_bytes = proc_.read_bytes;
            proc_.read_bytes = kproc.ki_rusage.ru_inblock as _;
            proc_.old_written_bytes = proc_.written_bytes;
            proc_.written_bytes = kproc.ki_rusage.ru_oublock as _;
        }

        return Ok(None);
    }

    // This is a new process, we need to get more information!
    let mut buffer = [0; libc::PATH_MAX as usize + 1];

    let exe = get_sys_value_str(
        &[
            libc::CTL_KERN,
            libc::KERN_PROC,
            libc::KERN_PROC_PATHNAME,
            kproc.ki_pid,
        ],
        &mut buffer,
    )
    .unwrap_or_default();
    // For some reason, it can return completely invalid path like `p\u{5}`. So we need to use
    // procstat to get around this problem.
    // let cwd = get_sys_value_str(
    //     &[
    //         libc::CTL_KERN,
    //         libc::KERN_PROC,
    //         libc::KERN_PROC_CWD,
    //         kproc.ki_pid,
    //     ],
    //     &mut buffer,
    // )
    // .map(|s| s.into())
    // .unwrap_or_else(PathBuf::new);

    let start_time = kproc.ki_start.tv_sec as u64;
    Ok(Some(Process {
        pid: Pid(kproc.ki_pid),
        parent,
        uid: kproc.ki_ruid,
        gid: kproc.ki_rgid,
        start_time,
        run_time: now.saturating_sub(start_time),
        cpu_usage,
        virtual_memory,
        memory,
        // procstat_getfiles
        cwd: PathBuf::new(),
        exe: exe.into(),
        // kvm_getargv isn't thread-safe so we get it in the main thread.
        name: String::new(),
        // kvm_getargv isn't thread-safe so we get it in the main thread.
        cmd: Vec::new(),
        // kvm_getargv isn't thread-safe so we get it in the main thread.
        root: PathBuf::new(),
        // kvm_getenvv isn't thread-safe so we get it in the main thread.
        environ: Vec::new(),
        status,
        read_bytes: kproc.ki_rusage.ru_inblock as _,
        old_read_bytes: 0,
        written_bytes: kproc.ki_rusage.ru_oublock as _,
        old_written_bytes: 0,
        updated: true,
    }))
}
<commit_msg>Support new User API on freebsd<commit_after>// Take a look at the license at the top of the repository in the LICENSE file.

use crate::{DiskUsage, Gid, Pid, ProcessExt, ProcessRefreshKind, ProcessStatus, Signal, Uid};

use std::fmt;
use std::path::{Path, PathBuf};

use super::utils::{get_sys_value_str, WrapMap};

#[doc(hidden)]
impl From<libc::c_char> for ProcessStatus {
    fn from(status: libc::c_char) -> ProcessStatus {
        match status {
            libc::SIDL => ProcessStatus::Idle,
            libc::SRUN => ProcessStatus::Run,
            libc::SSLEEP => ProcessStatus::Sleep,
            libc::SSTOP => ProcessStatus::Stop,
            libc::SZOMB => ProcessStatus::Zombie,
            libc::SWAIT => ProcessStatus::Dead,
            libc::SLOCK => ProcessStatus::LockBlocked,
            x => ProcessStatus::Unknown(x as _),
        }
    }
}

impl fmt::Display for ProcessStatus {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(match *self {
            ProcessStatus::Idle => "Idle",
            ProcessStatus::Run => "Runnable",
            ProcessStatus::Sleep => "Sleeping",
            ProcessStatus::Stop => "Stopped",
            ProcessStatus::Zombie => "Zombie",
            ProcessStatus::Dead => "Dead",
            ProcessStatus::LockBlocked => "LockBlocked",
            _ => "Unknown",
        })
    }
}

#[doc = include_str!("../../md_doc/process.md")]
pub struct Process {
    pub(crate) name: String,
    pub(crate) cmd: Vec<String>,
    pub(crate) exe: PathBuf,
    pub(crate) pid: Pid,
    parent: Option<Pid>,
    pub(crate) environ: Vec<String>,
    pub(crate) cwd: PathBuf,
    pub(crate) root: PathBuf,
    pub(crate) memory: u64,
    pub(crate) virtual_memory: u64,
    pub(crate) updated: bool,
    cpu_usage: f32,
    start_time: u64,
    run_time: u64,
    pub(crate) status: ProcessStatus,
    user_id: Uid,
    group_id: Gid,
    read_bytes: u64,
    old_read_bytes: u64,
    written_bytes: u64,
    old_written_bytes: u64,
}

impl ProcessExt for Process {
    fn kill_with(&self, signal: Signal) -> Option<bool> {
        let c_signal = super::system::convert_signal(signal)?;
        unsafe { Some(libc::kill(self.pid.0, c_signal) == 0) }
    }

    fn name(&self) -> &str {
        &self.name
    }

    fn cmd(&self) -> &[String] {
        &self.cmd
    }

    fn exe(&self) -> &Path {
        self.exe.as_path()
    }

    fn pid(&self) -> Pid {
        self.pid
    }

    fn environ(&self) -> &[String] {
        &self.environ
    }

    fn cwd(&self) -> &Path {
        self.cwd.as_path()
    }

    fn root(&self) -> &Path {
        self.root.as_path()
    }

    fn memory(&self) -> u64 {
        self.memory
    }

    fn virtual_memory(&self) -> u64 {
        self.virtual_memory
    }

    fn parent(&self) -> Option<Pid> {
        self.parent
    }

    fn status(&self) -> ProcessStatus {
        self.status
    }

    fn start_time(&self) -> u64 {
        self.start_time
    }

    fn run_time(&self) -> u64 {
        self.run_time
    }

    fn cpu_usage(&self) -> f32 {
        self.cpu_usage
    }

    fn disk_usage(&self) -> DiskUsage {
        DiskUsage {
            written_bytes: self.written_bytes.saturating_sub(self.old_written_bytes),
            total_written_bytes: self.written_bytes,
            read_bytes: self.read_bytes.saturating_sub(self.old_read_bytes),
            total_read_bytes: self.read_bytes,
        }
    }

    fn user_id(&self) -> Option<&Uid> {
        Some(&self.user_id)
    }

    fn group_id(&self) -> Option<Gid> {
        Some(self.group_id)
    }
}

pub(crate) unsafe fn get_process_data(
    kproc: &libc::kinfo_proc,
    wrap: &WrapMap,
    page_size: isize,
    fscale: f32,
    now: u64,
    refresh_kind: ProcessRefreshKind,
) -> Result<Option<Process>, ()> {
    if kproc.ki_pid != 1 && (kproc.ki_flag as libc::c_int & libc::P_SYSTEM) != 0 {
        // We filter out the kernel threads.
        return Err(());
    }

    // We now get the values needed for both new and existing process.
    let cpu_usage = if refresh_kind.cpu() {
        (100 * kproc.ki_pctcpu) as f32 / fscale
    } else {
        0.
    };
    // Processes can be reparented apparently?
    let parent = if kproc.ki_ppid != 0 {
        Some(Pid(kproc.ki_ppid))
    } else {
        None
    };
    let status = ProcessStatus::from(kproc.ki_stat);

    // from FreeBSD source /src/usr.bin/top/machine.c
    let virtual_memory = (kproc.ki_size / 1_000) as u64;
    let memory = (kproc.ki_rssize * page_size) as u64 / 1_000;
    // FIXME: This is to get the "real" run time (in micro-seconds).
    // let run_time = (kproc.ki_runtime + 5_000) / 10_000;

    if let Some(proc_) = (*wrap.0.get()).get_mut(&Pid(kproc.ki_pid)) {
        proc_.cpu_usage = cpu_usage;
        proc_.parent = parent;
        proc_.status = status;
        proc_.virtual_memory = virtual_memory;
        proc_.memory = memory;
        proc_.run_time = now.saturating_sub(proc_.start_time);
        proc_.updated = true;

        if refresh_kind.disk_usage() {
            proc_.old_read_bytes = proc_.read_bytes;
            proc_.read_bytes = kproc.ki_rusage.ru_inblock as _;
            proc_.old_written_bytes = proc_.written_bytes;
            proc_.written_bytes = kproc.ki_rusage.ru_oublock as _;
        }

        return Ok(None);
    }

    // This is a new process, we need to get more information!
    let mut buffer = [0; libc::PATH_MAX as usize + 1];

    let exe = get_sys_value_str(
        &[
            libc::CTL_KERN,
            libc::KERN_PROC,
            libc::KERN_PROC_PATHNAME,
            kproc.ki_pid,
        ],
        &mut buffer,
    )
    .unwrap_or_default();
    // For some reason, it can return completely invalid path like `p\u{5}`. So we need to use
    // procstat to get around this problem.
    // let cwd = get_sys_value_str(
    //     &[
    //         libc::CTL_KERN,
    //         libc::KERN_PROC,
    //         libc::KERN_PROC_CWD,
    //         kproc.ki_pid,
    //     ],
    //     &mut buffer,
    // )
    // .map(|s| s.into())
    // .unwrap_or_else(PathBuf::new);

    let start_time = kproc.ki_start.tv_sec as u64;
    Ok(Some(Process {
        pid: Pid(kproc.ki_pid),
        parent,
        user_id: Uid(kproc.ki_ruid),
        group_id: Gid(kproc.ki_rgid),
        start_time,
        run_time: now.saturating_sub(start_time),
        cpu_usage,
        virtual_memory,
        memory,
        // procstat_getfiles
        cwd: PathBuf::new(),
        exe: exe.into(),
        // kvm_getargv isn't thread-safe so we get it in the main thread.
        name: String::new(),
        // kvm_getargv isn't thread-safe so we get it in the main thread.
        cmd: Vec::new(),
        // kvm_getargv isn't thread-safe so we get it in the main thread.
        root: PathBuf::new(),
        // kvm_getenvv isn't thread-safe so we get it in the main thread.
        environ: Vec::new(),
        status,
        read_bytes: kproc.ki_rusage.ru_inblock as _,
        old_read_bytes: 0,
        written_bytes: kproc.ki_rusage.ru_oublock as _,
        old_written_bytes: 0,
        updated: true,
    }))
}
<|endoftext|>


<commit_before>//! The `canvas` module enables creating render targets to be used instead of
//! the screen.  This allows graphics to be rendered to images off-screen
//! in order to do things like saving to an image file or creating cool effects.

use gfx::{Factory};
use gfx::format::{ChannelTyped, Srgb, Srgba8, Swizzle};
use gfx::handle::RenderTargetView;
use gfx::memory::{Bind, Usage};
use gfx::texture::{AaMode, Kind};

use Context;
use conf::*;
use error::*;
use graphics::*;

/// A generic canvas independent of graphics backend. This type should probably
/// never be used directly; use `ggez::graphics::Canvas` instead.
#[derive(Debug)]
pub struct CanvasGeneric<Spec>
where
    Spec: BackendSpec,
{
    target: RenderTargetView<Spec::Resources, Srgba8>,
    image: Image,
}

/// A canvas that can be rendered to instead of the screen (sometimes referred
/// to as "render target" or "render to texture"). Set the canvas with the
/// `ggez::graphics::set_canvas()` function, and then anything you
/// draw will be drawn to the canvas instead of the screen.
///
/// Resume drawing to the screen by calling `ggez::graphics::set_canvas(None)`.
pub type Canvas = CanvasGeneric<GlBackendSpec>;

impl Canvas {
    /// Create a new canvas with the given size and number of samples.
    pub fn new(
        ctx: &mut Context,
        width: u32,
        height: u32,
        samples: NumSamples,
    ) -> GameResult<Canvas> {
        let (w, h) = (width as u16, height as u16);
        let aa = match samples {
            NumSamples::One => AaMode::Single,
            s => AaMode::Multi(s as u8),
        };
        let kind = Kind::D2(w, h, aa);
        let cty = Srgb::get_channel_type();
        let levels = 1;
        let factory = &mut ctx.gfx_context.factory;
        let tex = factory.create_texture(
            kind,
            levels,
            Bind::SHADER_RESOURCE | Bind::RENDER_TARGET,
            Usage::Data,
            Some(cty),
        )?;
        let resource = factory.view_texture_as_shader_resource::<Srgba8>(
            &tex,
            (0, levels - 1),
            Swizzle::new(),
        )?;
        let target = factory.view_texture_as_render_target(&tex, 0, None)?;
        Ok(Canvas {
            target,
            image: Image {
                texture: resource,
                sampler_info: ctx.gfx_context.default_sampler_info,
                blend_mode: None,
                width,
                height,
            },
        })
    }

    /// Create a new canvas with the current window dimensions.
    pub fn with_window_size(ctx: &mut Context) -> GameResult<Canvas> {
        use graphics;
        let (w, h) = graphics::get_drawable_size(ctx);
        // Default to no multisampling
        Canvas::new(ctx, w, h, NumSamples::One)
    }

    /// Gets the backend `Image` that is being rendered to.
    pub fn get_image(&self) -> &Image {
        &self.image
    }

    /// Destroys the Canvas and returns the `Image` it contains.
    pub fn into_inner(self) -> Image {
        // This texture is created with different settings
        // than the default; does that matter?
        self.image
    }
}

impl Drawable for Canvas {
    fn draw_ex(&self, ctx: &mut Context, param: DrawParam) -> GameResult<()> {
        self.image.draw_ex(ctx, param)
    }
    fn set_blend_mode(&mut self, mode: Option<BlendMode>) {
        self.image.blend_mode = mode;
    }
    fn get_blend_mode(&self) -> Option<BlendMode> {
        self.image.blend_mode
    }
}

/// Set the canvas to render to. Specifying `Option::None` will cause all
/// rendering to be done directly to the screen.
pub fn set_canvas(ctx: &mut Context, target: Option<&Canvas>) {
    match target {
        Some(surface) => {
            ctx.gfx_context.data.out = surface.target.clone();
        }
        None => {
            ctx.gfx_context.data.out = ctx.gfx_context.screen_render_target.clone();
        }
    };
}
<commit_msg>Update Canvas module docs a little<commit_after>//! I guess these docs will never appear since we re-export the canvas
//! module from graphics...

use gfx::{Factory};
use gfx::format::{ChannelTyped, Srgb, Srgba8, Swizzle};
use gfx::handle::RenderTargetView;
use gfx::memory::{Bind, Usage};
use gfx::texture::{AaMode, Kind};

use Context;
use conf::*;
use error::*;
use graphics::*;

/// A generic canvas independent of graphics backend. This type should probably
/// never be used directly; use `ggez::graphics::Canvas` instead.
#[derive(Debug)]
pub struct CanvasGeneric<Spec>
where
    Spec: BackendSpec,
{
    target: RenderTargetView<Spec::Resources, Srgba8>,
    image: Image,
}

/// The `Canvas` type allows creating render targets to be used instead of
/// the screen.  This allows graphics to be rendered to images off-screen
/// in order to do things like saving to an image file or creating cool effects.
/// If you just want to draw multiple things efficiently, look at `SpriteBatch`.
///
/// A canvas that can be rendered to instead of the screen (sometimes referred
/// to as "render target" or "render to texture"). Set the canvas with the
/// `ggez::graphics::set_canvas()` function, and then anything you
/// draw will be drawn to the canvas instead of the screen.
///
/// Resume drawing to the screen by calling `ggez::graphics::set_canvas(None)`.
pub type Canvas = CanvasGeneric<GlBackendSpec>;

impl Canvas {
    /// Create a new canvas with the given size and number of samples.
    pub fn new(
        ctx: &mut Context,
        width: u32,
        height: u32,
        samples: NumSamples,
    ) -> GameResult<Canvas> {
        let (w, h) = (width as u16, height as u16);
        let aa = match samples {
            NumSamples::One => AaMode::Single,
            s => AaMode::Multi(s as u8),
        };
        let kind = Kind::D2(w, h, aa);
        let cty = Srgb::get_channel_type();
        let levels = 1;
        let factory = &mut ctx.gfx_context.factory;
        let tex = factory.create_texture(
            kind,
            levels,
            Bind::SHADER_RESOURCE | Bind::RENDER_TARGET,
            Usage::Data,
            Some(cty),
        )?;
        let resource = factory.view_texture_as_shader_resource::<Srgba8>(
            &tex,
            (0, levels - 1),
            Swizzle::new(),
        )?;
        let target = factory.view_texture_as_render_target(&tex, 0, None)?;
        Ok(Canvas {
            target,
            image: Image {
                texture: resource,
                sampler_info: ctx.gfx_context.default_sampler_info,
                blend_mode: None,
                width,
                height,
            },
        })
    }

    /// Create a new canvas with the current window dimensions.
    pub fn with_window_size(ctx: &mut Context) -> GameResult<Canvas> {
        use graphics;
        let (w, h) = graphics::get_drawable_size(ctx);
        // Default to no multisampling
        Canvas::new(ctx, w, h, NumSamples::One)
    }

    /// Gets the backend `Image` that is being rendered to.
    pub fn get_image(&self) -> &Image {
        &self.image
    }

    /// Destroys the Canvas and returns the `Image` it contains.
    pub fn into_inner(self) -> Image {
        // This texture is created with different settings
        // than the default; does that matter?
        self.image
    }
}

impl Drawable for Canvas {
    fn draw_ex(&self, ctx: &mut Context, param: DrawParam) -> GameResult<()> {
        self.image.draw_ex(ctx, param)
    }
    fn set_blend_mode(&mut self, mode: Option<BlendMode>) {
        self.image.blend_mode = mode;
    }
    fn get_blend_mode(&self) -> Option<BlendMode> {
        self.image.blend_mode
    }
}

/// Set the canvas to render to. Specifying `Option::None` will cause all
/// rendering to be done directly to the screen.
pub fn set_canvas(ctx: &mut Context, target: Option<&Canvas>) {
    match target {
        Some(surface) => {
            ctx.gfx_context.data.out = surface.target.clone();
        }
        None => {
            ctx.gfx_context.data.out = ctx.gfx_context.screen_render_target.clone();
        }
    };
}
<|endoftext|>


<commit_before><commit_msg>Don't ignore HTTP errors by InfluxDB<commit_after><|endoftext|>


<commit_before>use std::collections::HashSet;
use std::net::{TcpListener, SocketAddr, TcpStream};
use std::io::prelude::*;
use std::thread;
use std::sync::mpsc::{Sender, Receiver, channel};
use std::io::BufReader;

pub struct Server {
    messages: Option<Sender<Message>>,
    addr: SocketAddr,
    thread: Option<thread::JoinHandle<()>>,
}

enum Message {
    Read(String),
    Write(String),
}

fn run(listener: &TcpListener, rx: &Receiver<Message>) {
    let mut socket = BufReader::new(listener.accept().unwrap().0);
    for msg in rx.iter() {
        match msg {
            Message::Read(ref expected) => {
                let mut expected = &expected[..];
                let mut expected_headers = HashSet::new();
                while let Some(i) = expected.find("\n") {
                    let line = &expected[..i + 1];
                    expected = &expected[i + 1..];
                    if line == "\r" {
                        break
                    }
                    expected_headers.insert(line);
                }
                if expected.len() > 0 {
                    assert!(expected_headers.insert(expected));
                }

                while expected_headers.len() > 0 {
                    let mut actual = String::new();
                    t!(socket.read_line(&mut actual));
                    if !expected_headers.remove(&actual[..]) {
                        panic!("unexpected header: {:?}", actual);
                    }
                }
                for header in expected_headers {
                    panic!("expected header but not found: {:?}", header);
                }

                let mut buf = vec![0; expected.len()];
                if buf.len() > 0 {
                    t!(socket.read_exact(&mut buf));
                    assert_eq!(buf, expected.as_bytes());
                }
            }
            Message::Write(ref to_write) => {
                t!(socket.get_mut().write_all(to_write.as_bytes()));
                return
            }
        }
    }

    let mut dst = Vec::new();
    t!(socket.read_to_end(&mut dst));
    assert!(dst.len() == 0);
}

impl Server {
    pub fn new() -> Server {
        let listener = t!(TcpListener::bind("127.0.0.1:0"));
        let addr = t!(listener.local_addr());
        let (tx, rx) = channel();
        let thread = thread::spawn(move || run(&listener, &rx));
        Server {
            messages: Some(tx),
            addr: addr,
            thread: Some(thread),
        }
    }

    pub fn receive(&self, msg: &str) {
        let msg = msg.replace("$PORT", &self.addr.port().to_string());
        self.msg(Message::Read(msg));
    }

    pub fn send(&self, msg: &str) {
        let msg = msg.replace("$PORT", &self.addr.port().to_string());
        self.msg(Message::Write(msg));
    }

    fn msg(&self, msg: Message) {
        t!(self.messages.as_ref().unwrap().send(msg));
    }

    pub fn addr(&self) -> &SocketAddr {
        &self.addr
    }

    pub fn url(&self, path: &str) -> String {
        format!("http://{}{}", self.addr, path)
    }
}

impl Drop for Server {
    fn drop(&mut self) {
        drop(TcpStream::connect(&self.addr));
        drop(self.messages.take());
        let res = self.thread.take().unwrap().join();
        if !thread::panicking() {
            t!(res);
        } else if let Err(e) = res {
            println!("child server thread also failed: {:?}", e);
        }
    }
}
<commit_msg>Try to make tests more robust?<commit_after>use std::collections::HashSet;
use std::net::{TcpListener, SocketAddr, TcpStream};
use std::io::prelude::*;
use std::thread;
use std::sync::mpsc::{Sender, Receiver, channel};
use std::io::BufReader;

pub struct Server {
    messages: Option<Sender<Message>>,
    addr: SocketAddr,
    thread: Option<thread::JoinHandle<()>>,
}

enum Message {
    Read(String),
    Write(String),
}

fn run(listener: &TcpListener, rx: &Receiver<Message>) {
    let mut socket = BufReader::new(listener.accept().unwrap().0);
    for msg in rx.iter() {
        match msg {
            Message::Read(ref expected) => {
                let mut expected = &expected[..];
                let mut expected_headers = HashSet::new();
                while let Some(i) = expected.find("\n") {
                    let line = &expected[..i + 1];
                    expected = &expected[i + 1..];
                    if line == "\r" || line == "" {
                        break
                    }
                    expected_headers.insert(line);
                }
                if expected.len() > 0 {
                    assert!(expected_headers.insert(expected));
                }

                while expected_headers.len() > 0 {
                    let mut actual = String::new();
                    t!(socket.read_line(&mut actual));
                    if !expected_headers.remove(&actual[..]) {
                        panic!("unexpected header: {:?}", actual);
                    }
                }
                for header in expected_headers {
                    panic!("expected header but not found: {:?}", header);
                }

                let mut buf = vec![0; expected.len()];
                if buf.len() > 0 {
                    t!(socket.read_exact(&mut buf));
                    assert_eq!(buf, expected.as_bytes());
                }
            }
            Message::Write(ref to_write) => {
                t!(socket.get_mut().write_all(to_write.as_bytes()));
                return
            }
        }
    }

    let mut dst = Vec::new();
    t!(socket.read_to_end(&mut dst));
    assert!(dst.len() == 0);
}

impl Server {
    pub fn new() -> Server {
        let listener = t!(TcpListener::bind("127.0.0.1:0"));
        let addr = t!(listener.local_addr());
        let (tx, rx) = channel();
        let thread = thread::spawn(move || run(&listener, &rx));
        Server {
            messages: Some(tx),
            addr: addr,
            thread: Some(thread),
        }
    }

    pub fn receive(&self, msg: &str) {
        let msg = msg.replace("$PORT", &self.addr.port().to_string());
        self.msg(Message::Read(msg));
    }

    pub fn send(&self, msg: &str) {
        let msg = msg.replace("$PORT", &self.addr.port().to_string());
        self.msg(Message::Write(msg));
    }

    fn msg(&self, msg: Message) {
        t!(self.messages.as_ref().unwrap().send(msg));
    }

    pub fn addr(&self) -> &SocketAddr {
        &self.addr
    }

    pub fn url(&self, path: &str) -> String {
        format!("http://{}{}", self.addr, path)
    }
}

impl Drop for Server {
    fn drop(&mut self) {
        drop(TcpStream::connect(&self.addr));
        drop(self.messages.take());
        let res = self.thread.take().unwrap().join();
        if !thread::panicking() {
            t!(res);
        } else if let Err(e) = res {
            println!("child server thread also failed: {:?}", e);
        }
    }
}
<|endoftext|>


<commit_before>use std::cmp;
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};

/// A simple implementation of a [HyperLogLog](https://en.wikipedia.org/wiki/HyperLogLog)
pub struct HyperLogLog {
    registers: Vec<u64>,
    b: usize,
}

impl HyperLogLog {
    /// Creates a new, empty HyperLogLog.
    ///
    /// - `b` number of bits used for register selection, number of registers within the
    ///   HyperLogLog will be `2^b`. `b` must be in `[4, 16]`
    ///
    /// Panics when `b` is out of bounds.
    pub fn new(b: usize) -> HyperLogLog {
        assert!(b >= 4);
        assert!(b <= 16);

        let m = (1 as usize) << b;
        let registers = (0..m).map(|_| 0).collect();
        HyperLogLog {
            registers: registers,
            b: b,
        }
    }

    /// Adds an element to the HyperLogLog.
    pub fn add<T>(&mut self, obj: &T)
    where
        T: Hash,
    {
        let mut hasher = DefaultHasher::new();
        obj.hash(&mut hasher);
        let h: u64 = hasher.finish();

        let w = h >> self.b;
        let j = h - (w << self.b);
        let p = w.leading_zeros() + 1 - (self.b as u32);

        let m_old = self.registers[j as usize];
        self.registers[j as usize] = cmp::max(m_old, p as u64);
    }

    /// Guess the number of unique elements seen by the HyperLogLog.
    pub fn count(&self) -> usize {
        let m = self.registers.len() as f64;

        let z = 1f64 /
            self.registers
                .iter()
                .map(|&x| 2f64.powi(-(x as i32)))
                .sum::<f64>();

        let am = if m >= 128. {
            0.7213 / (1. + 1.079 / m)
        } else if m >= 64. {
            0.709
        } else if m >= 32. {
            0.697
        } else {
            0.673
        };

        let e = am * m * m * z;

        let e_star = if e <= 5. / 2. * m {
            // small range correction
            let v = self.registers.iter().filter(|&&x| x == 0).count();
            if v != 0 {
                m * (m / (v as f64)).ln()
            } else {
                e
            }
        } else if e <= 1. / 30. * 2f64.powi(32) {
            // intermediate range => no correction
            e
        } else {
            // large range correction
            -2f64.powi(32) * (1. - e / 2f64.powi(32)).ln()
        };

        e_star as usize
    }
}

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

    #[test]
    fn empty() {
        let hll = HyperLogLog::new(8);
        assert_eq!(hll.count(), 0);
    }

    #[test]
    fn add_b4_n1k() {
        let mut hll = HyperLogLog::new(4);
        for i in 0..1000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 571);
    }

    #[test]
    fn add_b8_n1k() {
        let mut hll = HyperLogLog::new(8);
        for i in 0..1000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 966);
    }

    #[test]
    fn add_b12_n1k() {
        let mut hll = HyperLogLog::new(12);
        for i in 0..1000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 984);
    }

    #[test]
    fn add_b16_n1k() {
        let mut hll = HyperLogLog::new(16);
        for i in 0..1000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 998);
    }

    #[test]
    fn add_b8_n10k() {
        let mut hll = HyperLogLog::new(8);
        for i in 0..10000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 10196);
    }

    #[test]
    fn add_b12_n10k() {
        let mut hll = HyperLogLog::new(12);
        for i in 0..10000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 10303);
    }

    #[test]
    fn add_b16_n10k() {
        let mut hll = HyperLogLog::new(16);
        for i in 0..10000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 10055);
    }

    #[test]
    fn add_b16_n100k() {
        let mut hll = HyperLogLog::new(16);
        for i in 0..100000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 100551);
    }

    #[test]
    fn add_b16_n1m() {
        let mut hll = HyperLogLog::new(16);
        for i in 0..1000000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 1000226);
    }
}
<commit_msg>hyperloglog: impl clear<commit_after>use std::cmp;
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};

/// A simple implementation of a [HyperLogLog](https://en.wikipedia.org/wiki/HyperLogLog)
pub struct HyperLogLog {
    registers: Vec<u64>,
    b: usize,
}

impl HyperLogLog {
    /// Creates a new, empty HyperLogLog.
    ///
    /// - `b` number of bits used for register selection, number of registers within the
    ///   HyperLogLog will be `2^b`. `b` must be in `[4, 16]`
    ///
    /// Panics when `b` is out of bounds.
    pub fn new(b: usize) -> HyperLogLog {
        assert!(b >= 4);
        assert!(b <= 16);

        let m = (1 as usize) << b;
        let registers = vec![0; m];
        HyperLogLog {
            registers: registers,
            b: b,
        }
    }

    /// Adds an element to the HyperLogLog.
    pub fn add<T>(&mut self, obj: &T)
    where
        T: Hash,
    {
        let mut hasher = DefaultHasher::new();
        obj.hash(&mut hasher);
        let h: u64 = hasher.finish();

        let w = h >> self.b;
        let j = h - (w << self.b);
        let p = w.leading_zeros() + 1 - (self.b as u32);

        let m_old = self.registers[j as usize];
        self.registers[j as usize] = cmp::max(m_old, p as u64);
    }

    /// Guess the number of unique elements seen by the HyperLogLog.
    pub fn count(&self) -> usize {
        let m = self.registers.len() as f64;

        let z = 1f64 /
            self.registers
                .iter()
                .map(|&x| 2f64.powi(-(x as i32)))
                .sum::<f64>();

        let am = if m >= 128. {
            0.7213 / (1. + 1.079 / m)
        } else if m >= 64. {
            0.709
        } else if m >= 32. {
            0.697
        } else {
            0.673
        };

        let e = am * m * m * z;

        let e_star = if e <= 5. / 2. * m {
            // small range correction
            let v = self.registers.iter().filter(|&&x| x == 0).count();
            if v != 0 {
                m * (m / (v as f64)).ln()
            } else {
                e
            }
        } else if e <= 1. / 30. * 2f64.powi(32) {
            // intermediate range => no correction
            e
        } else {
            // large range correction
            -2f64.powi(32) * (1. - e / 2f64.powi(32)).ln()
        };

        e_star as usize
    }

    /// Empties the HyperLogLog.
    pub fn clear(&mut self) {
        self.registers = vec![0; self.registers.len()];
    }
}

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

    #[test]
    fn empty() {
        let hll = HyperLogLog::new(8);
        assert_eq!(hll.count(), 0);
    }

    #[test]
    fn add_b4_n1k() {
        let mut hll = HyperLogLog::new(4);
        for i in 0..1000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 571);
    }

    #[test]
    fn add_b8_n1k() {
        let mut hll = HyperLogLog::new(8);
        for i in 0..1000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 966);
    }

    #[test]
    fn add_b12_n1k() {
        let mut hll = HyperLogLog::new(12);
        for i in 0..1000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 984);
    }

    #[test]
    fn add_b16_n1k() {
        let mut hll = HyperLogLog::new(16);
        for i in 0..1000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 998);
    }

    #[test]
    fn add_b8_n10k() {
        let mut hll = HyperLogLog::new(8);
        for i in 0..10000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 10196);
    }

    #[test]
    fn add_b12_n10k() {
        let mut hll = HyperLogLog::new(12);
        for i in 0..10000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 10303);
    }

    #[test]
    fn add_b16_n10k() {
        let mut hll = HyperLogLog::new(16);
        for i in 0..10000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 10055);
    }

    #[test]
    fn add_b16_n100k() {
        let mut hll = HyperLogLog::new(16);
        for i in 0..100000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 100551);
    }

    #[test]
    fn add_b16_n1m() {
        let mut hll = HyperLogLog::new(16);
        for i in 0..1000000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 1000226);
    }

    #[test]
    fn clear() {
        let mut hll = HyperLogLog::new(8);
        for i in 0..1000 {
            hll.add(&i);
        }
        hll.clear();
        assert_eq!(hll.count(), 0);
    }
}
<|endoftext|>


<commit_before>extern crate inverted_index;

#[cfg(test)]
mod tests {
    #[test]
    fn noop() {
        assert!(false)
    }
}
<commit_msg>basic test<commit_after>extern crate inverted_index;

#[test]
fn test_index_document() {
    use inverted_index::InvertedIndex;

    let mut idx = InvertedIndex::new();
    idx.index("Hello, World!".to_string());
}
<|endoftext|>


<commit_before>use std::str::FromStr;

#[derive(Debug)]
pub enum Instruction {
    NOP,
    MOV { src: Operand, dst: Operand },
    SWP,
    SAV,
    ADD { addend: Operand },
    SUB { subtrahend: Operand} ,
    NEG,
    J { cond: Condition, dst: Label},
    JRO { dst: Operand },
}

impl FromStr for Instruction {
    type Err = &'static str;

    fn from_str(insn: &str) -> Result<Instruction, Self::Err> {
        let words: Vec<&str> = insn.split(' ').collect();

        match words.len() {
            1 => match words[0] {
                "NOP" => Ok(Instruction::NOP),
                "SWP" => Ok(Instruction::SWP),
                "SAV" => Ok(Instruction::SAV),
                "NEG" => Ok(Instruction::NEG),
                _ => Err("Bad opcode for # of arguments"),
            },

            2 => match words[0] {
                "ADD" => Operand::from_str(words[1]).map(|o| Instruction::ADD { addend: o }),
                "SUB" => Operand::from_str(words[1]).map(|o| Instruction::SUB { subtrahend: o }),
                "JMP" => Ok(Instruction::J { cond: Condition::Unconditional, dst: words[1].to_string() }),
                "JEZ" => Ok(Instruction::J { cond: Condition::Ez,            dst: words[1].to_string() }),
                "JNZ" => Ok(Instruction::J { cond: Condition::Nz,            dst: words[1].to_string() }),
                "JGZ" => Ok(Instruction::J { cond: Condition::Gz,            dst: words[1].to_string() }),
                "JLZ" => Ok(Instruction::J { cond: Condition::Lz,            dst: words[1].to_string() }),
                "JRO" => Operand::from_str(words[1]).map(|o| Instruction::JRO { dst: o }),
                _ => Err("Bad opcode for # of arguments"),
            },

            3 => match words[0] {
                "MOV" => Operand::from_str(words[1]).and_then(|s| Operand::from_str(words[2]).map(|d| (s, d)))
                            .map(|(s, d)| Instruction::MOV { src: s, dst: d }),
                _ => Err("Bad opcode for # of arguments"),
            },

            _ => Err("number of args")
        }
    }
}

#[derive(Debug)]
pub enum Port {
    Up,
    Down,
    Left,
    Right,
}

impl FromStr for Port {
    type Err = &'static str;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "UP" => Ok(Port::Up),
            "DOWN" => Ok(Port::Down),
            "LEFT" => Ok(Port::Left),
            "RIGHT" => Ok(Port::Right),
            _ => Err("bad port"),
        }
    }
}

#[derive(Debug)]
pub enum Operand {
    Lit(i32),
    Port(Port),
    ACC,
}

impl FromStr for Operand {
    type Err = &'static str;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if s == "ACC" {
            return Ok(Operand::ACC);
        }

        let as_int = i32::from_str(s);
        if as_int.is_ok() {
            return Ok(Operand::Lit(as_int.unwrap()));
        }

        let as_port = Port::from_str(s);
        if as_port.is_ok() {
            return Ok(Operand::Port(as_port.unwrap()));
        }

        Err("Invalid operand")
    }
}

#[derive(Debug)]
pub enum Condition {
    Unconditional,
    Ez,
    Nz,
    Gz,
    Lz,
}

pub type Label = String;
<commit_msg>Tests for instruction conversion<commit_after>use std::str::FromStr;

#[derive(Debug, PartialEq)]
pub enum Instruction {
    NOP,
    MOV { src: Operand, dst: Operand },
    SWP,
    SAV,
    ADD { addend: Operand },
    SUB { subtrahend: Operand} ,
    NEG,
    J { cond: Condition, dst: Label},
    JRO { dst: Operand },
}

static BAD_OPCODE_ERR: &'static str = "Bad opcode for # of arguments";
static NUM_ARGS_ERR: &'static str = "Wrong number of arguments";

impl FromStr for Instruction {
    type Err = &'static str;

    fn from_str(insn: &str) -> Result<Instruction, Self::Err> {
        let words: Vec<&str> = insn.split(' ').collect();

        match words.len() {
            1 => match words[0] {
                "NOP" => Ok(Instruction::NOP),
                "SWP" => Ok(Instruction::SWP),
                "SAV" => Ok(Instruction::SAV),
                "NEG" => Ok(Instruction::NEG),
                _ => Err(BAD_OPCODE_ERR),
            },

            2 => match words[0] {
                "ADD" => Operand::from_str(words[1]).map(|o| Instruction::ADD { addend: o }),
                "SUB" => Operand::from_str(words[1]).map(|o| Instruction::SUB { subtrahend: o }),
                "JMP" => Ok(Instruction::J { cond: Condition::Unconditional, dst: words[1].to_string() }),
                "JEZ" => Ok(Instruction::J { cond: Condition::Ez,            dst: words[1].to_string() }),
                "JNZ" => Ok(Instruction::J { cond: Condition::Nz,            dst: words[1].to_string() }),
                "JGZ" => Ok(Instruction::J { cond: Condition::Gz,            dst: words[1].to_string() }),
                "JLZ" => Ok(Instruction::J { cond: Condition::Lz,            dst: words[1].to_string() }),
                "JRO" => Operand::from_str(words[1]).map(|o| Instruction::JRO { dst: o }),
                _ => Err(BAD_OPCODE_ERR),
            },

            3 => match words[0] {
                "MOV" => Operand::from_str(words[1]).and_then(|s| Operand::from_str(words[2]).map(|d| (s, d)))
                            .map(|(s, d)| Instruction::MOV { src: s, dst: d }),
                _ => Err(BAD_OPCODE_ERR),
            },

            _ => Err(NUM_ARGS_ERR)
        }
    }
}

#[test]
fn instruction_from_str() {
    fn i(s: &str) -> Instruction {
        Instruction::from_str(s).unwrap()
    }
    assert_eq!(i("NOP"), Instruction::NOP);
    assert_eq!(i("SWP"), Instruction::SWP);
    assert_eq!(i("SAV"), Instruction::SAV);
    assert_eq!(i("NEG"), Instruction::NEG);
    assert_eq!(Instruction::from_str("BOGUS").unwrap_err(), BAD_OPCODE_ERR);

    assert_eq!(i("ADD 10"), Instruction::ADD { addend: Operand::Lit(10) });
    assert_eq!(i("SUB 10"), Instruction::SUB { subtrahend: Operand::Lit(10) });
    assert_eq!(i("JMP LOC"), Instruction::J { cond: Condition::Unconditional,   dst: "LOC".to_string() });
    assert_eq!(i("JEZ LOC"), Instruction::J { cond: Condition::Ez,              dst: "LOC".to_string() });
    assert_eq!(i("JGZ LOC"), Instruction::J { cond: Condition::Gz,              dst: "LOC".to_string() });
    assert_eq!(i("JLZ LOC"), Instruction::J { cond: Condition::Lz,              dst: "LOC".to_string() });
    assert_eq!(i("JRO 1"), Instruction::JRO { dst: Operand::Lit(1) });
    assert_eq!(Instruction::from_str("JEQ LOC").unwrap_err(), BAD_OPCODE_ERR);

    assert_eq!(i("MOV UP DOWN"),    Instruction::MOV { src: Operand::Port(Port::Up), dst: Operand::Port(Port::Down) });
    //assert_eq!(i("MOV  UP  DOWN"), Instruction::MOV { src: Operand::Port(Port::Up), dst: Operand::Port(Port::Down) });
    assert_eq!(i("MOV UP ACC"),     Instruction::MOV { src: Operand::Port(Port::Up), dst: Operand::ACC });
    assert_eq!(i("MOV ACC ACC"),    Instruction::MOV { src: Operand::ACC, dst: Operand::ACC });
    assert_eq!(Instruction::from_str("MV UP ACC").unwrap_err(), BAD_OPCODE_ERR);

    assert_eq!(Instruction::from_str("1 2 3 4").unwrap_err(), NUM_ARGS_ERR);
}

#[derive(Debug, PartialEq)]
pub enum Port {
    Up,
    Down,
    Left,
    Right,
}

impl FromStr for Port {
    type Err = &'static str;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "UP" => Ok(Port::Up),
            "DOWN" => Ok(Port::Down),
            "LEFT" => Ok(Port::Left),
            "RIGHT" => Ok(Port::Right),
            _ => Err("bad port"),
        }
    }
}

#[test]
fn port_from_str() {
    assert_eq!(Port::from_str("UP").unwrap(),   Port::Up);
    assert_eq!(Port::from_str("DOWN").unwrap(), Port::Down);
    assert_eq!(Port::from_str("LEFT").unwrap(), Port::Left);
    assert_eq!(Port::from_str("RIGHT").unwrap(), Port::Right);
    assert_eq!(Port::from_str("OTHER").unwrap_err(), "bad port");
}

#[derive(Debug, PartialEq)]
pub enum Operand {
    Lit(i32),
    Port(Port),
    ACC,
}

impl FromStr for Operand {
    type Err = &'static str;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if s == "ACC" {
            return Ok(Operand::ACC);
        }

        let as_int = i32::from_str(s);
        if as_int.is_ok() {
            return Ok(Operand::Lit(as_int.unwrap()));
        }

        let as_port = Port::from_str(s);
        if as_port.is_ok() {
            return Ok(Operand::Port(as_port.unwrap()));
        }

        Err("Invalid operand")
    }
}

#[test]
fn operand_from_str() {
    assert_eq!(Operand::from_str("ACC").unwrap(), Operand::ACC);
    assert_eq!(Operand::from_str("32").unwrap(), Operand::Lit(32));
    assert_eq!(Operand::from_str("UP").unwrap(), Operand::Port(Port::Up));
    assert_eq!(Operand::from_str("FOO").unwrap_err(), "Invalid operand");
}

#[derive(Debug, PartialEq)]
pub enum Condition {
    Unconditional,
    Ez,
    Nz,
    Gz,
    Lz,
}

pub type Label = String;
<|endoftext|>


<commit_before>// opcode enumeration suffix: // addressing mode:
// imm = #$00                 // immediate
// zp = $00                   // zero page
// zpx = $00,X                // zero page with X
// zpy = $00,Y                // zero page with Y
// izx = ($00,X)              // indexed indirect (X)
// izy = ($00),Y              // indirect indexed (Y)
// abs = $0000                // absolute
// abx = $0000,X              // absolute indexed with X
// aby = $0000,Y              // absolute indexed with Y
// ind = ($0000)              // indirect
// rel = $0000                // relative to PC/IP

use std::fmt;

pub enum AddrMode {
    Implied,
    Accumulator,
    Immediate,
    Absolute,
    AbsoluteIndexedX(bool), // extra cycle?
    AbsoluteIndexedY(bool), // extra cycle?
    Zeropage,
    ZeropageIndexedX,
    ZeropageIndexedY,
    Relative,
    Indirect,
    IndexedIndirectX,
    IndirectIndexedY(bool) // extra cycle?
}

pub enum CPURegister {
    A, X, Y
}

impl fmt::Display for CPURegister {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let reg_name = match *self {
            CPURegister::A => "A",
            CPURegister::X => "X",
            CPURegister::Y => "Y"
        };

        write!(f, "{}", reg_name)
    }
}

pub enum OpCode {
    // Load/store
    LDA, LDX, LDY, STA, STX, STY,
    // Register transfers
    TAX, TAY, TXA, TYA,
    // Stack operations
    TSX, TXS, PHA, PHP, PLA, PLP,
    // Logical
    AND, EOR, ORA, BIT,
    // Arithmetic
    ADC, SBC, CMP, CPX, CPY,
    // Inc/Dec
    INC, INX, INY, DEC, DEX, DEY,
    // Shifts
    ASL, LSR, ROL, ROR,
    // Jump calls
    JMP, JSR, RTS,
    // Branches
    BCC, BCS, BEQ, BMI, BNE, BPL, BVC, BVS,
    // Status flag changes
    CLC, CLD, CLI, CLV, SEC, SED, SEI,
    // System functions
    BRK, NOP, RTI,
    // forbidden/undocumented
    HLT, SLO, ANC, RLA, SRE, RRA, ALR,
    SAX, XAA, AHX, TAS, SHY, SHX, ARR,
    LAX, LAS, DCP, AXS, ISC
}

impl fmt::Display for OpCode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let op_name = match *self {
            OpCode::LDA => "LDA", OpCode::LDX => "LDX", OpCode::LDY => "LDY", OpCode::STA => "STA",
            OpCode::STX => "STX", OpCode::STY => "STY", OpCode::TAX => "TAX", OpCode::TAY => "TAY",
            OpCode::TXA => "TXA", OpCode::TYA => "TYA", OpCode::TSX => "TSX", OpCode::TXS => "TXS",
            OpCode::PHA => "PHA", OpCode::PHP => "PHP", OpCode::PLA => "PLA", OpCode::PLP => "PLP",
            OpCode::AND => "AND", OpCode::EOR => "EOR", OpCode::ORA => "ORA", OpCode::BIT => "BIT",
            OpCode::ADC => "ADC", OpCode::SBC => "SBC", OpCode::CMP => "CMP", OpCode::CPX => "CPX",
            OpCode::CPY => "CPY", OpCode::INC => "INC", OpCode::INX => "INX", OpCode::INY => "INY",
            OpCode::DEC => "DEC", OpCode::DEX => "DEX", OpCode::DEY => "DEY", OpCode::ASL => "ASL",
            OpCode::LSR => "LSR", OpCode::ROL => "ROL", OpCode::ROR => "ROR", OpCode::JMP => "JMP",
            OpCode::JSR => "JSR", OpCode::RTS => "RTS", OpCode::BCC => "BCC", OpCode::BCS => "BCS",
            OpCode::BEQ => "BEQ", OpCode::BMI => "BMI", OpCode::BNE => "BNE", OpCode::BPL => "BPL",
            OpCode::BVC => "BVC", OpCode::BVS => "BVS", OpCode::CLC => "CLC", OpCode::CLD => "CLD",
            OpCode::CLI => "CLI", OpCode::CLV => "CLV", OpCode::SEC => "SEC", OpCode::SED => "SED",
            OpCode::SEI => "SEI", OpCode::BRK => "BRK", OpCode::NOP => "NOP", OpCode::RTI => "RTI",
            OpCode::HLT => "HLT", OpCode::SLO => "SLO", OpCode::ANC => "ANC", OpCode::RLA => "RLA",
            OpCode::SRE => "SRE", OpCode::RRA => "RRA", OpCode::ALR => "ALR", OpCode::SAX => "SAX",
            OpCode::XAA => "XAA", OpCode::AHX => "AHX", OpCode::TAS => "TAS", OpCode::SHY => "SHY",
            OpCode::SHX => "SHX", OpCode::ARR => "ARR", OpCode::LAX => "LAX", OpCode::LAS => "LAS",
            OpCode::DCP => "DCP", OpCode::AXS => "AXS", OpCode::ISC => "ISC",
        };

        write!(f, "{}", op_name)
    }
}

pub struct Instruction {
    pub opcode: OpCode,
    pub cycles: u8, // how many cycles to execute the operation?
    pub addr_mode: AddrMode,
    pub address: u16,
    pub operand: Option<u16>,
    pub registers_read: Option<Vec<CPURegister>>, // registers read by this instruction
    pub registers_written: Option<Vec<CPURegister>> // registers written by this instruction
}

impl fmt::Display for Instruction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let op_value = if let Some(v) = self.operand {
            v
        } else {
            0
        };

        let operand = match self.addr_mode {
            AddrMode::Implied => format!(""),
            AddrMode::Accumulator => format!("A"),
            AddrMode::Immediate => format!("#${:02X}", op_value),
            AddrMode::Absolute => format!("${:04X}  ", op_value),
            AddrMode::AbsoluteIndexedX(_) => format!("${:04X},X", op_value),
            AddrMode::AbsoluteIndexedY(_) => format!("${:04X},Y", op_value),
            AddrMode::Zeropage => format!("${:02X}", op_value),
            AddrMode::ZeropageIndexedX => format!("${:02X},X", op_value),
            AddrMode::ZeropageIndexedY => format!("${:02X},Y", op_value),
            // TODO: check wrapping?
            AddrMode::Relative => format!("${:04X}", (self.address as i16 + (2 + op_value as i8) as i16) as u16),
            AddrMode::Indirect => format!("(${:04X})", op_value),
            AddrMode::IndexedIndirectX => format!("(${:02X},X)", op_value),
            AddrMode::IndirectIndexedY(_) => format!("(${:02X}),Y", op_value)
        };

        write!(f, "${:04X}: {} {}", self.address, self.opcode, operand)
    }
}

impl Instruction {
    fn new(opcode: OpCode, address: u16, cycles: u8, addr_mode: AddrMode) -> Instruction {
        Instruction {
            opcode: opcode,
            cycles: cycles,
            addr_mode: addr_mode,
            address: address,
            operand: None,
            registers_read: None,
            registers_written: None
        }
    }
}

fn read_word_le(index: &mut usize, buffer: &[u8]) -> u16 {
    let value_be: u16 = ((buffer[*index] as u16) << 8 & 0xFF00) |
    ((buffer[*index + 0x0001] as u16) & 0x00FF);
    let value_le: u16 = ((value_be << 8) & 0xFF00) | ((value_be >> 8) & 0x00FF);

    *index += 1;
    value_le
}

fn fetch_operand(addr_mode: &AddrMode, index: &mut usize, buffer: &[u8]) -> Option<u16> {
    *index += 1;

    let operand = match *addr_mode {
        AddrMode::Absolute => Some(read_word_le(index, buffer)),
        AddrMode::AbsoluteIndexedX(_) => Some(read_word_le(index, buffer)),
        AddrMode::AbsoluteIndexedY(_) => Some(read_word_le(index, buffer)),
        AddrMode::Zeropage => Some(buffer[*index] as u16),
        AddrMode::ZeropageIndexedX => Some(buffer[*index] as u16),
        AddrMode::ZeropageIndexedY => Some(buffer[*index] as u16),
        AddrMode::Relative => Some(buffer[*index] as u16),
        AddrMode::Immediate => Some(buffer[*index] as u16),
        AddrMode::Indirect => Some(read_word_le(index, buffer)),
        AddrMode::IndexedIndirectX => Some(buffer[*index] as u16),
        AddrMode::IndirectIndexedY(_) => Some(buffer[*index] as u16),
        _ => None
    };

    // move the buffer index past fetched operand (if it exists!)
    if let Some(_) = operand {
        *index += 1;
    }

    operand
}

fn fetch(opcode: OpCode, num_cycles: u8, addr_mode: AddrMode, address: u16, index: &mut usize, buffer: &[u8]) -> Instruction {
    // TODO: cycle count should be adjusted here for certain instructions
    let operand = fetch_operand(&addr_mode, index, buffer);
    let mut instruction = Instruction::new(opcode, address, num_cycles, addr_mode);
    instruction.operand = operand;
    instruction
}

pub fn decode(address: u16, index: &mut usize, memory: &[u8]) -> Instruction {
    match memory[*index] {
        0x05 => fetch(OpCode::ORA, 3, AddrMode::Zeropage, address, index, memory),
        0x0A => fetch(OpCode::ASL, 2, AddrMode::Accumulator, address, index, memory),
        0x15 => fetch(OpCode::ORA, 4, AddrMode::ZeropageIndexedX, address, index, memory),
        0x20 => fetch(OpCode::JSR, 6, AddrMode::Absolute, address, index, memory),
        0x78 => fetch(OpCode::SEI, 2, AddrMode::Implied, address, index, memory),
        0xA2 => fetch(OpCode::LDX, 2, AddrMode::Immediate, address, index, memory),
        0x1D => fetch(OpCode::ORA, 5, AddrMode::AbsoluteIndexedX(true), address, index, memory),
        0x1E => fetch(OpCode::ASL, 7, AddrMode::AbsoluteIndexedX(false), address, index, memory),
        0xD0 => fetch(OpCode::BNE, 4, AddrMode::Relative, address, index, memory),
        0x61 => fetch(OpCode::ADC, 6, AddrMode::IndexedIndirectX, address, index, memory),
        0x6C => fetch(OpCode::JMP, 5, AddrMode::Indirect, address, index, memory),
        0x91 => fetch(OpCode::STA, 6, AddrMode::IndirectIndexedY(false), address, index, memory),
        0x96 => fetch(OpCode::STX, 4, AddrMode::ZeropageIndexedY, address, index, memory),
        _ =>  fetch(OpCode::NOP, 7, AddrMode::Implied, address, index, memory),
    }
}
<commit_msg>added debug hex values<commit_after>// opcode enumeration suffix: // addressing mode:
// imm = #$00                 // immediate
// zp = $00                   // zero page
// zpx = $00,X                // zero page with X
// zpy = $00,Y                // zero page with Y
// izx = ($00,X)              // indexed indirect (X)
// izy = ($00),Y              // indirect indexed (Y)
// abs = $0000                // absolute
// abx = $0000,X              // absolute indexed with X
// aby = $0000,Y              // absolute indexed with Y
// ind = ($0000)              // indirect
// rel = $0000                // relative to PC/IP

use std::fmt;

pub enum AddrMode {
    Implied,
    Accumulator,
    Immediate,
    Absolute,
    AbsoluteIndexedX(bool), // extra cycle?
    AbsoluteIndexedY(bool), // extra cycle?
    Zeropage,
    ZeropageIndexedX,
    ZeropageIndexedY,
    Relative,
    Indirect,
    IndexedIndirectX,
    IndirectIndexedY(bool) // extra cycle?
}

pub enum CPURegister {
    A, X, Y
}

impl fmt::Display for CPURegister {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let reg_name = match *self {
            CPURegister::A => "A",
            CPURegister::X => "X",
            CPURegister::Y => "Y"
        };

        write!(f, "{}", reg_name)
    }
}

pub enum OpCode {
    // Load/store
    LDA(u8), LDX(u8), LDY(u8), STA(u8), STX(u8), STY(u8),
    // Register transfers
    TAX(u8), TAY(u8), TXA(u8), TYA(u8),
    // Stack operations
    TSX(u8), TXS(u8), PHA(u8), PHP(u8), PLA(u8), PLP(u8),
    // Logical
    AND(u8), EOR(u8), ORA(u8), BIT(u8),
    // Arithmetic
    ADC(u8), SBC(u8), CMP(u8), CPX(u8), CPY(u8),
    // Inc/Dec
    INC(u8), INX(u8), INY(u8), DEC(u8), DEX(u8), DEY(u8),
    // Shifts
    ASL(u8), LSR(u8), ROL(u8), ROR(u8),
    // Jump calls
    JMP(u8), JSR(u8), RTS(u8),
    // Branches
    BCC(u8), BCS(u8), BEQ(u8), BMI(u8), BNE(u8), BPL(u8), BVC(u8), BVS(u8),
    // Status flag changes
    CLC(u8), CLD(u8), CLI(u8), CLV(u8), SEC(u8), SED(u8), SEI(u8),
    // System functions
    BRK(u8), NOP(u8), RTI(u8),
    // forbidden/undocumented
    HLT(u8), SLO(u8), ANC(u8), RLA(u8), SRE(u8), RRA(u8), ALR(u8),
    SAX(u8), XAA(u8), AHX(u8), TAS(u8), SHY(u8), SHX(u8), ARR(u8),
    LAX(u8), LAS(u8), DCP(u8), AXS(u8), ISC(u8)
}

impl OpCode {
    pub fn to_hex(&self) -> u8 {
        match *self {
            OpCode::LDA(o) => o, OpCode::LDX(o) => o, OpCode::LDY(o) => o, OpCode::STA(o) => o,
            OpCode::STX(o) => o, OpCode::STY(o) => o, OpCode::TAX(o) => o, OpCode::TAY(o) => o,
            OpCode::TXA(o) => o, OpCode::TYA(o) => o, OpCode::TSX(o) => o, OpCode::TXS(o) => o,
            OpCode::PHA(o) => o, OpCode::PHP(o) => o, OpCode::PLA(o) => o, OpCode::PLP(o) => o,
            OpCode::AND(o) => o, OpCode::EOR(o) => o, OpCode::ORA(o) => o, OpCode::BIT(o) => o,
            OpCode::ADC(o) => o, OpCode::SBC(o) => o, OpCode::CMP(o) => o, OpCode::CPX(o) => o,
            OpCode::CPY(o) => o, OpCode::INC(o) => o, OpCode::INX(o) => o, OpCode::INY(o) => o,
            OpCode::DEC(o) => o, OpCode::DEX(o) => o, OpCode::DEY(o) => o, OpCode::ASL(o) => o,
            OpCode::LSR(o) => o, OpCode::ROL(o) => o, OpCode::ROR(o) => o, OpCode::JMP(o) => o,
            OpCode::JSR(o) => o, OpCode::RTS(o) => o, OpCode::BCC(o) => o, OpCode::BCS(o) => o,
            OpCode::BEQ(o) => o, OpCode::BMI(o) => o, OpCode::BNE(o) => o, OpCode::BPL(o) => o,
            OpCode::BVC(o) => o, OpCode::BVS(o) => o, OpCode::CLC(o) => o, OpCode::CLD(o) => o,
            OpCode::CLI(o) => o, OpCode::CLV(o) => o, OpCode::SEC(o) => o, OpCode::SED(o) => o,
            OpCode::SEI(o) => o, OpCode::BRK(o) => o, OpCode::NOP(o) => o, OpCode::RTI(o) => o,
            OpCode::HLT(o) => o, OpCode::SLO(o) => o, OpCode::ANC(o) => o, OpCode::RLA(o) => o,
            OpCode::SRE(o) => o, OpCode::RRA(o) => o, OpCode::ALR(o) => o, OpCode::SAX(o) => o,
            OpCode::XAA(o) => o, OpCode::AHX(o) => o, OpCode::TAS(o) => o, OpCode::SHY(o) => o,
            OpCode::SHX(o) => o, OpCode::ARR(o) => o, OpCode::LAX(o) => o, OpCode::LAS(o) => o,
            OpCode::DCP(o) => o, OpCode::AXS(o) => o, OpCode::ISC(o) => o
        }
    }
}

impl fmt::Display for OpCode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let op_name = match *self {
            OpCode::LDA(_) => "LDA", OpCode::LDX(_) => "LDX", OpCode::LDY(_) => "LDY", OpCode::STA(_) => "STA",
            OpCode::STX(_) => "STX", OpCode::STY(_) => "STY", OpCode::TAX(_) => "TAX", OpCode::TAY(_) => "TAY",
            OpCode::TXA(_) => "TXA", OpCode::TYA(_) => "TYA", OpCode::TSX(_) => "TSX", OpCode::TXS(_) => "TXS",
            OpCode::PHA(_) => "PHA", OpCode::PHP(_) => "PHP", OpCode::PLA(_) => "PLA", OpCode::PLP(_) => "PLP",
            OpCode::AND(_) => "AND", OpCode::EOR(_) => "EOR", OpCode::ORA(_) => "ORA", OpCode::BIT(_) => "BIT",
            OpCode::ADC(_) => "ADC", OpCode::SBC(_) => "SBC", OpCode::CMP(_) => "CMP", OpCode::CPX(_) => "CPX",
            OpCode::CPY(_) => "CPY", OpCode::INC(_) => "INC", OpCode::INX(_) => "INX", OpCode::INY(_) => "INY",
            OpCode::DEC(_) => "DEC", OpCode::DEX(_) => "DEX", OpCode::DEY(_) => "DEY", OpCode::ASL(_) => "ASL",
            OpCode::LSR(_) => "LSR", OpCode::ROL(_) => "ROL", OpCode::ROR(_) => "ROR", OpCode::JMP(_) => "JMP",
            OpCode::JSR(_) => "JSR", OpCode::RTS(_) => "RTS", OpCode::BCC(_) => "BCC", OpCode::BCS(_) => "BCS",
            OpCode::BEQ(_) => "BEQ", OpCode::BMI(_) => "BMI", OpCode::BNE(_) => "BNE", OpCode::BPL(_) => "BPL",
            OpCode::BVC(_) => "BVC", OpCode::BVS(_) => "BVS", OpCode::CLC(_) => "CLC", OpCode::CLD(_) => "CLD",
            OpCode::CLI(_) => "CLI", OpCode::CLV(_) => "CLV", OpCode::SEC(_) => "SEC", OpCode::SED(_) => "SED",
            OpCode::SEI(_) => "SEI", OpCode::BRK(_) => "BRK", OpCode::NOP(_) => "NOP", OpCode::RTI(_) => "RTI",
            OpCode::HLT(_) => "HLT", OpCode::SLO(_) => "SLO", OpCode::ANC(_) => "ANC", OpCode::RLA(_) => "RLA",
            OpCode::SRE(_) => "SRE", OpCode::RRA(_) => "RRA", OpCode::ALR(_) => "ALR", OpCode::SAX(_) => "SAX",
            OpCode::XAA(_) => "XAA", OpCode::AHX(_) => "AHX", OpCode::TAS(_) => "TAS", OpCode::SHY(_) => "SHY",
            OpCode::SHX(_) => "SHX", OpCode::ARR(_) => "ARR", OpCode::LAX(_) => "LAX", OpCode::LAS(_) => "LAS",
            OpCode::DCP(_) => "DCP", OpCode::AXS(_) => "AXS", OpCode::ISC(_) => "ISC",
        };

        write!(f, "{}", op_name)
    }
}

pub struct Instruction {
    pub opcode: OpCode,
    pub cycles: u8, // how many cycles to execute the operation?
    pub addr_mode: AddrMode,
    pub address: u16,
    pub operand: Option<u16>,
    pub registers_read: Option<Vec<CPURegister>>, // registers read by this instruction
    pub registers_written: Option<Vec<CPURegister>> // registers written by this instruction
}

impl fmt::Display for Instruction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let (op_value, op_hi, op_lo) = if let Some(v) = self.operand {
            (v, (v >> 8) & 0xFF, v & 0xFF)
        } else {
            (0, 0, 0)
        };

        let (operand, operand_hex) = match self.addr_mode {
            AddrMode::Implied => (format!(""), format!("      ")),
            AddrMode::Accumulator => (format!("A"), format!("      ")),
            AddrMode::Immediate => (format!("#${:02X}", op_value), format!(" {:02X}   ", op_lo)),
            AddrMode::Absolute => (format!("${:04X}", op_value), format!(" {:02X} {:02X}", op_lo, op_hi)),
            AddrMode::AbsoluteIndexedX(_) => (format!("${:04X},X", op_value), format!(" {:02X} {:02X}", op_lo, op_hi)),
            AddrMode::AbsoluteIndexedY(_) => (format!("${:04X},Y", op_value), format!(" {:02X} {:02X}", op_lo, op_hi)),
            AddrMode::Zeropage => (format!("${:02X}", op_value), format!(" {:02X}   ", op_lo)),
            AddrMode::ZeropageIndexedX => (format!("${:02X},X", op_value), format!(" {:02X}   ", op_lo)),
            AddrMode::ZeropageIndexedY => (format!("${:02X},Y", op_value), format!(" {:02X}   ", op_lo)),
            // TODO: check wrapping?
            AddrMode::Relative => (format!("${:04X}", (self.address as i16 + (2 + op_value as i8) as i16) as u16), format!(" {:02X}   ", op_lo)),
            AddrMode::Indirect => (format!("(${:04X})", op_value), format!(" {:02X} {:02X}", op_lo, op_hi)),
            AddrMode::IndexedIndirectX => (format!("(${:02X},X)", op_value), format!(" {:02X}   ", op_lo)),
            AddrMode::IndirectIndexedY(_) => (format!("(${:02X}),Y", op_value), format!(" {:02X}   ", op_lo))
        };

        write!(f, "${:04X}: {:02X}{} {} {}", self.address, self.opcode.to_hex(), operand_hex, self.opcode, operand)
    }
}

impl Instruction {
    fn new(opcode: OpCode, address: u16, cycles: u8, addr_mode: AddrMode) -> Instruction {
        Instruction {
            opcode: opcode,
            cycles: cycles,
            addr_mode: addr_mode,
            address: address,
            operand: None,
            registers_read: None,
            registers_written: None
        }
    }
}

fn read_word_le(index: &mut usize, buffer: &[u8]) -> u16 {
    let value_be: u16 = ((buffer[*index] as u16) << 8 & 0xFF00) |
    ((buffer[*index + 0x0001] as u16) & 0x00FF);
    let value_le: u16 = ((value_be << 8) & 0xFF00) | ((value_be >> 8) & 0x00FF);

    *index += 1;
    value_le
}

fn fetch_operand(addr_mode: &AddrMode, index: &mut usize, buffer: &[u8]) -> Option<u16> {
    *index += 1;

    let operand = match *addr_mode {
        AddrMode::Absolute => Some(read_word_le(index, buffer)),
        AddrMode::AbsoluteIndexedX(_) => Some(read_word_le(index, buffer)),
        AddrMode::AbsoluteIndexedY(_) => Some(read_word_le(index, buffer)),
        AddrMode::Zeropage => Some(buffer[*index] as u16),
        AddrMode::ZeropageIndexedX => Some(buffer[*index] as u16),
        AddrMode::ZeropageIndexedY => Some(buffer[*index] as u16),
        AddrMode::Relative => Some(buffer[*index] as u16),
        AddrMode::Immediate => Some(buffer[*index] as u16),
        AddrMode::Indirect => Some(read_word_le(index, buffer)),
        AddrMode::IndexedIndirectX => Some(buffer[*index] as u16),
        AddrMode::IndirectIndexedY(_) => Some(buffer[*index] as u16),
        _ => None
    };

    // move the buffer index past fetched operand (if it exists!)
    if let Some(_) = operand {
        *index += 1;
    }

    operand
}

fn fetch(opcode: OpCode, num_cycles: u8, addr_mode: AddrMode, address: u16, index: &mut usize, buffer: &[u8]) -> Instruction {
    // TODO: cycle count should be adjusted here for certain instructions
    let operand = fetch_operand(&addr_mode, index, buffer);
    let mut instruction = Instruction::new(opcode, address, num_cycles, addr_mode);
    instruction.operand = operand;
    instruction
}

pub fn decode(address: u16, index: &mut usize, memory: &[u8]) -> Instruction {
    let op = memory[*index];
    match op {
        0x05 => fetch(OpCode::ORA(op), 3, AddrMode::Zeropage, address, index, memory),
        0x0A => fetch(OpCode::ASL(op), 2, AddrMode::Accumulator, address, index, memory),
        0x15 => fetch(OpCode::ORA(op), 4, AddrMode::ZeropageIndexedX, address, index, memory),
        0x20 => fetch(OpCode::JSR(op), 6, AddrMode::Absolute, address, index, memory),
        0x78 => fetch(OpCode::SEI(op), 2, AddrMode::Implied, address, index, memory),
        0xA2 => fetch(OpCode::LDX(op), 2, AddrMode::Immediate, address, index, memory),
        0x1D => fetch(OpCode::ORA(op), 5, AddrMode::AbsoluteIndexedX(true), address, index, memory),
        0x1E => fetch(OpCode::ASL(op), 7, AddrMode::AbsoluteIndexedX(false), address, index, memory),
        0xD0 => fetch(OpCode::BNE(op), 4, AddrMode::Relative, address, index, memory),
        0x61 => fetch(OpCode::ADC(op), 6, AddrMode::IndexedIndirectX, address, index, memory),
        0x6C => fetch(OpCode::JMP(op), 5, AddrMode::Indirect, address, index, memory),
        0x91 => fetch(OpCode::STA(op), 6, AddrMode::IndirectIndexedY(false), address, index, memory),
        0x96 => fetch(OpCode::STX(op), 4, AddrMode::ZeropageIndexedY, address, index, memory),
        _ =>  fetch(OpCode::NOP(op), 7, AddrMode::Implied, address, index, memory),
    }
}
<|endoftext|>


<commit_before>//! An interpreter implementation.

/// Instructions.
#[derive(PartialEq, Debug, Copy, Clone)]
pub enum Op {
    /// Treats the next instruction as a function call.
    Call,
    /// Treats the next instruction as argument path.
    Path,
    /// Treats the next instruction as function path.
    FnPath,
    /// A function reference.
    FnRef(usize),
    /// An instruction reference.
    OpRef(usize),
    /// End of instructions.
    End,
}

/// Evaluates a program.
pub fn eval(fns: &[Op], ops: &[Op], st: &mut Vec<Op>, calls: &mut Vec<usize>) {
    let mut call = ops.len();
    'e: loop {
        let mut f = None;
        // Push instructions.
        for op in ops[0..call].iter().rev() {
            match op {
                &Op::End => {
                    // Continue previous call.
                    call = match calls.pop() {
                        None => { return; }
                        Some(call) => call,
                    };
                    continue 'e;
                }
                &Op::Call => {
                    // Call a function.
                    call -= 1;
                    f = match st.last() {
                        Some(&Op::FnRef(f)) => Some(f),
                        x => { panic!("Expected `FnRef`, found `{:?}`", x); }
                    };
                    break;
                }
                x => {
                    // Push instruction.
                    call -= 1;
                    st.push(*x);
                }
            }
        }

        if let Some(mut f) = f {
            // Pattern match function.
            'f: loop {
                let mut j = st.len();
                for (i, fi) in fns[f..].iter().enumerate() {
                    match fi {
                        &Op::End => {
                            panic!("Function does not return a value");
                        }
                        &Op::OpRef(o) => {
                            // Remove values and call function.
                            st.truncate(j);
                            calls.push(call);
                            call = o + 1;
                            continue 'e;
                        }
                        _ => {}
                    }
                    if j == 0 {
                        panic!("Stack is shorter than function signature");
                    }
                    j -= 1;
                    if fi != &st[j] {
                        if i == 0 {
                            panic!("No function matched (failed to match name)");
                        }
                        // Try next function.
                        for (k, fi) in fns[f + i..].iter().enumerate() {
                            match fi {
                                &Op::End | &Op::OpRef(_) => {
                                    f = f + i + k + 1;
                                    if f >= fns.len() {
                                        panic!("No function matched (end)");
                                    }
                                    continue 'f;
                                }
                                _ => {}
                            }
                        }
                    }
                }
            }
        }
    }
}

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

    #[test]
    fn not_true() {
        let fns = vec![
            // bool,
            FnRef(0),                   // 0: bool
            End,
            // false,
            FnRef(2),                   // 2: false
            End,
            // true,
            FnRef(4),                   // 4: true
            End,
            // not(bool) -> bool
            FnRef(6),                   // 6: not
            FnRef(0),                   // 7: bool,
            OpRef(1),                   // 8: -> bool
            // not([true] true) -> [false] false
            FnRef(6),                   // 9: not
            Path,
            FnRef(4),                   // 11: true
            FnRef(4),                   // 12: true
            OpRef(5),                   // 13: -> [false] false,
        ];

        let ops = vec![
            // bool
            End,
            FnRef(0),                   // 1: bool
            // [false] false
            End,
            Path,
            FnRef(2),                   // 4: false
            FnRef(2),                   // 5: false
            // call not([true] true)
            End,
            Call,
            FnRef(6),                   // 8: not
            Path,
            FnRef(4),                   // 10: true
            FnRef(4),                   // 11: true
        ];

        let mut stack = vec![];
        let mut calls = vec![];

        eval(&fns, &ops, &mut stack, &mut calls);

        assert_eq!(&stack, &[
            FnRef(2),   // false
            FnRef(2),
            Path
        ]);
    }

    #[test]
    fn not_false() {
        let fns = vec![
            // bool,
            FnRef(0),                   // 0: bool
            End,
            // false,
            FnRef(2),                   // 2: false
            End,
            // true,
            FnRef(4),                   // 4: true
            End,
            // not(bool) -> bool
            FnRef(6),                   // 6: not
            FnRef(0),                   // 7: bool,
            OpRef(1),                   // 8: -> bool
            // not([true] true) -> [false] false
            FnRef(6),                   // 9: not
            Path,
            FnRef(4),                   // 11: true
            FnRef(4),                   // 12: true
            OpRef(5),                   // 13: -> [false] false,
            // not([false] false) -> [true] true
            FnRef(6),                   // 14: not
            Path,
            FnRef(2),                   // 16: false
            FnRef(2),                   // 17: false
            OpRef(9),                   // 18: -> [true] true
        ];

        let ops = vec![
            // bool
            End,
            FnRef(0),                   // 1: bool
            // [false] false
            End,
            Path,
            FnRef(2),                   // 4: false
            FnRef(2),                   // 5: false
            // [true] true
            End,
            Path,
            FnRef(4),                   // 8: false
            FnRef(4),                   // 9: false
            // call not([true] true)
            End,
            Call,
            FnRef(6),                   // 8: not
            Path,
            FnRef(2),                   // 10: false
            FnRef(2),                   // 11: false
        ];

        let mut stack = vec![];
        let mut calls = vec![];

        eval(&fns, &ops, &mut stack, &mut calls);

        assert_eq!(&stack, &[
            FnRef(4),   // true
            FnRef(4),
            Path
        ]);
    }

    #[test]
    fn not_type() {
        let fns = vec![
            // bool,
            FnRef(0),                   // 0: bool
            End,
            // false,
            FnRef(2),                   // 2: false
            End,
            // true,
            FnRef(4),                   // 4: true
            End,
            // not(bool) -> bool
            FnRef(6),                   // 6: not
            FnRef(0),                   // 7: bool,
            OpRef(1),                   // 8: -> bool
            // not([true] true) -> [false] false
            FnRef(6),                   // 9: not
            Path,
            FnRef(4),                   // 11: true
            FnRef(4),                   // 12: true
            OpRef(5),                   // 13: -> [false] false,
        ];

        let ops = vec![
            // bool
            End,
            FnRef(0),                   // 1: bool
            // [false] false
            End,
            Path,
            FnRef(2),                   // 4: false
            FnRef(2),                   // 5: false
            // call not(bool)
            End,
            Call,
            FnRef(6),                   // 8: not
            FnRef(0),
        ];

        let mut stack = vec![];
        let mut calls = vec![];

        eval(&fns, &ops, &mut stack, &mut calls);

        assert_eq!(&stack, &[
            FnRef(0),   // bool
        ]);
    }
}
<commit_msg>Added panic for missing `End` or `OpRef`<commit_after>//! An interpreter implementation.

/// Instructions.
#[derive(PartialEq, Debug, Copy, Clone)]
pub enum Op {
    /// Treats the next instruction as a function call.
    Call,
    /// Treats the next instruction as argument path.
    Path,
    /// Treats the next instruction as function path.
    FnPath,
    /// A function reference.
    FnRef(usize),
    /// An instruction reference.
    OpRef(usize),
    /// End of instructions.
    End,
}

/// Evaluates a program.
pub fn eval(fns: &[Op], ops: &[Op], st: &mut Vec<Op>, calls: &mut Vec<usize>) {
    let mut call = ops.len();
    'e: loop {
        let mut f = None;
        // Push instructions.
        for op in ops[0..call].iter().rev() {
            match op {
                &Op::End => {
                    // Continue previous call.
                    call = match calls.pop() {
                        None => { return; }
                        Some(call) => call,
                    };
                    continue 'e;
                }
                &Op::Call => {
                    // Call a function.
                    call -= 1;
                    f = match st.last() {
                        Some(&Op::FnRef(f)) => Some(f),
                        x => { panic!("Expected `FnRef`, found `{:?}`", x); }
                    };
                    break;
                }
                x => {
                    // Push instruction.
                    call -= 1;
                    st.push(*x);
                }
            }
        }

        if let Some(mut f) = f {
            // Pattern match function.
            'f: loop {
                let mut j = st.len();
                for (i, fi) in fns[f..].iter().enumerate() {
                    match fi {
                        &Op::End => {
                            panic!("Function does not return a value");
                        }
                        &Op::OpRef(o) => {
                            // Remove values and call function.
                            st.truncate(j);
                            calls.push(call);
                            call = o + 1;
                            continue 'e;
                        }
                        _ => {}
                    }
                    if j == 0 {
                        panic!("Stack is shorter than function signature");
                    }
                    j -= 1;
                    if fi != &st[j] {
                        if i == 0 {
                            panic!("No function matched (failed to match name)");
                        }
                        // Try next function.
                        for (k, fi) in fns[f + i..].iter().enumerate() {
                            match fi {
                                &Op::End | &Op::OpRef(_) => {
                                    f = f + i + k + 1;
                                    if f >= fns.len() {
                                        panic!("No function matched (end)");
                                    }
                                    continue 'f;
                                }
                                _ => {}
                            }
                        }

                        panic!("Expected `End` or `OpRef` after function signature");
                    }
                }
            }
        }
    }
}

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

    #[test]
    fn not_true() {
        let fns = vec![
            // bool,
            FnRef(0),                   // 0: bool
            End,
            // false,
            FnRef(2),                   // 2: false
            End,
            // true,
            FnRef(4),                   // 4: true
            End,
            // not(bool) -> bool
            FnRef(6),                   // 6: not
            FnRef(0),                   // 7: bool,
            OpRef(1),                   // 8: -> bool
            // not([true] true) -> [false] false
            FnRef(6),                   // 9: not
            Path,
            FnRef(4),                   // 11: true
            FnRef(4),                   // 12: true
            OpRef(5),                   // 13: -> [false] false,
        ];

        let ops = vec![
            // bool
            End,
            FnRef(0),                   // 1: bool
            // [false] false
            End,
            Path,
            FnRef(2),                   // 4: false
            FnRef(2),                   // 5: false
            // call not([true] true)
            End,
            Call,
            FnRef(6),                   // 8: not
            Path,
            FnRef(4),                   // 10: true
            FnRef(4),                   // 11: true
        ];

        let mut stack = vec![];
        let mut calls = vec![];

        eval(&fns, &ops, &mut stack, &mut calls);

        assert_eq!(&stack, &[
            FnRef(2),   // false
            FnRef(2),
            Path
        ]);
    }

    #[test]
    fn not_false() {
        let fns = vec![
            // bool,
            FnRef(0),                   // 0: bool
            End,
            // false,
            FnRef(2),                   // 2: false
            End,
            // true,
            FnRef(4),                   // 4: true
            End,
            // not(bool) -> bool
            FnRef(6),                   // 6: not
            FnRef(0),                   // 7: bool,
            OpRef(1),                   // 8: -> bool
            // not([true] true) -> [false] false
            FnRef(6),                   // 9: not
            Path,
            FnRef(4),                   // 11: true
            FnRef(4),                   // 12: true
            OpRef(5),                   // 13: -> [false] false,
            // not([false] false) -> [true] true
            FnRef(6),                   // 14: not
            Path,
            FnRef(2),                   // 16: false
            FnRef(2),                   // 17: false
            OpRef(9),                   // 18: -> [true] true
        ];

        let ops = vec![
            // bool
            End,
            FnRef(0),                   // 1: bool
            // [false] false
            End,
            Path,
            FnRef(2),                   // 4: false
            FnRef(2),                   // 5: false
            // [true] true
            End,
            Path,
            FnRef(4),                   // 8: false
            FnRef(4),                   // 9: false
            // call not([true] true)
            End,
            Call,
            FnRef(6),                   // 8: not
            Path,
            FnRef(2),                   // 10: false
            FnRef(2),                   // 11: false
        ];

        let mut stack = vec![];
        let mut calls = vec![];

        eval(&fns, &ops, &mut stack, &mut calls);

        assert_eq!(&stack, &[
            FnRef(4),   // true
            FnRef(4),
            Path
        ]);
    }

    #[test]
    fn not_type() {
        let fns = vec![
            // bool,
            FnRef(0),                   // 0: bool
            End,
            // false,
            FnRef(2),                   // 2: false
            End,
            // true,
            FnRef(4),                   // 4: true
            End,
            // not(bool) -> bool
            FnRef(6),                   // 6: not
            FnRef(0),                   // 7: bool,
            OpRef(1),                   // 8: -> bool
            // not([true] true) -> [false] false
            FnRef(6),                   // 9: not
            Path,
            FnRef(4),                   // 11: true
            FnRef(4),                   // 12: true
            OpRef(5),                   // 13: -> [false] false,
        ];

        let ops = vec![
            // bool
            End,
            FnRef(0),                   // 1: bool
            // [false] false
            End,
            Path,
            FnRef(2),                   // 4: false
            FnRef(2),                   // 5: false
            // call not(bool)
            End,
            Call,
            FnRef(6),                   // 8: not
            FnRef(0),
        ];

        let mut stack = vec![];
        let mut calls = vec![];

        eval(&fns, &ops, &mut stack, &mut calls);

        assert_eq!(&stack, &[
            FnRef(0),   // bool
        ]);
    }
}
<|endoftext|>


<commit_before>use std::io::{Cursor, Read, Write, stdin, stdout};

use result::BfResult;
use state::State;

/// Program forms which can be interpreted.
pub trait Interpretable {
    /// Interprets a program against the given state.
    fn interpret_state<R: Read, W: Write>(
        &self, state: State, input: R, output: W) -> BfResult<()>;

    /// Interprets a program. If the given `state` is `None`, uses a new, empty state.
    fn interpret<R: Read, W: Write>(
        &self, size: Option<usize>, input: R, output: W) -> BfResult<()>
    {
        let state = size.map(State::with_capacity).unwrap_or_else(|| State::new());
        self.interpret_state(state, input, output)
    }

    /// Interprets a program using stdin and stdout for input and output.
    fn interpret_stdin(&self, size: Option<usize>) -> BfResult<()> {
        self.interpret(size, stdin(), stdout())
    }

    /// Interprets a program from memory, returning a vector of its output.
    fn interpret_memory(&self, size: Option<usize>, input: &[u8]) -> BfResult<Vec<u8>> {
        let input = Cursor::new(input);
        let mut output = Cursor::new(Vec::new());

        self.interpret(size, input, &mut output)?;
        Ok(output.into_inner())
    }
}

<commit_msg>Fixed doc comment.<commit_after>use std::io::{Cursor, Read, Write, stdin, stdout};

use result::BfResult;
use state::State;

/// Program forms which can be interpreted.
pub trait Interpretable {
    /// Interprets a program against the given state.
    fn interpret_state<R: Read, W: Write>(
        &self, state: State, input: R, output: W) -> BfResult<()>;

    /// Interprets a program. If the given `size` is `None`, the default memory size.
    fn interpret<R: Read, W: Write>(
        &self, size: Option<usize>, input: R, output: W) -> BfResult<()>
    {
        let state = size.map(State::with_capacity).unwrap_or_else(|| State::new());
        self.interpret_state(state, input, output)
    }

    /// Interprets a program using stdin and stdout for input and output.
    fn interpret_stdin(&self, size: Option<usize>) -> BfResult<()> {
        self.interpret(size, stdin(), stdout())
    }

    /// Interprets a program from memory, returning a vector of its output.
    fn interpret_memory(&self, size: Option<usize>, input: &[u8]) -> BfResult<Vec<u8>> {
        let input = Cursor::new(input);
        let mut output = Cursor::new(Vec::new());

        self.interpret(size, input, &mut output)?;
        Ok(output.into_inner())
    }
}

<|endoftext|>