<commit_before>//! The structures used to manage commands sent over to tmux.

use load::tmux::target::*;
use load::tmux;
use std::io;
use std::path::PathBuf;
use std::process::Output;
use std::rc::Rc;
use std::{process, str};

pub trait Command {
    fn call(&self) -> Result<Output, io::Error> {
        tmux::call(&self.args())
    }

    fn args(&self) -> Vec<&str>;
}

/// The Session command is used to fire up a new daemonized session in tmux.
/// `name`: The Name of a named tmux session.
/// `window_name`: The Name of the first window.
/// `root_path`: The root directory for the tmux session.
#[derive(Debug, Clone)]
pub struct Session<'a> {
    pub name: &'a str,
    pub window_name: Rc<String>,
    pub root_path: Option<PathBuf>,
}

impl<'a> Session<'a> {
    pub fn new(name: &'a str, window_name: Rc<String>, root_path: Option<PathBuf>) -> Session<'a> {
        Session {
            name,
            window_name,
            root_path,
        }
    }
}

// TODO: Real logic exists here. Test it!
impl<'a> Command for Session<'a> {
    fn args(&self) -> Vec<&str> {
        let args: Vec<&str> = vec!["new", "-d", "-s", &self.name, "-n", &self.window_name];

        match self.root_path.as_ref() {
            Some(path) => [&args[..], &["-c", path.to_str().unwrap()]].concat(),
            None => args,
        }
    }
}

/// The Window command is used to identify every new window opened in the tmux
/// session.
/// `session_name`: The name of the session.
/// `name`: The named window to be opened.
/// `path`: An `Option<PathBuf>` containing a possible root directory passed to the
/// `-c` arguement.
#[derive(Debug, Clone)]
pub struct Window<'a> {
    pub session_name: &'a str,
    pub name: Rc<String>,
    pub path: Option<PathBuf>,
    pub session_name_arg: String
}

impl<'a> Window<'a> {
    pub fn new(session_name: &'a str, name: Rc<String>, path: Option<PathBuf>) -> Window<'a> {
        let mut name_arg: String = String::from(session_name);
        name_arg.push(':');

        Window {
            session_name,
            name,
            path,
            session_name_arg: name_arg
        }
    }
}

impl<'a> Command for Window<'a> {
    fn args(&self) -> Vec<&str> {
        let args: Vec<&str> = vec!["new-window", "-t", &self.session_name_arg, "-n", &self.name];

        match self.path.as_ref() {
            Some(path) => [&args[..], &["-c", path.to_str().unwrap()]].concat(),
            None => args,
        }
    }
}

/// The Split is used to call split-window on a particular window in the
/// session.
/// `target`: The target window. In the format `{session}:{window}.{paneIndex}`.
/// `path`: An `Option<PathBuf>` containing a possible root directory passed to the
/// `-c` arguement.
#[derive(Debug, Clone)]
pub struct Split {
    pub target: PaneTarget,
    pub path: Option<PathBuf>,
}

impl Split {
    pub fn new(target: PaneTarget, path: Option<PathBuf>) -> Split {
        Split {
            target,
            path,
        }
    }
}

impl Command for Split {
    fn args(&self) -> Vec<&str> {
        let args: Vec<&str> = vec!["split-window", "-t", &self.target.arg_string];

        match self.path.as_ref() {
            Some(path) => [&args[..], &["-c", path.to_str().unwrap()]].concat(),
            None => args,
        }
    }
}

/// The Layout command calls select-layout with a specific pre-defined tmux
/// layout option see `tmux select-layout --help` for more options.
/// `target`: The target window. In the format `{session}:{window}.{paneIndex}`.
/// `layout`: The type of layout. ex `main-horizontal`.
#[derive(Debug, Clone)]
pub struct Layout {
    pub target: String,
    pub layout: String,
}

impl Layout {
    pub fn new(target: String, layout: String) -> Layout {
        Layout {
            target,
            layout,
        }
    }
}

impl Command for Layout {
    fn args(&self) -> Vec<&str> {
        vec!["select-layout", "-t", &self.target, &self.layout]
    }
}

/// A generic `SendKeys` command used to send "typed" commands to tmux. This is
/// used to initialize processes or tasks in specific window. Such as starting log
/// tails or running servers.
/// target: The target window. In the format `{session}:{window}.{paneIndex}`.
/// exec: The cli command to be run. ex. `tail -f logs/development.log`.
#[derive(Debug, Clone)]
pub struct SendKeys {
    pub target: Target,
    pub exec: String,
}

impl SendKeys {
    pub fn new(target: Target, exec: String) -> SendKeys {
        SendKeys {
            target,
            exec
        }
    }
}

impl Command for SendKeys {
    fn args(&self) -> Vec<&str> {
        vec!["send-keys", "-t", &self.target.arg_string(), &self.exec, "KPEnter"]
    }
}

/// Used to attach to the daemonized session.
/// name: The named session to attach too.
/// `path`: An `Option<PathBuf>` containing a possible root directory passed to the
/// `-c` arguement.
#[derive(Debug, Clone)]
pub struct Attach<'a> {
    pub name: SessionTarget<'a>,
    pub root_path: Option<PathBuf>,
}

impl<'a> Attach<'a> {
    pub fn new(name: &'a str, root_path: Option<PathBuf>) -> Attach<'a> {
        Attach {
            name: SessionTarget::new(name),
            root_path,
        }
    }
}

impl<'a> Command for Attach<'a> {
    fn args(&self) -> Vec<&str> {
        let args: Vec<&str> = vec!["attach", "-t", &self.name.arg_string];

        let args = match self.root_path.as_ref() {
            Some(path) => [&args[..], &["-c", path.to_str().unwrap()]].concat(),
            None => args,
        };

        [&args[..], &[">/dev/null"]].concat()
    }

    fn call(&self) -> Result<Output, io::Error> {
        tmux::attach(&self.args())
    }
}

/// Used to move focus back to the first window.
/// target: The target window. In the format `{session}:{window}`.
#[derive(Debug, Clone)]
pub struct SelectWindow {
    pub target: String,
}

impl SelectWindow {
    pub fn new(target: String) -> SelectWindow {
        SelectWindow {
            target,
        }
    }
}

impl Command for SelectWindow {
    fn args(&self) -> Vec<&str> {
        vec!["select-window", "-t", &self.target]
    }
}

/// Used to move focus back to the top pane.
/// target: The target pane. In the format `{session}:{window}.{pane-target}`.
#[derive(Debug, Clone)]
pub struct SelectPane {
    pub target: String,
}

impl SelectPane {
    pub fn new(target: String) -> SelectPane {
        SelectPane {
            target,
        }
    }
}

impl Command for SelectPane {
    fn args(&self) -> Vec<&str> {
        vec!["select-pane", "-t", &self.target]
    }
}

/// Used for executing the `pre` option to execute commands before building the
/// tmux session.
/// exec: The command to execute
#[derive(Debug, Clone)]
pub struct Pre {
    pub exec: String,
}

impl Pre {
    pub fn new(exec: String) -> Pre {
        Pre {
            exec,
        }
    }
}

impl Command for Pre {
    fn args(&self) -> Vec<&str> {
        // No-op!
        vec![]
    }

    fn call(&self) -> Result<Output, io::Error> {
        let cmd_array: Vec<&str> = self.exec.split(' ').collect();
        let (program, args) = cmd_array
            .split_first()
            .expect("Couldn't find args for pre option");

        process::Command::new(program).args(args).output()
    }
}

/// The Command enum. Commands represent the series of commands sent to the
/// running tmux process to build a users env. This is an enum to support
/// containing all the commands that require running in a single Vec. This
/// allows a simple process of first in, first out command execution.
#[derive(Debug, Clone)]
pub enum Commands<'a> {
    Attach(Attach<'a>),
    Layout(Layout),
    Pre(Pre),
    SelectPane(SelectPane),
    SelectWindow(SelectWindow),
    SendKeys(SendKeys),
    Session(Session<'a>),
    Split(Split),
    Window(Window<'a>),
}

impl<'a> Commands<'a> {
    pub fn as_trait(&self) -> &Command {
        match *self {
            Commands::Attach(ref c) => c,
            Commands::Layout(ref c) => c,
            Commands::Pre(ref c) => c,
            Commands::SelectPane(ref c) => c,
            Commands::SelectWindow(ref c) => c,
            Commands::SendKeys(ref c) => c,
            Commands::Session(ref c) => c,
            Commands::Split(ref c) => c,
            Commands::Window(ref c) => c,
        }
    }
}

impl<'a> From<Attach<'a>> for Commands<'a> {
    fn from(command: Attach<'a>) -> Self {
        Commands::Attach(command)
    }
}

impl<'a> From<Layout> for Commands<'a> {
    fn from(command: Layout) -> Self {
        Commands::Layout(command)
    }
}

impl<'a> From<Pre> for Commands<'a> {
    fn from(command: Pre) -> Self {
        Commands::Pre(command)
    }
}

impl<'a> From<SelectPane> for Commands<'a> {
    fn from(command: SelectPane) -> Self {
        Commands::SelectPane(command)
    }
}

impl<'a> From<SelectWindow> for Commands<'a> {
    fn from(command: SelectWindow) -> Self {
        Commands::SelectWindow(command)
    }
}

impl<'a> From<SendKeys> for Commands<'a> {
    fn from(command: SendKeys) -> Self {
        Commands::SendKeys(command)
    }
}

impl<'a> From<Session<'a>> for Commands<'a> {
    fn from(command: Session<'a>) -> Self {
        Commands::Session(command)
    }
}

impl<'a> From<Split> for Commands<'a> {
    fn from(command: Split) -> Self {
        Commands::Split(command)
    }
}

impl<'a> From<Window<'a>> for Commands<'a> {
    fn from(command: Window<'a>) -> Self {
        Commands::Window(command)
    }
}
<commit_msg>Fix borrowed trait objects warning<commit_after>//! The structures used to manage commands sent over to tmux.

use load::tmux::target::*;
use load::tmux;
use std::io;
use std::path::PathBuf;
use std::process::Output;
use std::rc::Rc;
use std::{process, str};

pub trait Command {
    fn call(&self) -> Result<Output, io::Error> {
        tmux::call(&self.args())
    }

    fn args(&self) -> Vec<&str>;
}

/// The Session command is used to fire up a new daemonized session in tmux.
/// `name`: The Name of a named tmux session.
/// `window_name`: The Name of the first window.
/// `root_path`: The root directory for the tmux session.
#[derive(Debug, Clone)]
pub struct Session<'a> {
    pub name: &'a str,
    pub window_name: Rc<String>,
    pub root_path: Option<PathBuf>,
}

impl<'a> Session<'a> {
    pub fn new(name: &'a str, window_name: Rc<String>, root_path: Option<PathBuf>) -> Session<'a> {
        Session {
            name,
            window_name,
            root_path,
        }
    }
}

// TODO: Real logic exists here. Test it!
impl<'a> Command for Session<'a> {
    fn args(&self) -> Vec<&str> {
        let args: Vec<&str> = vec!["new", "-d", "-s", &self.name, "-n", &self.window_name];

        match self.root_path.as_ref() {
            Some(path) => [&args[..], &["-c", path.to_str().unwrap()]].concat(),
            None => args,
        }
    }
}

/// The Window command is used to identify every new window opened in the tmux
/// session.
/// `session_name`: The name of the session.
/// `name`: The named window to be opened.
/// `path`: An `Option<PathBuf>` containing a possible root directory passed to the
/// `-c` arguement.
#[derive(Debug, Clone)]
pub struct Window<'a> {
    pub session_name: &'a str,
    pub name: Rc<String>,
    pub path: Option<PathBuf>,
    pub session_name_arg: String
}

impl<'a> Window<'a> {
    pub fn new(session_name: &'a str, name: Rc<String>, path: Option<PathBuf>) -> Window<'a> {
        let mut name_arg: String = String::from(session_name);
        name_arg.push(':');

        Window {
            session_name,
            name,
            path,
            session_name_arg: name_arg
        }
    }
}

impl<'a> Command for Window<'a> {
    fn args(&self) -> Vec<&str> {
        let args: Vec<&str> = vec!["new-window", "-t", &self.session_name_arg, "-n", &self.name];

        match self.path.as_ref() {
            Some(path) => [&args[..], &["-c", path.to_str().unwrap()]].concat(),
            None => args,
        }
    }
}

/// The Split is used to call split-window on a particular window in the
/// session.
/// `target`: The target window. In the format `{session}:{window}.{paneIndex}`.
/// `path`: An `Option<PathBuf>` containing a possible root directory passed to the
/// `-c` arguement.
#[derive(Debug, Clone)]
pub struct Split {
    pub target: PaneTarget,
    pub path: Option<PathBuf>,
}

impl Split {
    pub fn new(target: PaneTarget, path: Option<PathBuf>) -> Split {
        Split {
            target,
            path,
        }
    }
}

impl Command for Split {
    fn args(&self) -> Vec<&str> {
        let args: Vec<&str> = vec!["split-window", "-t", &self.target.arg_string];

        match self.path.as_ref() {
            Some(path) => [&args[..], &["-c", path.to_str().unwrap()]].concat(),
            None => args,
        }
    }
}

/// The Layout command calls select-layout with a specific pre-defined tmux
/// layout option see `tmux select-layout --help` for more options.
/// `target`: The target window. In the format `{session}:{window}.{paneIndex}`.
/// `layout`: The type of layout. ex `main-horizontal`.
#[derive(Debug, Clone)]
pub struct Layout {
    pub target: String,
    pub layout: String,
}

impl Layout {
    pub fn new(target: String, layout: String) -> Layout {
        Layout {
            target,
            layout,
        }
    }
}

impl Command for Layout {
    fn args(&self) -> Vec<&str> {
        vec!["select-layout", "-t", &self.target, &self.layout]
    }
}

/// A generic `SendKeys` command used to send "typed" commands to tmux. This is
/// used to initialize processes or tasks in specific window. Such as starting log
/// tails or running servers.
/// target: The target window. In the format `{session}:{window}.{paneIndex}`.
/// exec: The cli command to be run. ex. `tail -f logs/development.log`.
#[derive(Debug, Clone)]
pub struct SendKeys {
    pub target: Target,
    pub exec: String,
}

impl SendKeys {
    pub fn new(target: Target, exec: String) -> SendKeys {
        SendKeys {
            target,
            exec
        }
    }
}

impl Command for SendKeys {
    fn args(&self) -> Vec<&str> {
        vec!["send-keys", "-t", &self.target.arg_string(), &self.exec, "KPEnter"]
    }
}

/// Used to attach to the daemonized session.
/// name: The named session to attach too.
/// `path`: An `Option<PathBuf>` containing a possible root directory passed to the
/// `-c` arguement.
#[derive(Debug, Clone)]
pub struct Attach<'a> {
    pub name: SessionTarget<'a>,
    pub root_path: Option<PathBuf>,
}

impl<'a> Attach<'a> {
    pub fn new(name: &'a str, root_path: Option<PathBuf>) -> Attach<'a> {
        Attach {
            name: SessionTarget::new(name),
            root_path,
        }
    }
}

impl<'a> Command for Attach<'a> {
    fn args(&self) -> Vec<&str> {
        let args: Vec<&str> = vec!["attach", "-t", &self.name.arg_string];

        let args = match self.root_path.as_ref() {
            Some(path) => [&args[..], &["-c", path.to_str().unwrap()]].concat(),
            None => args,
        };

        [&args[..], &[">/dev/null"]].concat()
    }

    fn call(&self) -> Result<Output, io::Error> {
        tmux::attach(&self.args())
    }
}

/// Used to move focus back to the first window.
/// target: The target window. In the format `{session}:{window}`.
#[derive(Debug, Clone)]
pub struct SelectWindow {
    pub target: String,
}

impl SelectWindow {
    pub fn new(target: String) -> SelectWindow {
        SelectWindow {
            target,
        }
    }
}

impl Command for SelectWindow {
    fn args(&self) -> Vec<&str> {
        vec!["select-window", "-t", &self.target]
    }
}

/// Used to move focus back to the top pane.
/// target: The target pane. In the format `{session}:{window}.{pane-target}`.
#[derive(Debug, Clone)]
pub struct SelectPane {
    pub target: String,
}

impl SelectPane {
    pub fn new(target: String) -> SelectPane {
        SelectPane {
            target,
        }
    }
}

impl Command for SelectPane {
    fn args(&self) -> Vec<&str> {
        vec!["select-pane", "-t", &self.target]
    }
}

/// Used for executing the `pre` option to execute commands before building the
/// tmux session.
/// exec: The command to execute
#[derive(Debug, Clone)]
pub struct Pre {
    pub exec: String,
}

impl Pre {
    pub fn new(exec: String) -> Pre {
        Pre {
            exec,
        }
    }
}

impl Command for Pre {
    fn args(&self) -> Vec<&str> {
        // No-op!
        vec![]
    }

    fn call(&self) -> Result<Output, io::Error> {
        let cmd_array: Vec<&str> = self.exec.split(' ').collect();
        let (program, args) = cmd_array
            .split_first()
            .expect("Couldn't find args for pre option");

        process::Command::new(program).args(args).output()
    }
}

/// The Command enum. Commands represent the series of commands sent to the
/// running tmux process to build a users env. This is an enum to support
/// containing all the commands that require running in a single Vec. This
/// allows a simple process of first in, first out command execution.
#[derive(Debug, Clone)]
pub enum Commands<'a> {
    Attach(Attach<'a>),
    Layout(Layout),
    Pre(Pre),
    SelectPane(SelectPane),
    SelectWindow(SelectWindow),
    SendKeys(SendKeys),
    Session(Session<'a>),
    Split(Split),
    Window(Window<'a>),
}

impl<'a> Commands<'a> {
    pub fn as_trait(&self) -> &dyn Command {
        match self {
            Commands::Attach(c) => c,
            Commands::Layout(c) => c,
            Commands::Pre(c) => c,
            Commands::SelectPane(c) => c,
            Commands::SelectWindow(c) => c,
            Commands::SendKeys(c) => c,
            Commands::Session(c) => c,
            Commands::Split(c) => c,
            Commands::Window(c) => c,
        }
    }
}

impl<'a> From<Attach<'a>> for Commands<'a> {
    fn from(command: Attach<'a>) -> Self {
        Commands::Attach(command)
    }
}

impl<'a> From<Layout> for Commands<'a> {
    fn from(command: Layout) -> Self {
        Commands::Layout(command)
    }
}

impl<'a> From<Pre> for Commands<'a> {
    fn from(command: Pre) -> Self {
        Commands::Pre(command)
    }
}

impl<'a> From<SelectPane> for Commands<'a> {
    fn from(command: SelectPane) -> Self {
        Commands::SelectPane(command)
    }
}

impl<'a> From<SelectWindow> for Commands<'a> {
    fn from(command: SelectWindow) -> Self {
        Commands::SelectWindow(command)
    }
}

impl<'a> From<SendKeys> for Commands<'a> {
    fn from(command: SendKeys) -> Self {
        Commands::SendKeys(command)
    }
}

impl<'a> From<Session<'a>> for Commands<'a> {
    fn from(command: Session<'a>) -> Self {
        Commands::Session(command)
    }
}

impl<'a> From<Split> for Commands<'a> {
    fn from(command: Split) -> Self {
        Commands::Split(command)
    }
}

impl<'a> From<Window<'a>> for Commands<'a> {
    fn from(command: Window<'a>) -> Self {
        Commands::Window(command)
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::env;

use rustc::ty::layout::{Size};
use rustc_mir::interpret::{Pointer, Memory};
use crate::stacked_borrows::Tag;
use crate::*;

#[derive(Default)]
pub struct EnvVars {
    /// Stores pointers to the environment variables. These variables must be stored as
    /// null-terminated C strings with the `"{name}={value}"` format.
    map: HashMap<Vec<u8>, Pointer<Tag>>,
}

impl EnvVars {
    pub(crate) fn init<'mir, 'tcx>(
        ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>,
        mut excluded_env_vars: Vec<String>,
    ) {
        // Exclude `TERM` var to avoid terminfo trying to open the termcap file.
        excluded_env_vars.push("TERM".to_owned());

        if ecx.machine.communicate {
            for (name, value) in env::vars() {
                if !excluded_env_vars.contains(&name) {
                    let var_ptr = alloc_env_var(name.as_bytes(), value.as_bytes(), ecx.memory_mut());
                    ecx.machine.env_vars.map.insert(name.into_bytes(), var_ptr);
                }
            }
        }
    }
}

fn alloc_env_var<'mir, 'tcx>(
    name: &[u8],
    value: &[u8],
    memory: &mut Memory<'mir, 'tcx, Evaluator<'tcx>>,
) -> Pointer<Tag> {
    let mut bytes = name.to_vec();
    bytes.push(b'=');
    bytes.extend_from_slice(value);
    bytes.push(0);
    memory.allocate_static_bytes(bytes.as_slice(), MiriMemoryKind::Env.into())
}

impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    fn getenv(
        &mut self,
        name_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, Scalar<Tag>> {
        let this = self.eval_context_mut();

        let name_ptr = this.read_scalar(name_op)?.not_undef()?;
        let name = this.memory().read_c_str(name_ptr)?;
        Ok(match this.machine.env_vars.map.get(name) {
            // The offset is used to strip the "{name}=" part of the string.
            Some(var_ptr) => Scalar::Ptr(var_ptr.offset(Size::from_bytes(name.len() as u64 + 1), this)?),
            None => Scalar::ptr_null(&*this.tcx),
        })
    }

    fn setenv(
        &mut self,
        name_op: OpTy<'tcx, Tag>,
        value_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        let name_ptr = this.read_scalar(name_op)?.not_undef()?;
        let value_ptr = this.read_scalar(value_op)?.not_undef()?;
        let value = this.memory().read_c_str(value_ptr)?;
        let mut new = None;
        if !this.is_null(name_ptr)? {
            let name = this.memory().read_c_str(name_ptr)?;
            if !name.is_empty() && !name.contains(&b'=') {
                new = Some((name.to_owned(), value.to_owned()));
            }
        }
        if let Some((name, value)) = new {
            let var_ptr = alloc_env_var(&name, &value, this.memory_mut());
            if let Some(var) = this.machine.env_vars.map.insert(name.to_owned(), var_ptr) {
                this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?;
            }
            Ok(0)
        } else {
            Ok(-1)
        }
    }

    fn unsetenv(
        &mut self,
        name_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        let name_ptr = this.read_scalar(name_op)?.not_undef()?;
        let mut success = None;
        if !this.is_null(name_ptr)? {
            let name = this.memory().read_c_str(name_ptr)?.to_owned();
            if !name.is_empty() && !name.contains(&b'=') {
                success = Some(this.machine.env_vars.map.remove(&name));
            }
        }
        if let Some(old) = success {
            if let Some(var) = old {
                this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?;
            }
            Ok(0)
        } else {
            Ok(-1)
        }
    }

    fn getcwd(
        &mut self,
        buf_op: OpTy<'tcx, Tag>,
        size_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, Scalar<Tag>> {
        let this = self.eval_context_mut();

        if this.machine.communicate {
            let tcx = &{this.tcx.tcx};

            let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?;
            let size = this.read_scalar(size_op)?.to_usize(&*this.tcx)?;
            // If we cannot get the current directory, we return null
            if let Ok(cwd) = env::current_dir() {
                // It is not clear what happens with non-utf8 paths here
                let mut bytes = cwd.display().to_string().into_bytes();
                // If the buffer is smaller than the path, we return null
                if bytes.len() as u64 <= size {
                    // We need `size` bytes exactly
                    bytes.resize(size as usize, 0);
                    this.memory_mut().get_mut(buf.alloc_id)?.write_bytes(tcx, buf, &bytes)?;
                    return Ok(Scalar::Ptr(buf))
                }
            }
            return Ok(Scalar::ptr_null(&*this.tcx));
        }
        throw_unsup_format!("Function not available when isolation is enabled")
    }
}
<commit_msg>Avoid writing more bytes than necessary<commit_after>use std::collections::HashMap;
use std::env;

use rustc::ty::layout::{Size};
use rustc_mir::interpret::{Pointer, Memory};
use crate::stacked_borrows::Tag;
use crate::*;

#[derive(Default)]
pub struct EnvVars {
    /// Stores pointers to the environment variables. These variables must be stored as
    /// null-terminated C strings with the `"{name}={value}"` format.
    map: HashMap<Vec<u8>, Pointer<Tag>>,
}

impl EnvVars {
    pub(crate) fn init<'mir, 'tcx>(
        ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>,
        mut excluded_env_vars: Vec<String>,
    ) {
        // Exclude `TERM` var to avoid terminfo trying to open the termcap file.
        excluded_env_vars.push("TERM".to_owned());

        if ecx.machine.communicate {
            for (name, value) in env::vars() {
                if !excluded_env_vars.contains(&name) {
                    let var_ptr = alloc_env_var(name.as_bytes(), value.as_bytes(), ecx.memory_mut());
                    ecx.machine.env_vars.map.insert(name.into_bytes(), var_ptr);
                }
            }
        }
    }
}

fn alloc_env_var<'mir, 'tcx>(
    name: &[u8],
    value: &[u8],
    memory: &mut Memory<'mir, 'tcx, Evaluator<'tcx>>,
) -> Pointer<Tag> {
    let mut bytes = name.to_vec();
    bytes.push(b'=');
    bytes.extend_from_slice(value);
    bytes.push(0);
    memory.allocate_static_bytes(bytes.as_slice(), MiriMemoryKind::Env.into())
}

impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    fn getenv(
        &mut self,
        name_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, Scalar<Tag>> {
        let this = self.eval_context_mut();

        let name_ptr = this.read_scalar(name_op)?.not_undef()?;
        let name = this.memory().read_c_str(name_ptr)?;
        Ok(match this.machine.env_vars.map.get(name) {
            // The offset is used to strip the "{name}=" part of the string.
            Some(var_ptr) => Scalar::Ptr(var_ptr.offset(Size::from_bytes(name.len() as u64 + 1), this)?),
            None => Scalar::ptr_null(&*this.tcx),
        })
    }

    fn setenv(
        &mut self,
        name_op: OpTy<'tcx, Tag>,
        value_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        let name_ptr = this.read_scalar(name_op)?.not_undef()?;
        let value_ptr = this.read_scalar(value_op)?.not_undef()?;
        let value = this.memory().read_c_str(value_ptr)?;
        let mut new = None;
        if !this.is_null(name_ptr)? {
            let name = this.memory().read_c_str(name_ptr)?;
            if !name.is_empty() && !name.contains(&b'=') {
                new = Some((name.to_owned(), value.to_owned()));
            }
        }
        if let Some((name, value)) = new {
            let var_ptr = alloc_env_var(&name, &value, this.memory_mut());
            if let Some(var) = this.machine.env_vars.map.insert(name.to_owned(), var_ptr) {
                this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?;
            }
            Ok(0)
        } else {
            Ok(-1)
        }
    }

    fn unsetenv(
        &mut self,
        name_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        let name_ptr = this.read_scalar(name_op)?.not_undef()?;
        let mut success = None;
        if !this.is_null(name_ptr)? {
            let name = this.memory().read_c_str(name_ptr)?.to_owned();
            if !name.is_empty() && !name.contains(&b'=') {
                success = Some(this.machine.env_vars.map.remove(&name));
            }
        }
        if let Some(old) = success {
            if let Some(var) = old {
                this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?;
            }
            Ok(0)
        } else {
            Ok(-1)
        }
    }

    fn getcwd(
        &mut self,
        buf_op: OpTy<'tcx, Tag>,
        size_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, Scalar<Tag>> {
        let this = self.eval_context_mut();

        if !this.machine.communicate {
            throw_unsup_format!("Function not available when isolation is enabled")
        }

        let tcx = &{this.tcx.tcx};

        let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?;
        let size = this.read_scalar(size_op)?.to_usize(&*this.tcx)?;
        // If we cannot get the current directory, we return null
        // FIXME: Technically we have to set the `errno` global too
        if let Ok(cwd) = env::current_dir() {
            // It is not clear what happens with non-utf8 paths here
            let mut bytes = cwd.display().to_string().into_bytes();
            // If the buffer is smaller or equal than the path, we return null.
            // FIXME: Technically we have to set the `errno` global too
            if (bytes.len() as u64) < size {
                // We add a `/0` terminator
                bytes.push(0);
                // This is ok because the buffer is larger than the path with the null terminator.
                this.memory_mut().get_mut(buf.alloc_id)?.write_bytes(tcx, buf, &bytes)?;
                return Ok(Scalar::Ptr(buf))
            }
        }
        Ok(Scalar::ptr_null(&*this.tcx))
    }
}
<|endoftext|>


<commit_before>// This is a part of rust-encoding.
// Copyright (c) 2013-2014, Kang Seonghoon.
// See README.md and LICENSE.txt for details.

//! Internal utilities.

#![macro_escape]

use std::{str, mem};
use std::default::Default;
use types;

/// Unchecked conversion to `char`.
pub fn as_char<T:Int+NumCast>(ch: T) -> char {
    unsafe { mem::transmute(ch.to_u32().unwrap()) }
}

/// External iterator for a string's characters with its corresponding byte offset range.
pub struct StrCharIndexIterator<'r> {
    index: uint,
    string: &'r str,
}

impl<'r> Iterator<((uint,uint), char)> for StrCharIndexIterator<'r> {
    #[inline]
    fn next(&mut self) -> Option<((uint,uint), char)> {
        if self.index < self.string.len() {
            let str::CharRange {ch, next} = self.string.char_range_at(self.index);
            let prev = self.index;
            self.index = next;
            Some(((prev, next), ch))
        } else {
            None
        }
    }
}

/// A trait providing an `index_iter` method.
pub trait StrCharIndex<'r> {
    fn index_iter(&self) -> StrCharIndexIterator<'r>;
}

impl<'r> StrCharIndex<'r> for &'r str {
    /// Iterates over each character with corresponding byte offset range.
    fn index_iter(&self) -> StrCharIndexIterator<'r> {
        StrCharIndexIterator { index: 0, string: *self }
    }
}

/// A helper struct for the stateful decoder DSL.
pub struct StatefulDecoderHelper<'a, St> {
    /// The current buffer.
    pub buf: &'a [u8],
    /// The current index to the buffer.
    pub pos: uint,
    /// The output buffer.
    pub output: &'a mut types::StringWriter,
    /// The last codec error. The caller will later collect this.
    pub err: Option<types::CodecError>,
}

impl<'a, St:Default> StatefulDecoderHelper<'a, St> {
    /// Reads one byte from the buffer if any.
    #[inline(always)]
    pub fn read(&mut self) -> Option<u8> {
        match self.buf.get(self.pos) {
            Some(&c) => { self.pos += 1; Some(c) }
            None => None
        }
    }

    /// Resets back to the initial state.
    /// This should be the last expr in the rules.
    #[inline(always)]
    pub fn reset(&self) -> St {
        Default::default()
    }

    /// Writes one Unicode scalar value to the output.
    /// There is intentionally no check for `c`, so the caller should ensure that it's valid.
    /// If this is the last expr in the rules, also resets back to the initial state.
    #[inline(always)]
    pub fn emit(&mut self, c: u32) -> St {
        self.output.write_char(unsafe {mem::transmute(c)});
        Default::default()
    }

    /// Writes a Unicode string to the output.
    /// If this is the last expr in the rules, also resets back to the initial state.
    #[inline(always)]
    pub fn emit_str(&mut self, s: &str) -> St {
        self.output.write_str(s);
        Default::default()
    }

    /// Issues a codec error with given message at the current position.
    /// If this is the last expr in the rules, also resets back to the initial state.
    #[inline(always)]
    pub fn err(&mut self, msg: &'static str) -> St {
        self.err = Some(types::CodecError { upto: self.pos as int, cause: msg.into_maybe_owned() });
        Default::default()
    }

    /// Issues a codec error with given message at the current position minus `backup` bytes.
    /// If this is the last expr in the rules, also resets back to the initial state.
    ///
    /// This should be used to implement "prepending byte to the stream" in the Encoding spec,
    /// which corresponds to `ctx.backup_and_err(1, ...)`.
    #[inline(always)]
    pub fn backup_and_err(&mut self, backup: uint, msg: &'static str) -> St {
        let upto = self.pos as int - backup as int;
        self.err = Some(types::CodecError { upto: upto, cause: msg.into_maybe_owned() });
        Default::default()
    }
}

/// Defines a stateful decoder from given state machine.
macro_rules! stateful_decoder(
    (
        $(#[$decmeta:meta])*
        struct $dec:ident;
        module $stmod:ident; // should be unique from other existing identifiers
        ascii_compatible $asciicompat:expr;
        $(internal $item:item)* // will only be visible from state functions
        initial state $inist:ident($inictx:ident) {
            $(case $($inilhs:pat)|+ => $($inirhs:expr),+;)+
            final => $($inifin:expr),+;
        }
        $(checkpoint state $ckst:ident($ckctx:ident $(, $ckarg:ident: $ckty:ty)*) {
            $(case $($cklhs:pat)|+ => $($ckrhs:expr),+;)+
            final => $($ckfin:expr),+;
        })*
        $(state $st:ident($ctx:ident $(, $arg:ident: $ty:ty)*) {
            $(case $($lhs:pat)|+ => $($rhs:expr),+;)+
            final => $($fin:expr),+;
        })*
    ) => (
        $(#[$decmeta])*
        pub struct $dec {
            st: $stmod::State
        }

        #[allow(non_snake_case_functions)]
        mod $stmod {
            #[deriving(PartialEq,Clone)]
            pub enum State {
                $inist,
                $(
                    $ckst(() $(, $ckty)*),
                )*
                $(
                    $st(() $(, $ty)*),
                )*
            }

            impl ::std::default::Default for State {
                #[inline(always)] fn default() -> State { $inist }
            }

            pub mod internal {
                pub type Context<'a> = ::util::StatefulDecoderHelper<'a, super::State>;

                $($item)*
            }

            pub mod start {
                use super::internal::*;

                #[inline(always)]
                pub fn $inist($inictx: &mut Context) -> super::State {
                    // prohibits all kind of recursions, including self-recursions
                    #[allow(unused_imports)] use super::transient::*;
                    match $inictx.read() {
                        None => super::$inist,
                        Some(c) => match c { $($($inilhs)|+ => { $($inirhs);+ })+ },
                    }
                }

                $(
                    #[inline(always)]
                    pub fn $ckst($ckctx: &mut Context $(, $ckarg: $ckty)*) -> super::State {
                        // prohibits all kind of recursions, including self-recursions
                        #[allow(unused_imports)] use super::transient::*;
                        match $ckctx.read() {
                            None => super::$ckst(() $(, $ckarg)*),
                            Some(c) => match c { $($($cklhs)|+ => { $($ckrhs);+ })+ },
                        }
                    }
                )*
            }

            pub mod transient {
                use super::internal::*;

                #[inline(always)]
                #[allow(dead_code)]
                pub fn $inist(_: &mut Context) -> super::State {
                    super::$inist // do not recurse further
                }

                $(
                    #[inline(always)]
                    #[allow(dead_code)]
                    pub fn $ckst(_: &mut Context $(, $ckarg: $ckty)*) -> super::State {
                        super::$ckst(() $(, $ckarg)*) // do not recurse further
                    }
                )*

                $(
                    #[inline(always)]
                    pub fn $st($ctx: &mut Context $(, $arg: $ty)*) -> super::State {
                        match $inictx.read() {
                            None => super::$st(() $(, $arg)*),
                            Some(c) => match c { $($($lhs)|+ => { $($rhs);+ })+ },
                        }
                    }
                )*
            }
        }

        impl $dec {
            pub fn new() -> Box<Decoder> { box $dec { st: $stmod::$inist } as Box<Decoder> }
        }

        impl Decoder for $dec {
            fn from_self(&self) -> Box<Decoder> { $dec::new() }
            fn is_ascii_compatible(&self) -> bool { $asciicompat }

            fn raw_feed(&mut self, input: &[u8],
                        output: &mut StringWriter) -> (uint, Option<CodecError>) {
                use self::$stmod::{start, transient};

                output.writer_hint(input.len());

                let mut ctx = ::util::StatefulDecoderHelper {
                    buf: input, pos: 0, output: output, err: None
                };
                let mut processed = 0;
                let mut st = self.st;

                let st_ = match st {
                    $stmod::$inist => $stmod::$inist,
                    $(
                        $stmod::$ckst(() $(, $ckarg)*) => start::$ckst(&mut ctx $(, $ckarg)*),
                    )*
                    $(
                        $stmod::$st(() $(, $arg)*) => transient::$st(&mut ctx $(, $arg)*),
                    )*
                };
                match (ctx.err.take(), st_) {
                    (None, $stmod::$inist) $(| (None, $stmod::$ckst(..)))* =>
                        { st = st_; processed = ctx.pos; }
                    // XXX splitting the match case improves the performance somehow, but why?
                    (None, _) => { self.st = st_; return (processed, None); }
                    (Some(err), _) => { self.st = st_; return (processed, Some(err)); }
                }

                while ctx.pos < ctx.buf.len() {
                    let st_ = match st {
                        $stmod::$inist => start::$inist(&mut ctx),
                        $(
                            $stmod::$ckst(() $(, $ckarg)*) => start::$ckst(&mut ctx $(, $ckarg)*),
                        )*
                        _ => unreachable!(),
                    };
                    match (ctx.err.take(), st_) {
                        (None, $stmod::$inist) $(| (None, $stmod::$ckst(..)))* =>
                            { st = st_; processed = ctx.pos; }
                        // XXX splitting the match case improves the performance somehow, but why?
                        (None, _) => { self.st = st_; return (processed, None); }
                        (Some(err), _) => { self.st = st_; return (processed, Some(err)); }
                    }
                }

                self.st = st;
                (processed, None)
            }

            fn raw_finish(&mut self, output: &mut StringWriter) -> Option<CodecError> {
                #![allow(unused_mut, unused_variable)]
                let mut ctx = ::util::StatefulDecoderHelper {
                    buf: &[], pos: 0, output: output, err: None
                };
                self.st = match ::std::mem::replace(&mut self.st, $stmod::$inist) {
                    $stmod::$inist => { let $inictx = &mut ctx; $($inifin);+ },
                    $(
                        $stmod::$ckst(() $(, $ckarg)*) => { let $ckctx = &mut ctx; $($ckfin);+ },
                    )*
                    $(
                        $stmod::$st(() $(, $arg)*) => { let $ctx = &mut ctx; $($fin);+ },
                    )*
                };
                ctx.err.take()
            }
        }
    )
)

/// Defines an ASCII-compatible stateful decoder from given state machine.
macro_rules! ascii_compatible_stateful_decoder(
    (
        $(#[$decmeta:meta])*
        struct $dec:ident;
        module $stmod:ident; // should be unique from other existing identifiers
        $(internal $item:item)* // will only be visible from state functions
        initial state $inist:ident($inictx:ident) {
            $(case $($inilhs:pat)|+ => $($inirhs:expr),+;)+
        }
        $(state $st:ident($ctx:ident $(, $arg:ident: $ty:ty)*) {
            $(case $($lhs:pat)|+ => $($rhs:expr),+;)+
        })*
    ) => (
        stateful_decoder!(
            $(#[$decmeta])*
            struct $dec;
            module $stmod;
            ascii_compatible true;
            $(internal $item)*
            initial state $inist($inictx) {
                $(case $($inilhs)|+ => $($inirhs),+;)+
                final => $inictx.reset();
            }
            $(state $st($ctx $(, $arg: $ty)*) {
                $(case $($lhs)|+ => $($rhs),+;)+
                final => $ctx.err("incomplete sequence");
            })*
        )
    )
)

<commit_msg>language changes: lint renaming.<commit_after>// This is a part of rust-encoding.
// Copyright (c) 2013-2014, Kang Seonghoon.
// See README.md and LICENSE.txt for details.

//! Internal utilities.

#![macro_escape]

use std::{str, mem};
use std::default::Default;
use types;

/// Unchecked conversion to `char`.
pub fn as_char<T:Int+NumCast>(ch: T) -> char {
    unsafe { mem::transmute(ch.to_u32().unwrap()) }
}

/// External iterator for a string's characters with its corresponding byte offset range.
pub struct StrCharIndexIterator<'r> {
    index: uint,
    string: &'r str,
}

impl<'r> Iterator<((uint,uint), char)> for StrCharIndexIterator<'r> {
    #[inline]
    fn next(&mut self) -> Option<((uint,uint), char)> {
        if self.index < self.string.len() {
            let str::CharRange {ch, next} = self.string.char_range_at(self.index);
            let prev = self.index;
            self.index = next;
            Some(((prev, next), ch))
        } else {
            None
        }
    }
}

/// A trait providing an `index_iter` method.
pub trait StrCharIndex<'r> {
    fn index_iter(&self) -> StrCharIndexIterator<'r>;
}

impl<'r> StrCharIndex<'r> for &'r str {
    /// Iterates over each character with corresponding byte offset range.
    fn index_iter(&self) -> StrCharIndexIterator<'r> {
        StrCharIndexIterator { index: 0, string: *self }
    }
}

/// A helper struct for the stateful decoder DSL.
pub struct StatefulDecoderHelper<'a, St> {
    /// The current buffer.
    pub buf: &'a [u8],
    /// The current index to the buffer.
    pub pos: uint,
    /// The output buffer.
    pub output: &'a mut types::StringWriter,
    /// The last codec error. The caller will later collect this.
    pub err: Option<types::CodecError>,
}

impl<'a, St:Default> StatefulDecoderHelper<'a, St> {
    /// Reads one byte from the buffer if any.
    #[inline(always)]
    pub fn read(&mut self) -> Option<u8> {
        match self.buf.get(self.pos) {
            Some(&c) => { self.pos += 1; Some(c) }
            None => None
        }
    }

    /// Resets back to the initial state.
    /// This should be the last expr in the rules.
    #[inline(always)]
    pub fn reset(&self) -> St {
        Default::default()
    }

    /// Writes one Unicode scalar value to the output.
    /// There is intentionally no check for `c`, so the caller should ensure that it's valid.
    /// If this is the last expr in the rules, also resets back to the initial state.
    #[inline(always)]
    pub fn emit(&mut self, c: u32) -> St {
        self.output.write_char(unsafe {mem::transmute(c)});
        Default::default()
    }

    /// Writes a Unicode string to the output.
    /// If this is the last expr in the rules, also resets back to the initial state.
    #[inline(always)]
    pub fn emit_str(&mut self, s: &str) -> St {
        self.output.write_str(s);
        Default::default()
    }

    /// Issues a codec error with given message at the current position.
    /// If this is the last expr in the rules, also resets back to the initial state.
    #[inline(always)]
    pub fn err(&mut self, msg: &'static str) -> St {
        self.err = Some(types::CodecError { upto: self.pos as int, cause: msg.into_maybe_owned() });
        Default::default()
    }

    /// Issues a codec error with given message at the current position minus `backup` bytes.
    /// If this is the last expr in the rules, also resets back to the initial state.
    ///
    /// This should be used to implement "prepending byte to the stream" in the Encoding spec,
    /// which corresponds to `ctx.backup_and_err(1, ...)`.
    #[inline(always)]
    pub fn backup_and_err(&mut self, backup: uint, msg: &'static str) -> St {
        let upto = self.pos as int - backup as int;
        self.err = Some(types::CodecError { upto: upto, cause: msg.into_maybe_owned() });
        Default::default()
    }
}

/// Defines a stateful decoder from given state machine.
macro_rules! stateful_decoder(
    (
        $(#[$decmeta:meta])*
        struct $dec:ident;
        module $stmod:ident; // should be unique from other existing identifiers
        ascii_compatible $asciicompat:expr;
        $(internal $item:item)* // will only be visible from state functions
        initial state $inist:ident($inictx:ident) {
            $(case $($inilhs:pat)|+ => $($inirhs:expr),+;)+
            final => $($inifin:expr),+;
        }
        $(checkpoint state $ckst:ident($ckctx:ident $(, $ckarg:ident: $ckty:ty)*) {
            $(case $($cklhs:pat)|+ => $($ckrhs:expr),+;)+
            final => $($ckfin:expr),+;
        })*
        $(state $st:ident($ctx:ident $(, $arg:ident: $ty:ty)*) {
            $(case $($lhs:pat)|+ => $($rhs:expr),+;)+
            final => $($fin:expr),+;
        })*
    ) => (
        $(#[$decmeta])*
        pub struct $dec {
            st: $stmod::State
        }

        #[allow(non_snake_case)]
        mod $stmod {
            #[deriving(PartialEq,Clone)]
            pub enum State {
                $inist,
                $(
                    $ckst(() $(, $ckty)*),
                )*
                $(
                    $st(() $(, $ty)*),
                )*
            }

            impl ::std::default::Default for State {
                #[inline(always)] fn default() -> State { $inist }
            }

            pub mod internal {
                pub type Context<'a> = ::util::StatefulDecoderHelper<'a, super::State>;

                $($item)*
            }

            pub mod start {
                use super::internal::*;

                #[inline(always)]
                pub fn $inist($inictx: &mut Context) -> super::State {
                    // prohibits all kind of recursions, including self-recursions
                    #[allow(unused_imports)] use super::transient::*;
                    match $inictx.read() {
                        None => super::$inist,
                        Some(c) => match c { $($($inilhs)|+ => { $($inirhs);+ })+ },
                    }
                }

                $(
                    #[inline(always)]
                    pub fn $ckst($ckctx: &mut Context $(, $ckarg: $ckty)*) -> super::State {
                        // prohibits all kind of recursions, including self-recursions
                        #[allow(unused_imports)] use super::transient::*;
                        match $ckctx.read() {
                            None => super::$ckst(() $(, $ckarg)*),
                            Some(c) => match c { $($($cklhs)|+ => { $($ckrhs);+ })+ },
                        }
                    }
                )*
            }

            pub mod transient {
                use super::internal::*;

                #[inline(always)]
                #[allow(dead_code)]
                pub fn $inist(_: &mut Context) -> super::State {
                    super::$inist // do not recurse further
                }

                $(
                    #[inline(always)]
                    #[allow(dead_code)]
                    pub fn $ckst(_: &mut Context $(, $ckarg: $ckty)*) -> super::State {
                        super::$ckst(() $(, $ckarg)*) // do not recurse further
                    }
                )*

                $(
                    #[inline(always)]
                    pub fn $st($ctx: &mut Context $(, $arg: $ty)*) -> super::State {
                        match $inictx.read() {
                            None => super::$st(() $(, $arg)*),
                            Some(c) => match c { $($($lhs)|+ => { $($rhs);+ })+ },
                        }
                    }
                )*
            }
        }

        impl $dec {
            pub fn new() -> Box<Decoder> { box $dec { st: $stmod::$inist } as Box<Decoder> }
        }

        impl Decoder for $dec {
            fn from_self(&self) -> Box<Decoder> { $dec::new() }
            fn is_ascii_compatible(&self) -> bool { $asciicompat }

            fn raw_feed(&mut self, input: &[u8],
                        output: &mut StringWriter) -> (uint, Option<CodecError>) {
                use self::$stmod::{start, transient};

                output.writer_hint(input.len());

                let mut ctx = ::util::StatefulDecoderHelper {
                    buf: input, pos: 0, output: output, err: None
                };
                let mut processed = 0;
                let mut st = self.st;

                let st_ = match st {
                    $stmod::$inist => $stmod::$inist,
                    $(
                        $stmod::$ckst(() $(, $ckarg)*) => start::$ckst(&mut ctx $(, $ckarg)*),
                    )*
                    $(
                        $stmod::$st(() $(, $arg)*) => transient::$st(&mut ctx $(, $arg)*),
                    )*
                };
                match (ctx.err.take(), st_) {
                    (None, $stmod::$inist) $(| (None, $stmod::$ckst(..)))* =>
                        { st = st_; processed = ctx.pos; }
                    // XXX splitting the match case improves the performance somehow, but why?
                    (None, _) => { self.st = st_; return (processed, None); }
                    (Some(err), _) => { self.st = st_; return (processed, Some(err)); }
                }

                while ctx.pos < ctx.buf.len() {
                    let st_ = match st {
                        $stmod::$inist => start::$inist(&mut ctx),
                        $(
                            $stmod::$ckst(() $(, $ckarg)*) => start::$ckst(&mut ctx $(, $ckarg)*),
                        )*
                        _ => unreachable!(),
                    };
                    match (ctx.err.take(), st_) {
                        (None, $stmod::$inist) $(| (None, $stmod::$ckst(..)))* =>
                            { st = st_; processed = ctx.pos; }
                        // XXX splitting the match case improves the performance somehow, but why?
                        (None, _) => { self.st = st_; return (processed, None); }
                        (Some(err), _) => { self.st = st_; return (processed, Some(err)); }
                    }
                }

                self.st = st;
                (processed, None)
            }

            fn raw_finish(&mut self, output: &mut StringWriter) -> Option<CodecError> {
                #![allow(unused_mut, unused_variable)]
                let mut ctx = ::util::StatefulDecoderHelper {
                    buf: &[], pos: 0, output: output, err: None
                };
                self.st = match ::std::mem::replace(&mut self.st, $stmod::$inist) {
                    $stmod::$inist => { let $inictx = &mut ctx; $($inifin);+ },
                    $(
                        $stmod::$ckst(() $(, $ckarg)*) => { let $ckctx = &mut ctx; $($ckfin);+ },
                    )*
                    $(
                        $stmod::$st(() $(, $arg)*) => { let $ctx = &mut ctx; $($fin);+ },
                    )*
                };
                ctx.err.take()
            }
        }
    )
)

/// Defines an ASCII-compatible stateful decoder from given state machine.
macro_rules! ascii_compatible_stateful_decoder(
    (
        $(#[$decmeta:meta])*
        struct $dec:ident;
        module $stmod:ident; // should be unique from other existing identifiers
        $(internal $item:item)* // will only be visible from state functions
        initial state $inist:ident($inictx:ident) {
            $(case $($inilhs:pat)|+ => $($inirhs:expr),+;)+
        }
        $(state $st:ident($ctx:ident $(, $arg:ident: $ty:ty)*) {
            $(case $($lhs:pat)|+ => $($rhs:expr),+;)+
        })*
    ) => (
        stateful_decoder!(
            $(#[$decmeta])*
            struct $dec;
            module $stmod;
            ascii_compatible true;
            $(internal $item)*
            initial state $inist($inictx) {
                $(case $($inilhs)|+ => $($inirhs),+;)+
                final => $inictx.reset();
            }
            $(state $st($ctx $(, $arg: $ty)*) {
                $(case $($lhs)|+ => $($rhs),+;)+
                final => $ctx.err("incomplete sequence");
            })*
        )
    )
)

<|endoftext|>


<commit_before>#![cfg(test)]
use std::ops::Add;
use std::collections::HashMap;

use traits::Cell;
use traits::Coord;
use traits::Engine;
use traits::ReprConsumer;
use traits::Grid;
use engine::sequential::Sequential;
use grid::square::SquareGrid;
use grid::nhood::MooreNhood;
use grid::square::GridCoord;
use repr::CellRepr;
use repr::GridRepr;

/// Implementation of Conway's Game of Life.

#[derive(Clone, Debug)]
enum LifeState {
    Dead,
    Alive
}

#[derive(Clone, Debug)]
struct Life {
    state: LifeState
}

impl Life {

    fn alive_count<'a, I>(&self, neighbors: I) -> i32
        where I: Iterator<Item=Option<&'a Self>> {
        neighbors.map(
            |n| {
                match n {
                    Some(ref cell) => match cell.state {
                        LifeState::Alive => 1,
                        LifeState::Dead => 0
                    },
                    None => 0,
                }
            }
        ).fold(0, Add::add)
    }

    #[inline]
    fn dead_state(&self, alive: i32) -> LifeState {
        match alive {
            3 => LifeState::Alive,
            _ => LifeState::Dead
        }
    }

    #[inline]
    fn alive_state(&self, alive: i32) -> LifeState {
        match alive {
            2 | 3 => LifeState::Alive,
            _ => LifeState::Dead
        }
    }
}

impl Default for Life {

    fn default() -> Self {
        Life { state: LifeState::Dead }
    }
}

const ALIVE: &'static str = "a";
const DEAD: &'static str = "d";
const STATE: &'static str = "s";

impl Cell for Life {

    fn step<'a, I>(&self, neighbors: I) -> Self
        where I: Iterator<Item=Option<&'a Self>> {

        let alive_count = self.alive_count(neighbors);

        let new_state = match self.state {
            LifeState::Alive => self.alive_state(alive_count),
            LifeState::Dead => self.dead_state(alive_count)
        };

        let mut new_cell = self.clone();
        new_cell.state = new_state;

        new_cell
    }

    fn repr(&self, meta: &mut HashMap<&str, &str>) {

        let state_str = match self.state {
            LifeState::Alive => ALIVE,
            LifeState::Dead  => DEAD
        };

        meta.insert(STATE, state_str);
    }

    fn from_repr(&mut self, meta: &HashMap<&str, &str>) {

        let new_state = match meta[STATE] {
            ALIVE => LifeState::Alive,
            DEAD => LifeState::Dead,
            _ => panic!("Unknown state: {}.", meta[STATE])
        };

        self.state = new_state;
    }
}

struct SpinnerTestConsumer {
    vertical: bool
}

impl SpinnerTestConsumer {

    pub fn new() -> Self {
        SpinnerTestConsumer { vertical: true }
    }
}

impl ReprConsumer for SpinnerTestConsumer {

    fn consume<C: Coord>(&mut self, repr: &GridRepr<C>) {
        assert_eq!(repr.cells.len(), 9);

        let alive_cells: Vec<&CellRepr<C>> =
            repr.cells.iter().filter(|c| c.state[STATE] == ALIVE).collect();
        assert_eq!(alive_cells.len(), 3);

        let dead_cells: Vec<&CellRepr<C>> =
            repr.cells.iter().filter(|c| c.state[STATE] == DEAD).collect();
        assert_eq!(dead_cells.len(), 6);

        self.vertical = !self.vertical;

        // if spinner is in vertical state
        if alive_cells.iter().all(|c| c.coord.x() == 1) {
            assert!(self.vertical);
        }
        // if spinner is in horizontal state
        if alive_cells.iter().all(|c| c.coord.y() == 1) {
            assert!(!self.vertical);
        }
    }
}

#[test]
fn test_game_of_life() {

    let nhood = MooreNhood::new();
    let mut grid: SquareGrid<Life, _> = SquareGrid::new(3, 3, nhood);

    // Vertical spinner
    // D | A | D
    // D | A | D
    // D | A | D
    // Cells not specified below should be equal to default cell value
    let mut alive_cell = HashMap::new();
    alive_cell.insert(STATE, ALIVE);

    let cells = vec![
        CellRepr::new(GridCoord::from_2d(1, 0), Some(&alive_cell)),
        CellRepr::new(GridCoord::from_2d(1, 1), Some(&alive_cell)),
        CellRepr::new(GridCoord::from_2d(1, 2), Some(&alive_cell)),
    ];

    let grid_repr = GridRepr::new(3, 3, Some(cells));

    let life_default = Life::default();
    let mut default_state = HashMap::new();
    life_default.repr(&mut default_state);

    assert!(grid.repr().cells.iter().all(|c| c.state[STATE] == default_state[STATE]));

    grid.from_repr(&grid_repr);

    let consumer = SpinnerTestConsumer::new();
    let mut engine = Sequential::new(grid, consumer);
    engine.run_times(2);
}
<commit_msg>Concise version.<commit_after>#![cfg(test)]
use std::collections::HashMap;

use traits::Cell;
use traits::Coord;
use traits::Engine;
use traits::ReprConsumer;
use traits::Grid;
use engine::sequential::Sequential;
use grid::square::SquareGrid;
use grid::nhood::MooreNhood;
use grid::square::GridCoord;
use repr::CellRepr;
use repr::GridRepr;

/// Implementation of Conway's Game of Life.

#[derive(Clone, Debug, PartialEq)]
enum LifeState {
    Dead,
    Alive
}

#[derive(Clone, Debug)]
struct Life {
    state: LifeState
}

impl Life {

    fn alive_count<'a, I>(&self, neighbors: I) -> i32
        where I: Iterator<Item=Option<&'a Self>> {

        neighbors.filter(|n| match *n {
            Some(n) => n.state == LifeState::Alive,
            None => false
        }).count() as i32
    }

    #[inline]
    fn dead_state(&self, alive: i32) -> LifeState {
        match alive {
            3 => LifeState::Alive,
            _ => LifeState::Dead
        }
    }

    #[inline]
    fn alive_state(&self, alive: i32) -> LifeState {
        match alive {
            2 | 3 => LifeState::Alive,
            _ => LifeState::Dead
        }
    }
}

impl Default for Life {

    fn default() -> Self {
        Life { state: LifeState::Dead }
    }
}

const ALIVE: &'static str = "a";
const DEAD: &'static str = "d";
const STATE: &'static str = "s";

impl Cell for Life {

    fn step<'a, I>(&self, neighbors: I) -> Self
        where I: Iterator<Item=Option<&'a Self>> {

        let alive_count = self.alive_count(neighbors);

        let new_state = match self.state {
            LifeState::Alive => self.alive_state(alive_count),
            LifeState::Dead => self.dead_state(alive_count)
        };

        let mut new_cell = self.clone();
        new_cell.state = new_state;

        new_cell
    }

    fn repr(&self, meta: &mut HashMap<&str, &str>) {

        let state_str = match self.state {
            LifeState::Alive => ALIVE,
            LifeState::Dead  => DEAD
        };

        meta.insert(STATE, state_str);
    }

    fn from_repr(&mut self, meta: &HashMap<&str, &str>) {

        let new_state = match meta[STATE] {
            ALIVE => LifeState::Alive,
            DEAD => LifeState::Dead,
            _ => panic!("Unknown state: {}.", meta[STATE])
        };

        self.state = new_state;
    }
}

struct SpinnerTestConsumer {
    vertical: bool
}

impl SpinnerTestConsumer {

    pub fn new() -> Self {
        SpinnerTestConsumer { vertical: true }
    }
}

impl ReprConsumer for SpinnerTestConsumer {

    fn consume<C: Coord>(&mut self, repr: &GridRepr<C>) {
        assert_eq!(repr.cells.len(), 9);

        let alive_cells: Vec<&CellRepr<C>> =
            repr.cells.iter().filter(|c| c.state[STATE] == ALIVE).collect();
        assert_eq!(alive_cells.len(), 3);

        let dead_cells: Vec<&CellRepr<C>> =
            repr.cells.iter().filter(|c| c.state[STATE] == DEAD).collect();
        assert_eq!(dead_cells.len(), 6);

        self.vertical = !self.vertical;

        // if spinner is in vertical state
        if alive_cells.iter().all(|c| c.coord.x() == 1) {
            assert!(self.vertical);
        }
        // if spinner is in horizontal state
        if alive_cells.iter().all(|c| c.coord.y() == 1) {
            assert!(!self.vertical);
        }
    }
}

#[test]
fn test_game_of_life() {

    let nhood = MooreNhood::new();
    let mut grid: SquareGrid<Life, _> = SquareGrid::new(3, 3, nhood);

    // Vertical spinner
    // D | A | D
    // D | A | D
    // D | A | D
    // Cells not specified below should be equal to default cell value
    let mut alive_cell = HashMap::new();
    alive_cell.insert(STATE, ALIVE);

    let cells = vec![
        CellRepr::new(GridCoord::from_2d(1, 0), Some(&alive_cell)),
        CellRepr::new(GridCoord::from_2d(1, 1), Some(&alive_cell)),
        CellRepr::new(GridCoord::from_2d(1, 2), Some(&alive_cell)),
    ];

    let grid_repr = GridRepr::new(3, 3, Some(cells));

    let life_default = Life::default();
    let mut default_state = HashMap::new();
    life_default.repr(&mut default_state);

    assert!(grid.repr().cells.iter().all(|c| c.state[STATE] == default_state[STATE]));

    grid.from_repr(&grid_repr);

    let consumer = SpinnerTestConsumer::new();
    let mut engine = Sequential::new(grid, consumer);
    engine.run_times(2);
}
<|endoftext|>


<commit_before>use std::mem;
use std::rc::Rc;
use std::cell::RefCell;
use std::marker::PhantomData;
use std::collections::VecDeque;

use progress::Timestamp;
use communication::Data;
use communication::{Communicator, Pullable, Pushable, Observer};
use communication::observer::ExchangeObserver;

use columnar::Columnar;

// A ParallelizationContract transforms the output of a Communicator, a (Vec<Pushable>, Pullable), to an (Observer, Pullable)
// TODO : There is an asymmetry with the Observer/Pullable interface at the moment in that the Pullable
// TODO : yields (and loses) vectors, which need to be continually allocated on the Observer side. It would
// TODO : be better if there were a way to recycle them, perhaps by having the Pullable only show them,
// TODO : or be a Pullable<(&T, &mut Vec<D>)>, or Pullable<(T, Iterator<D>)>, or who knows what...
pub trait ParallelizationContract<T: Timestamp, D: Data> {
    type Observer: Observer<Time=T, Data=D>+'static;
    type Pullable: Pullable<(T, Vec<D>)>+'static;
    fn connect<C: Communicator>(self, communicator: &mut C) -> (Self::Observer, PactPullable<T, D, Self::Pullable>);
}

// direct connection
pub struct Pipeline;
impl<T: Timestamp, D: Data> ParallelizationContract<T, D> for Pipeline {
    type Observer = PactObserver<T, D, Rc<RefCell<VecDeque<(T, Vec<D>)>>>>;
    type Pullable = Rc<RefCell<VecDeque<(T, Vec<D>)>>>;
    fn connect<C: Communicator>(self,_communicator: &mut C) -> (Self::Observer, PactPullable<T, D, Self::Pullable>) {
        let shared1 = Rc::new(RefCell::new(VecDeque::new()));
        let shared2 = Rc::new(RefCell::new(Vec::new()));
        return (PactObserver::new(shared1.clone(), shared2.clone()), PactPullable::new(shared1, shared2));
    }
}

// exchanges between multiple observers
pub struct Exchange<D, F: Fn(&D)->u64> { hash_func: F, phantom: PhantomData<D>, }
impl<D, F: Fn(&D)->u64> Exchange<D, F> {
    pub fn new(func: F) -> Exchange<D, F> {
        Exchange {
            hash_func:  func,
            phantom:    PhantomData,
        }
    }
}

// Exchange uses a Box<Pushable> because it cannot know what type of pushable will return from the communicator.
// The PactObserver will do some buffering for Exchange, cutting down on the virtual calls, but we still
// would like to get the vectors it sends back, so that they can be re-used if possible.
impl<T: Timestamp, D: Data+Columnar, F: Fn(&D)->u64+'static> ParallelizationContract<T, D> for Exchange<D, F> {
    type Observer = ExchangeObserver<PactObserver<T, D, Box<Pushable<(T, Vec<D>)>>>, F>;
    type Pullable = Box<Pullable<(T, Vec<D>)>>;
    fn connect<C: Communicator>(self, communicator: &mut C) -> (Self::Observer, PactPullable<T, D, Self::Pullable>) {
        let (senders, receiver) = communicator.new_channel();

        let shared = Rc::new(RefCell::new(Vec::new()));

        let exchange_sender = ExchangeObserver {
            observers:  senders.into_iter().map(|x| PactObserver::new(x, shared.clone())).collect(),
            hash_func:  self.hash_func,
        };

        return (exchange_sender, PactPullable::new(receiver, shared));
    }
}

pub struct PactPullable<T:Send, D:Send+Clone, P: Pullable<(T, Vec<D>)>> {
    pullable: P,
    buffer:   Vec<D>,
    shared:   Rc<RefCell<Vec<Vec<D>>>>,
    phantom:  PhantomData<T>,
}

impl<T:Send, D: Send+Clone, P: Pullable<(T, Vec<D>)>> PactPullable<T, D, P> {
    pub fn pull(&mut self) -> Option<(T, &mut Vec<D>)> {
        if let Some((time, mut data)) = self.pullable.pull() {
            if data.len() > 0 {
                mem::swap(&mut data, &mut self.buffer);
                data.clear();
                // self.shared.borrow_mut().push(data);
                Some((time, &mut self.buffer))
            } else { None }
        } else { None }
    }
    fn new(pullable: P, shared: Rc<RefCell<Vec<Vec<D>>>>) -> PactPullable<T, D, P> {
        PactPullable {
            pullable: pullable,
            buffer:   Vec::new(),
            shared:   shared,
            phantom:  PhantomData,
        }
    }
}

pub struct PactObserver<T:Send, D:Send+Clone, P: Pushable<(T, Vec<D>)>> {
    pub data:       Vec<D>,
    pub pushable:   P,
    pub phantom:    PhantomData<T>,
    shared:         Rc<RefCell<Vec<Vec<D>>>>,
    // threshold:      usize, // TODO : add this in, cloning time, I guess.
}

impl<T:Send, D:Send+Clone, P: Pushable<(T, Vec<D>)>> PactObserver<T, D, P> {
    pub fn new(pushable: P, shared: Rc<RefCell<Vec<Vec<D>>>>) -> PactObserver<T, D, P> {
        PactObserver {
            data:       Vec::new(),
            pushable:   pushable,
            phantom:    PhantomData,
            shared:     shared,
        }
    }
}

impl<T:Send+Clone, D:Send+Clone, P: Pushable<(T, Vec<D>)>> Observer for PactObserver<T,D,P> {
    type Time = T;
    type Data = D;
    #[inline(always)] fn open(&mut self,_time: &T) { }
    #[inline(always)] fn show(&mut self, data: &D) { self.give(data.clone()); }
    #[inline(always)] fn give(&mut self, data:  D) { self.data.push(data); }
    #[inline(always)] fn shut(&mut self, time: &T) {
        if self.data.len() > 0 {
            let empty = self.shared.borrow_mut().pop().unwrap_or(Vec::new());
            // if empty.capacity() == 0 { println!("empty buffer!"); }
            self.pushable.push((time.clone(), mem::replace(&mut self.data, empty)));
        }
    }
}

// broadcasts to all observers
// TODO : This needs support from the progress tracking protocol;
// TODO : we don't know/report how many messages are actually created.
// pub struct Broadcast;
// impl<T: Timestamp, D: Data+Columnar> ParallelizationContract<T, D> for Broadcast {
//     type Observer = BroadcastObserver<PushableObserver<T,D,Box<Pushable<(T,Vec<D>)>>>>;
//     type Pullable = Box<Pullable<(T, Vec<D>)>>;
//     fn connect<C: Communicator>(self, communicator: &mut C) -> (<Broadcast as ParallelizationContract<T, D>>::Observer,
//                                                                 <Broadcast as ParallelizationContract<T, D>>::Pullable) {
//         let (senders, receiver) = communicator.new_channel();
//
//         let exchange_sender = BroadcastObserver {
//             observers:  senders.into_iter().map(|x| PushableObserver { data: Vec::new(), pushable: x, phantom: PhantomData }).collect()
//         };
//
//         panic!("Broadcast won't work until progress counting becomes aware of how many records are sent");
//
//         return (exchange_sender, receiver);
//     }
// }
<commit_msg>PactObserver flushes sent data after some threshold rather than only on shut<commit_after>use std::mem;
use std::rc::Rc;
use std::cell::RefCell;
use std::marker::PhantomData;
use std::collections::VecDeque;

use progress::Timestamp;
use communication::Data;
use communication::{Communicator, Pullable, Pushable, Observer};
use communication::observer::ExchangeObserver;

use columnar::Columnar;

// A ParallelizationContract transforms the output of a Communicator, a (Vec<Pushable>, Pullable), to an (Observer, Pullable)
// TODO : There is an asymmetry with the Observer/Pullable interface at the moment in that the Pullable
// TODO : yields (and loses) vectors, which need to be continually allocated on the Observer side. It would
// TODO : be better if there were a way to recycle them, perhaps by having the Pullable only show them,
// TODO : or be a Pullable<(&T, &mut Vec<D>)>, or Pullable<(T, Iterator<D>)>, or who knows what...
pub trait ParallelizationContract<T: Timestamp, D: Data> {
    type Observer: Observer<Time=T, Data=D>+'static;
    type Pullable: Pullable<(T, Vec<D>)>+'static;
    fn connect<C: Communicator>(self, communicator: &mut C) -> (Self::Observer, PactPullable<T, D, Self::Pullable>);
}

// direct connection
pub struct Pipeline;
impl<T: Timestamp, D: Data> ParallelizationContract<T, D> for Pipeline {
    type Observer = PactObserver<T, D, Rc<RefCell<VecDeque<(T, Vec<D>)>>>>;
    type Pullable = Rc<RefCell<VecDeque<(T, Vec<D>)>>>;
    fn connect<C: Communicator>(self,_communicator: &mut C) -> (Self::Observer, PactPullable<T, D, Self::Pullable>) {
        let shared1 = Rc::new(RefCell::new(VecDeque::new()));
        let shared2 = Rc::new(RefCell::new(Vec::new()));
        return (PactObserver::new(shared1.clone(), shared2.clone()), PactPullable::new(shared1, shared2));
    }
}

// exchanges between multiple observers
pub struct Exchange<D, F: Fn(&D)->u64> { hash_func: F, phantom: PhantomData<D>, }
impl<D, F: Fn(&D)->u64> Exchange<D, F> {
    pub fn new(func: F) -> Exchange<D, F> {
        Exchange {
            hash_func:  func,
            phantom:    PhantomData,
        }
    }
}

// Exchange uses a Box<Pushable> because it cannot know what type of pushable will return from the communicator.
// The PactObserver will do some buffering for Exchange, cutting down on the virtual calls, but we still
// would like to get the vectors it sends back, so that they can be re-used if possible.
impl<T: Timestamp, D: Data+Columnar, F: Fn(&D)->u64+'static> ParallelizationContract<T, D> for Exchange<D, F> {
    type Observer = ExchangeObserver<PactObserver<T, D, Box<Pushable<(T, Vec<D>)>>>, F>;
    type Pullable = Box<Pullable<(T, Vec<D>)>>;
    fn connect<C: Communicator>(self, communicator: &mut C) -> (Self::Observer, PactPullable<T, D, Self::Pullable>) {
        let (senders, receiver) = communicator.new_channel();

        let shared = Rc::new(RefCell::new(Vec::new()));

        let exchange_sender = ExchangeObserver {
            observers:  senders.into_iter().map(|x| PactObserver::new(x, shared.clone())).collect(),
            hash_func:  self.hash_func,
        };

        return (exchange_sender, PactPullable::new(receiver, shared));
    }
}

pub struct PactPullable<T:Send, D:Send+Clone, P: Pullable<(T, Vec<D>)>> {
    pullable: P,
    buffer:   Vec<D>,
    shared:   Rc<RefCell<Vec<Vec<D>>>>,
    phantom:  PhantomData<T>,
}

impl<T:Send, D: Send+Clone, P: Pullable<(T, Vec<D>)>> PactPullable<T, D, P> {
    pub fn pull(&mut self) -> Option<(T, &mut Vec<D>)> {
        if let Some((time, mut data)) = self.pullable.pull() {
            if data.len() > 0 {
                mem::swap(&mut data, &mut self.buffer);
                data.clear();
                // self.shared.borrow_mut().push(data);
                Some((time, &mut self.buffer))
            } else { None }
        } else { None }
    }
    fn new(pullable: P, shared: Rc<RefCell<Vec<Vec<D>>>>) -> PactPullable<T, D, P> {
        PactPullable {
            pullable: pullable,
            buffer:   Vec::new(),
            shared:   shared,
            phantom:  PhantomData,
        }
    }
}

pub struct PactObserver<T:Send, D:Send+Clone, P: Pushable<(T, Vec<D>)>> {
    pub data:       Vec<D>,
    pub pushable:   P,
    pub phantom:    PhantomData<T>,
    shared:         Rc<RefCell<Vec<Vec<D>>>>,
    // threshold:      usize, // TODO : add this in, cloning time, I guess.
    my_time:        Option<T>,
}

impl<T:Send, D:Send+Clone, P: Pushable<(T, Vec<D>)>> PactObserver<T, D, P> {
    pub fn new(pushable: P, shared: Rc<RefCell<Vec<Vec<D>>>>) -> PactObserver<T, D, P> {
        PactObserver {
            data:       Vec::new(),
            pushable:   pushable,
            phantom:    PhantomData,
            shared:     shared,
            my_time:    None,
        }
    }
}

impl<T:Send+Clone, D:Send+Clone, P: Pushable<(T, Vec<D>)>> Observer for PactObserver<T,D,P> {
    type Time = T;
    type Data = D;
    #[inline(always)] fn open(&mut self, time: &T) { self.my_time = Some(time.clone()); }
    #[inline(always)] fn show(&mut self, data: &D) { self.give(data.clone()); }
    #[inline(always)] fn give(&mut self, data:  D) {
        self.data.push(data);
        if self.data.len() > 1024 {
            let empty = self.shared.borrow_mut().pop().unwrap_or(Vec::new());
            self.pushable.push((self.my_time.as_ref().unwrap().clone(), mem::replace(&mut self.data, empty)));
        }
    }
    #[inline(always)] fn shut(&mut self, time: &T) {
        if self.data.len() > 0 {
            let empty = self.shared.borrow_mut().pop().unwrap_or(Vec::new());
            // if empty.capacity() == 0 { println!("empty buffer!"); }
            self.pushable.push((time.clone(), mem::replace(&mut self.data, empty)));
        }
    }
}

// broadcasts to all observers
// TODO : This needs support from the progress tracking protocol;
// TODO : we don't know/report how many messages are actually created.
// pub struct Broadcast;
// impl<T: Timestamp, D: Data+Columnar> ParallelizationContract<T, D> for Broadcast {
//     type Observer = BroadcastObserver<PushableObserver<T,D,Box<Pushable<(T,Vec<D>)>>>>;
//     type Pullable = Box<Pullable<(T, Vec<D>)>>;
//     fn connect<C: Communicator>(self, communicator: &mut C) -> (<Broadcast as ParallelizationContract<T, D>>::Observer,
//                                                                 <Broadcast as ParallelizationContract<T, D>>::Pullable) {
//         let (senders, receiver) = communicator.new_channel();
//
//         let exchange_sender = BroadcastObserver {
//             observers:  senders.into_iter().map(|x| PushableObserver { data: Vec::new(), pushable: x, phantom: PhantomData }).collect()
//         };
//
//         panic!("Broadcast won't work until progress counting becomes aware of how many records are sent");
//
//         return (exchange_sender, receiver);
//     }
// }
<|endoftext|>


<commit_before>mod terminal;
mod ansi;

use std::io::{self, Write};
use self::terminal::{Terminal, Event, Key};
use self::ansi::{clear, color, cursor, style};
use rayon::prelude::*;
use rff::choice::Choice;

#[derive(Debug)]
pub enum Error {
    Exit,
    Write(io::Error),
    Reset(terminal::Error)
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Write(err)
    }
}

impl From<terminal::Error> for Error {
    fn from(err: terminal::Error) -> Error {
        Error::Reset(err)
    }
}

pub struct Options {
    pub choices: Vec<String>,
    pub initial: String,
}

pub struct Interface {
    choices: Vec<String>,
    matching: Vec<Choice>,
    selected: usize,
    search: String,
    terminal: Terminal
}

impl Interface {
    /// Creates a new Interface from the provided options.
    pub fn from_opts(opts: Options) -> Interface {
        let mut term = Terminal::from("/dev/tty").unwrap();
        term.set_raw_mode().unwrap();

        Interface {
            choices: opts.choices,
            matching: Vec::new(),
            selected: 0,
            search: opts.initial,
            terminal: term
        }
    }

    // Starts the interface
    pub fn run(&mut self) -> Result<&str, Error> {
        self.filter_choices();
        self.render()?;

        for event in self.terminal.events()? {
            if let Event::Key(key) = event? {
                match key {
                    Key::Ctrl('c') | Key::Ctrl('d') => {
                        self.clear()?;
                        return Err(Error::Exit);
                    }

                    Key::Char('\n') => {
                        break;
                    },

                    Key::Ctrl('n') => {
                        self.selected += 1;
                        self.clamp_selected();
                        self.render()?;
                    },

                    Key::Ctrl('p') => {
                        self.selected = self.selected.
                            checked_sub(1).
                            unwrap_or(0);

                        self.clamp_selected();
                        self.render()?;
                    },

                    Key::Char(ch) => {
                        self.search.push(ch);
                        self.filter_existing_matches();
                        self.render()?;
                    },

                    Key::Backspace | Key::Ctrl('h') => {
                        self.search.pop();
                        self.filter_choices();
                        self.render()?;
                    }

                    Key::Ctrl('u') => {
                        self.search.clear();
                        self.filter_choices();
                        self.render()?;
                    }

                    _ => {}
                }
            };
        }

        self.clear()?;
        Ok(self.result())
    }

    fn filter_choices(&mut self) {
        let mut matches = self.choices.
            par_iter().
            cloned().
            filter_map(|choice| Choice::with_positions(&self.search, choice)).
            collect::<Vec<_>>();

        matches.sort_by(|a, b| b.partial_cmp(a).unwrap());

        self.matching = matches;
    }

    fn filter_existing_matches(&mut self) {
        let mut matches = self.matching.
            par_iter().
            map(|c| c.text().to_string()).
            filter_map(|choice| Choice::with_positions(&self.search, choice)).
            collect::<Vec<_>>();

        matches.sort_by(|a, b| b.partial_cmp(a).unwrap());

        self.matching = matches;
    }

    fn render(&mut self) -> io::Result<()> {
        write!(self.terminal, "{}{}", cursor::Column(1), clear::Screen)?;
        write!(self.terminal, "> {}", self.search)?;

        let n = self.render_choices()?;

        if n > 0 {
            let column = format!("> {}", self.search).len() as u16;
            write!(self.terminal, "{}{}", cursor::Up(n), cursor::Column(column + 1))?;
        }

        Ok(())
    }

    fn render_choices(&mut self) -> io::Result<u16> {
        let max_width = self.terminal.max_width as usize;

        let matches = self.matching.iter().take(10);

        let number_of_choices = matches.len() as u16;

        for (i, choice) in matches.enumerate() {
            let selected = i == self.selected;

            write!(self.terminal, "\r\n")?;

            if selected {
                write!(self.terminal, "{}", style::Invert)?;
            }

            if let Some(positions) = choice.positions() {
                let chars = choice.text().chars().take(max_width);

                for (i, ch) in chars.enumerate() {
                    let match_position = positions.iter().any(|p| *p == i);

                    if match_position {
                        let blue = color::Fg(color::Colors::LightBlue);
                        let reset = color::Fg(color::Reset);
                        write!(self.terminal, "{}{}{}", blue, ch, reset)?;
                    } else {
                        write!(self.terminal, "{}", ch)?;
                    }
                }

            } else {
                let text = choice.text()
                    .chars()
                    .take(max_width)
                    .collect::<String>();

                write!(self.terminal, "{}", text)?;
            }

            if selected {
                write!(self.terminal, "{}", style::NoInvert)?;
            }
        }

        Ok(number_of_choices)
    }

    #[inline(always)]
    fn clamp_selected(&mut self) {
        let mut max = self.matching.len();
        if max > 10 { max = 10; }

        if self.selected >= max {
            self.selected = max - 1;
        }
    }

    fn clear(&mut self) -> Result<(), Error> {
        write!(self.terminal, "{}{}", cursor::Column(1), clear::Screen)?;
        self.terminal.reset()?;
        Ok(())
    }

    fn result(&mut self) -> &str {
        self.matching.iter().
            map(|c| c.text()).
            nth(self.selected).
            unwrap_or(&self.search)
    }
}
<commit_msg>Change match color<commit_after>mod terminal;
mod ansi;

use std::io::{self, Write};
use self::terminal::{Terminal, Event, Key};
use self::ansi::{clear, color, cursor, style};
use rayon::prelude::*;
use rff::choice::Choice;

#[derive(Debug)]
pub enum Error {
    Exit,
    Write(io::Error),
    Reset(terminal::Error)
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Write(err)
    }
}

impl From<terminal::Error> for Error {
    fn from(err: terminal::Error) -> Error {
        Error::Reset(err)
    }
}

pub struct Options {
    pub choices: Vec<String>,
    pub initial: String,
}

pub struct Interface {
    choices: Vec<String>,
    matching: Vec<Choice>,
    selected: usize,
    search: String,
    terminal: Terminal
}

impl Interface {
    /// Creates a new Interface from the provided options.
    pub fn from_opts(opts: Options) -> Interface {
        let mut term = Terminal::from("/dev/tty").unwrap();
        term.set_raw_mode().unwrap();

        Interface {
            choices: opts.choices,
            matching: Vec::new(),
            selected: 0,
            search: opts.initial,
            terminal: term
        }
    }

    // Starts the interface
    pub fn run(&mut self) -> Result<&str, Error> {
        self.filter_choices();
        self.render()?;

        for event in self.terminal.events()? {
            if let Event::Key(key) = event? {
                match key {
                    Key::Ctrl('c') | Key::Ctrl('d') => {
                        self.clear()?;
                        return Err(Error::Exit);
                    }

                    Key::Char('\n') => {
                        break;
                    },

                    Key::Ctrl('n') => {
                        self.selected += 1;
                        self.clamp_selected();
                        self.render()?;
                    },

                    Key::Ctrl('p') => {
                        self.selected = self.selected.
                            checked_sub(1).
                            unwrap_or(0);

                        self.clamp_selected();
                        self.render()?;
                    },

                    Key::Char(ch) => {
                        self.search.push(ch);
                        self.filter_existing_matches();
                        self.render()?;
                    },

                    Key::Backspace | Key::Ctrl('h') => {
                        self.search.pop();
                        self.filter_choices();
                        self.render()?;
                    }

                    Key::Ctrl('u') => {
                        self.search.clear();
                        self.filter_choices();
                        self.render()?;
                    }

                    _ => {}
                }
            };
        }

        self.clear()?;
        Ok(self.result())
    }

    fn filter_choices(&mut self) {
        let mut matches = self.choices.
            par_iter().
            cloned().
            filter_map(|choice| Choice::with_positions(&self.search, choice)).
            collect::<Vec<_>>();

        matches.sort_by(|a, b| b.partial_cmp(a).unwrap());

        self.matching = matches;
    }

    fn filter_existing_matches(&mut self) {
        let mut matches = self.matching.
            par_iter().
            map(|c| c.text().to_string()).
            filter_map(|choice| Choice::with_positions(&self.search, choice)).
            collect::<Vec<_>>();

        matches.sort_by(|a, b| b.partial_cmp(a).unwrap());

        self.matching = matches;
    }

    fn render(&mut self) -> io::Result<()> {
        write!(self.terminal, "{}{}", cursor::Column(1), clear::Screen)?;
        write!(self.terminal, "> {}", self.search)?;

        let n = self.render_choices()?;

        if n > 0 {
            let column = format!("> {}", self.search).len() as u16;
            write!(self.terminal, "{}{}", cursor::Up(n), cursor::Column(column + 1))?;
        }

        Ok(())
    }

    fn render_choices(&mut self) -> io::Result<u16> {
        let max_width = self.terminal.max_width as usize;

        let matches = self.matching.iter().take(10);

        let number_of_choices = matches.len() as u16;

        for (i, choice) in matches.enumerate() {
            let selected = i == self.selected;

            write!(self.terminal, "\r\n")?;

            if selected {
                write!(self.terminal, "{}", style::Invert)?;
            }

            if let Some(positions) = choice.positions() {
                let chars = choice.text().chars().take(max_width);

                for (i, ch) in chars.enumerate() {
                    let match_position = positions.iter().any(|p| *p == i);

                    if match_position {
                        let color = color::Fg(color::Colors::Magenta);
                        let reset = color::Fg(color::Reset);
                        write!(self.terminal, "{}{}{}", color, ch, reset)?;
                    } else {
                        write!(self.terminal, "{}", ch)?;
                    }
                }

            } else {
                let text = choice.text()
                    .chars()
                    .take(max_width)
                    .collect::<String>();

                write!(self.terminal, "{}", text)?;
            }

            if selected {
                write!(self.terminal, "{}", style::NoInvert)?;
            }
        }

        Ok(number_of_choices)
    }

    #[inline(always)]
    fn clamp_selected(&mut self) {
        let mut max = self.matching.len();
        if max > 10 { max = 10; }

        if self.selected >= max {
            self.selected = max - 1;
        }
    }

    fn clear(&mut self) -> Result<(), Error> {
        write!(self.terminal, "{}{}", cursor::Column(1), clear::Screen)?;
        self.terminal.reset()?;
        Ok(())
    }

    fn result(&mut self) -> &str {
        self.matching.iter().
            map(|c| c.text()).
            nth(self.selected).
            unwrap_or(&self.search)
    }
}
<|endoftext|>


<commit_before>//! The memory module.
//! This module declares a single struct, the Memory Management Unit (MMU).
//! The MMU acts as the system bus, allowing components to communicate with each other, reaches
//! RAM, ROM, I/O registers and more.
use std::fmt;
use std::cell::Cell;

use jeebie::gpu::GPU;
use jeebie::cart::Cartridge;
use jeebie::bootrom::DMG_BOOTROM;

/// The Memory Management Unit.
/// Provides access to all mapped memory in the system, including I/O and graphics.
pub struct MMU {
    pub loading_bios: Cell<bool>,
    data: [u8; 65536],
    pub gpu: GPU,
}

impl fmt::Debug for MMU {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "MMU 64k")
    }
}

impl MMU {
    pub fn new() -> MMU {
        MMU {
            loading_bios: Cell::new(true),
            data: [0; 65536],
            gpu: GPU::new(),
        }
    }

    pub fn load_rom(&mut self, cart: &Cartridge) {
        for i in 0..cart.size {
            self.data[i] = cart.data[i];
        }
    }

    /// reads a byte at the memory address specified
    pub fn read_b(&self, addr: u16) -> u8 {
        // when PC first reaches 0x100, the BIOS data is not addressable anymore.
        // using Cell sucks, but this is one of the few cases mentioned by official docs where
        // it is an option. Read is logically an immutable operation, but we need to make the
        // bios unaddressable after its first read.
        if self.loading_bios.get() && addr == 0x0100 {
            self.loading_bios.set(false);
        }

        match addr {
            // bios area, 256B long for regular gameboy.
            0...0x00FF if self.loading_bios.get() => DMG_BOOTROM[(addr & 0xFF) as usize],
            // ROM0 area accessible only when bootrom is disabled (first 256 bytes).
            0x0000...0x00FF if !self.loading_bios.get() => self.data[addr as usize],
            // ROM0 area, this is banked memory, it will swap according to selected bank
            0x0100...0x3FFF => self.data[addr as usize],
            // ROM1 area, 16kB unbanked data
            0x4000...0x7FFF => self.data[addr as usize],
            // Graphics, 8kB VRAM
            0x8000...0x9FFF => self.gpu.read_vram((addr & 0x1FFF) as usize),
            // Switchable RAM bank, 8kB
            0xA000...0xBFFF => {
                // TODO: handle RAM banks
                self.data[addr as usize]
            }
            // Internal RAM, 8kB
            0xC000...0xDFFF => self.data[addr as usize],
            // Echo of internal RAM, this is less than 8k, up to 0xFDFF,
            0xE000...0xFDFF => self.data[(addr - 0x2000) as usize],
            // Sprite attribute memory, 160B
            0xFE00...0xFE9F => self.gpu.read_oam((addr - 0xFE00) as usize),
            // empty
            0xFEA0...0xFEFF | 0xFF4C...0xFF7F => 0,
            // I/O ports
            0xFF00...0xFF4B => {
                match addr & 0xFF {
                    0x40 | 0x42 | 0x43 | 0x44 | 0x47 => self.gpu.read_register(addr as usize),
                    _ => 0,
                }
            },
            // High RAM (zero page), used with LDH instructions
            0xFF80...0xFFFE => 0,
            // Interrupt Enable register
            0xFFFF => 0,

            _ => panic!("tried to read at unknown address: {:04x}", addr),
        }
    }

    pub fn write_b(&mut self, addr: u16, data: u8) {
        match addr {
            // bios area, 256B long for regular gameboy.
            0...0x00FF if self.loading_bios.get() => panic!("Writing to bootrom ${:04x} <- {:02x}", addr, data),
            // ROM0 area, this is banked memory, it will swap according to selected bank
            0x0000...0x3FFF => panic!("Writing to ROM0 ${:04x} <- {:02x}", addr, data),
            // ROM1 area, 16kB unbanked data
            0x4000...0x7FFF => panic!("Writing to ROM1 ${:04x} <- {:02x}", addr, data),
            // Graphics, 8kB VRAM
            0x8000...0x9FFF => self.gpu.write_vram((addr & 0x1FFF) as usize, data),
            // Switchable RAM bank, 8kB
            0xA000...0xBFFF => {
                // TODO: handle RAM banks
                self.data[addr as usize] = data;
            }
            // Internal RAM, 8kB
            0xC000...0xDFFF => {
                self.data[addr as usize] = data;
            },
            // Echo of internal RAM, this is less than 8k, up to 0xFDFF,
            0xE000...0xFDFF => {
                self.data[(addr - 0x2000) as usize] = data;
            },
            // Sprite attribute memory, 160B
            0xFE00...0xFE9F => {
                self.gpu.write_oam((addr - 0xFE00) as usize, data);
            }
            // empty
            0xFEA0...0xFEFF | 0xFF4C...0xFF7F => {},
            // I/O ports
            0xFF00...0xFF4B => {
                match addr & 0xFF {
                    0x40 | 0x42 | 0x43 | 0x44 | 0x47 => self.gpu.write_register(addr as usize, data),
                    _ => {},
                }
            },
            // High RAM (zero page), used with LDH instructions
            0xFF80...0xFFFE => unimplemented!(),
            // Interrupt Enable register
            0xFFFF => unimplemented!(),

            _ => panic!("tried to write at unknown address: {:4x}", addr),
        }
    }
}
<commit_msg>Added HRAM, minor fixes to memory<commit_after>//! The memory module.
//! This module declares a single struct, the Memory Management Unit (MMU).
//! The MMU acts as the system bus, allowing components to communicate with each other, reaches
//! RAM, ROM, I/O registers and more.
use std::fmt;
use std::cell::Cell;

use jeebie::gpu::GPU;
use jeebie::cart::Cartridge;
use jeebie::bootrom::DMG_BOOTROM;

/// The Memory Management Unit.
/// Provides access to all mapped memory in the system, including I/O and graphics.
pub struct MMU {
    // TODO: MMU should own RAM/High RAM (8k + 256 bytes), maybe some registers.
    data: [u8; 65536],
    loading_bios: Cell<bool>,

    pub gpu: GPU,
}

impl fmt::Debug for MMU {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "MMU 64k")
    }
}

impl MMU {
    pub fn new() -> MMU {
        MMU {
            loading_bios: Cell::new(true),
            data: [0; 65536],
            gpu: GPU::new(),
        }
    }

    pub fn load_rom(&mut self, cart: &Cartridge) {
        for i in 0..cart.size {
            self.data[i] = cart.data[i];
        }
    }

    /// reads a byte at the memory address specified
    pub fn read_b(&self, addr: u16) -> u8 {
        // when PC first reaches 0x100, the BIOS data is not addressable anymore.
        // using Cell sucks, but this is one of the few cases mentioned by official docs where
        // it is an option. Read is logically an immutable operation, but we need to make the
        // bios unaddressable after its first read.
        if self.loading_bios.get() && addr == 0x0100 {
            self.loading_bios.set(false);
        }

        match addr {
            // bios area, 256B long for regular gameboy.
            0...0x00FF if self.loading_bios.get() => DMG_BOOTROM[(addr & 0xFF) as usize],
            // ROM0 area accessible only when bootrom is disabled (first 256 bytes).
            0x0000...0x00FF if !self.loading_bios.get() => self.data[addr as usize],
            // ROM0 area, this is banked memory, it will swap according to selected bank
            0x0100...0x3FFF => self.data[addr as usize],
            // ROM1 area, 16kB unbanked data
            0x4000...0x7FFF => self.data[addr as usize],
            // Graphics, 8kB VRAM
            0x8000...0x9FFF => self.gpu.read_vram((addr & 0x1FFF) as usize),
            // Switchable RAM bank, 8kB
            0xA000...0xBFFF => {
                // TODO: handle RAM banks
                self.data[addr as usize]
            }
            // Internal RAM, 8kB
            0xC000...0xDFFF => self.data[addr as usize],
            // Echo of internal RAM, this is less than 8k, up to 0xFDFF,
            0xE000...0xFDFF => self.data[(addr - 0x2000) as usize],
            // Sprite attribute memory, 160B
            0xFE00...0xFE9F => self.gpu.read_oam((addr - 0xFE00) as usize),
            // empty
            0xFEA0...0xFEFF | 0xFF4C...0xFF7F => 0,
            // I/O ports
            0xFF00...0xFF4B => {
                match addr & 0xFF {
                    0x40 | 0x42 | 0x43 | 0x44 | 0x47 => self.gpu.read_register(addr as usize),
                    _ => unimplemented!(),
                }
            },
            // High RAM (zero page), used with LDH instructions
            0xFF80...0xFFFE => self.data[addr as usize],
            // Interrupt Enable register
            0xFFFF => unimplemented!(),

            _ => panic!("tried to read at unknown address: {:04x}", addr),
        }
    }

    pub fn write_b(&mut self, addr: u16, data: u8) {
        match addr {
            // bios area, 256B long for regular gameboy.
            0...0x00FF if self.loading_bios.get() => panic!("Writing to bootrom ${:04x} <- {:02x}", addr, data),
            // ROM0 area, this is banked memory, it will swap according to selected bank
            0x0000...0x3FFF => panic!("Writing to ROM0 ${:04x} <- {:02x}", addr, data),
            // ROM1 area, 16kB unbanked data
            0x4000...0x7FFF => panic!("Writing to ROM1 ${:04x} <- {:02x}", addr, data),
            // Graphics, 8kB VRAM
            0x8000...0x9FFF => self.gpu.write_vram((addr & 0x1FFF) as usize, data),
            // Switchable RAM bank, 8kB
            0xA000...0xBFFF => {
                // TODO: handle RAM banks
                self.data[addr as usize] = data;
            }
            // Internal RAM, 8kB
            0xC000...0xDFFF => {
                self.data[addr as usize] = data;
            },
            // Echo of internal RAM, this is less than 8k, up to 0xFDFF,
            0xE000...0xFDFF => {
                self.data[(addr - 0x2000) as usize] = data;
            },
            // Sprite attribute memory, 160B
            0xFE00...0xFE9F => {
                self.gpu.write_oam((addr - 0xFE00) as usize, data);
            }
            // empty
            0xFEA0...0xFEFF | 0xFF4C...0xFF7F => {},
            // I/O ports
            0xFF00...0xFF4B => {
                match addr & 0xFF {
                    0x40 | 0x42 | 0x43 | 0x44 | 0x47 => self.gpu.write_register(addr as usize, data),
                    _ => {},
                }
            },
            // High RAM (zero page), used with LDH instructions
            0xFF80...0xFFFE => { self.data[addr as usize] = data; },
            // Interrupt Enable register
            0xFFFF => unimplemented!(),

            _ => panic!("tried to write at unknown address: {:4x}", addr),
        }
    }
}
<|endoftext|>