<commit_before>use byteorder::ReadBytesExt;
use std::error::Error;
use std::io;
use std::io::prelude::*;
use std::fmt;
use std::net::TcpStream;
use std::time::Duration;
use bufstream::BufStream;
#[cfg(feature = "with-unix_socket")]
use unix_socket::UnixStream;
#[cfg(all(not(feature = "with-unix_socket"), all(unix, feature = "nightly")))]
use std::os::unix::net::UnixStream;
#[cfg(unix)]
use std::os::unix::io::{AsRawFd, RawFd};
#[cfg(windows)]
use std::os::windows::io::{AsRawSocket, RawSocket};

use {TlsMode, ConnectParams, ConnectTarget};
use error::ConnectError;
use io::TlsStream;
use message::{self, WriteMessage};
use message::Frontend;

const DEFAULT_PORT: u16 = 5432;

#[doc(hidden)]
pub trait StreamOptions {
    fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()>;
    fn set_nonblocking(&self, nonblock: bool) -> io::Result<()>;
}

impl StreamOptions for BufStream<Box<TlsStream>> {
    fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
        match self.get_ref().get_ref().0 {
            InternalStream::Tcp(ref s) => s.set_read_timeout(timeout),
            #[cfg(any(feature = "with-unix_socket", all(unix, feature = "nightly")))]
            InternalStream::Unix(ref s) => s.set_read_timeout(timeout),
        }
    }

    fn set_nonblocking(&self, nonblock: bool) -> io::Result<()> {
        match self.get_ref().get_ref().0 {
            InternalStream::Tcp(ref s) => s.set_nonblocking(nonblock),
            #[cfg(any(feature = "with-unix_socket", all(unix, feature = "nightly")))]
            InternalStream::Unix(ref s) => s.set_nonblocking(nonblock),
        }
    }
}

/// A connection to the Postgres server.
///
/// It implements `Read`, `Write` and `TlsStream`, as well as `AsRawFd` on
/// Unix platforms and `AsRawSocket` on Windows platforms.
pub struct Stream(InternalStream);

impl fmt::Debug for Stream {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match self.0 {
            InternalStream::Tcp(ref s) => fmt::Debug::fmt(s, fmt),
            #[cfg(any(feature = "with-unix_socket", all(unix, feature = "nightly")))]
            InternalStream::Unix(ref s) => fmt::Debug::fmt(s, fmt),
        }
    }
}

impl Read for Stream {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
}

impl Write for Stream {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.0.flush()
    }
}

impl TlsStream for Stream {
    fn get_ref(&self) -> &Stream {
        self
    }

    fn get_mut(&mut self) -> &mut Stream {
        self
    }
}

#[cfg(unix)]
impl AsRawFd for Stream {
    fn as_raw_fd(&self) -> RawFd {
        match self.0 {
            InternalStream::Tcp(ref s) => s.as_raw_fd(),
            #[cfg(any(feature = "with-unix_socket", all(unix, feature = "nightly")))]
            InternalStream::Unix(ref s) => s.as_raw_fd(),
        }
    }
}

#[cfg(windows)]
impl AsRawSocket for Stream {
    fn as_raw_socket(&self) -> RawSocket {
        // Unix sockets aren't supported on windows, so no need to match
        match self.0 {
            InternalStream::Tcp(ref s) => s.as_raw_socket(),
        }
    }
}

enum InternalStream {
    Tcp(TcpStream),
    #[cfg(any(feature = "with-unix_socket", all(unix, feature = "nightly")))]
    Unix(UnixStream),
}

impl Read for InternalStream {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        match *self {
            InternalStream::Tcp(ref mut s) => s.read(buf),
            #[cfg(any(feature = "with-unix_socket", all(unix, feature = "nightly")))]
            InternalStream::Unix(ref mut s) => s.read(buf),
        }
    }
}

impl Write for InternalStream {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        match *self {
            InternalStream::Tcp(ref mut s) => s.write(buf),
            #[cfg(any(feature = "with-unix_socket", all(unix, feature = "nightly")))]
            InternalStream::Unix(ref mut s) => s.write(buf),
        }
    }

    fn flush(&mut self) -> io::Result<()> {
        match *self {
            InternalStream::Tcp(ref mut s) => s.flush(),
            #[cfg(any(feature = "with-unix_socket", all(unix, feature = "nightly")))]
            InternalStream::Unix(ref mut s) => s.flush(),
        }
    }
}

fn open_socket(params: &ConnectParams) -> Result<InternalStream, ConnectError> {
    let port = params.port.unwrap_or(DEFAULT_PORT);
    match params.target {
        ConnectTarget::Tcp(ref host) => {
            Ok(try!(TcpStream::connect(&(&**host, port)).map(InternalStream::Tcp)))
        }
        #[cfg(any(feature = "with-unix_socket", all(unix, feature = "nightly")))]
        ConnectTarget::Unix(ref path) => {
            let path = path.join(&format!(".s.PGSQL.{}", port));
            Ok(try!(UnixStream::connect(&path).map(InternalStream::Unix)))
        }
    }
}

pub fn initialize_stream(params: &ConnectParams,
                         ssl: TlsMode)
                         -> Result<Box<TlsStream>, ConnectError> {
    let mut socket = Stream(try!(open_socket(params)));

    let (ssl_required, negotiator) = match ssl {
        TlsMode::None => return Ok(Box::new(socket)),
        TlsMode::Prefer(negotiator) => (false, negotiator),
        TlsMode::Require(negotiator) => (true, negotiator),
    };

    try!(socket.write_message(&Frontend::SslRequest { code: message::SSL_CODE }));
    try!(socket.flush());

    if try!(socket.read_u8()) == b'N' {
        if ssl_required {
            let err: Box<Error + Sync + Send> = "The server does not support SSL".into();
            return Err(ConnectError::Ssl(err));
        } else {
            return Ok(Box::new(socket));
        }
    }

    // Postgres doesn't support SSL over unix sockets
    let host = match params.target {
        ConnectTarget::Tcp(ref host) => host,
        #[cfg(any(feature = "with-unix_socket", all(unix, feature = "nightly")))]
        ConnectTarget::Unix(_) => return Err(ConnectError::Io(::bad_response())),
    };

    negotiator.tls_handshake(host, socket).map_err(ConnectError::Ssl)
}
<commit_msg>Cleanup<commit_after>use byteorder::ReadBytesExt;
use std::io;
use std::io::prelude::*;
use std::fmt;
use std::net::TcpStream;
use std::time::Duration;
use bufstream::BufStream;
#[cfg(feature = "with-unix_socket")]
use unix_socket::UnixStream;
#[cfg(all(not(feature = "with-unix_socket"), all(unix, feature = "nightly")))]
use std::os::unix::net::UnixStream;
#[cfg(unix)]
use std::os::unix::io::{AsRawFd, RawFd};
#[cfg(windows)]
use std::os::windows::io::{AsRawSocket, RawSocket};

use {TlsMode, ConnectParams, ConnectTarget};
use error::ConnectError;
use io::TlsStream;
use message::{self, WriteMessage};
use message::Frontend;

const DEFAULT_PORT: u16 = 5432;

#[doc(hidden)]
pub trait StreamOptions {
    fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()>;
    fn set_nonblocking(&self, nonblock: bool) -> io::Result<()>;
}

impl StreamOptions for BufStream<Box<TlsStream>> {
    fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
        match self.get_ref().get_ref().0 {
            InternalStream::Tcp(ref s) => s.set_read_timeout(timeout),
            #[cfg(any(feature = "with-unix_socket", all(unix, feature = "nightly")))]
            InternalStream::Unix(ref s) => s.set_read_timeout(timeout),
        }
    }

    fn set_nonblocking(&self, nonblock: bool) -> io::Result<()> {
        match self.get_ref().get_ref().0 {
            InternalStream::Tcp(ref s) => s.set_nonblocking(nonblock),
            #[cfg(any(feature = "with-unix_socket", all(unix, feature = "nightly")))]
            InternalStream::Unix(ref s) => s.set_nonblocking(nonblock),
        }
    }
}

/// A connection to the Postgres server.
///
/// It implements `Read`, `Write` and `TlsStream`, as well as `AsRawFd` on
/// Unix platforms and `AsRawSocket` on Windows platforms.
pub struct Stream(InternalStream);

impl fmt::Debug for Stream {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match self.0 {
            InternalStream::Tcp(ref s) => fmt::Debug::fmt(s, fmt),
            #[cfg(any(feature = "with-unix_socket", all(unix, feature = "nightly")))]
            InternalStream::Unix(ref s) => fmt::Debug::fmt(s, fmt),
        }
    }
}

impl Read for Stream {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
}

impl Write for Stream {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.0.flush()
    }
}

impl TlsStream for Stream {
    fn get_ref(&self) -> &Stream {
        self
    }

    fn get_mut(&mut self) -> &mut Stream {
        self
    }
}

#[cfg(unix)]
impl AsRawFd for Stream {
    fn as_raw_fd(&self) -> RawFd {
        match self.0 {
            InternalStream::Tcp(ref s) => s.as_raw_fd(),
            #[cfg(any(feature = "with-unix_socket", all(unix, feature = "nightly")))]
            InternalStream::Unix(ref s) => s.as_raw_fd(),
        }
    }
}

#[cfg(windows)]
impl AsRawSocket for Stream {
    fn as_raw_socket(&self) -> RawSocket {
        // Unix sockets aren't supported on windows, so no need to match
        match self.0 {
            InternalStream::Tcp(ref s) => s.as_raw_socket(),
        }
    }
}

enum InternalStream {
    Tcp(TcpStream),
    #[cfg(any(feature = "with-unix_socket", all(unix, feature = "nightly")))]
    Unix(UnixStream),
}

impl Read for InternalStream {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        match *self {
            InternalStream::Tcp(ref mut s) => s.read(buf),
            #[cfg(any(feature = "with-unix_socket", all(unix, feature = "nightly")))]
            InternalStream::Unix(ref mut s) => s.read(buf),
        }
    }
}

impl Write for InternalStream {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        match *self {
            InternalStream::Tcp(ref mut s) => s.write(buf),
            #[cfg(any(feature = "with-unix_socket", all(unix, feature = "nightly")))]
            InternalStream::Unix(ref mut s) => s.write(buf),
        }
    }

    fn flush(&mut self) -> io::Result<()> {
        match *self {
            InternalStream::Tcp(ref mut s) => s.flush(),
            #[cfg(any(feature = "with-unix_socket", all(unix, feature = "nightly")))]
            InternalStream::Unix(ref mut s) => s.flush(),
        }
    }
}

fn open_socket(params: &ConnectParams) -> Result<InternalStream, ConnectError> {
    let port = params.port.unwrap_or(DEFAULT_PORT);
    match params.target {
        ConnectTarget::Tcp(ref host) => {
            Ok(try!(TcpStream::connect(&(&**host, port)).map(InternalStream::Tcp)))
        }
        #[cfg(any(feature = "with-unix_socket", all(unix, feature = "nightly")))]
        ConnectTarget::Unix(ref path) => {
            let path = path.join(&format!(".s.PGSQL.{}", port));
            Ok(try!(UnixStream::connect(&path).map(InternalStream::Unix)))
        }
    }
}

pub fn initialize_stream(params: &ConnectParams,
                         tls: TlsMode)
                         -> Result<Box<TlsStream>, ConnectError> {
    let mut socket = Stream(try!(open_socket(params)));

    let (tls_required, handshaker) = match tls {
        TlsMode::None => return Ok(Box::new(socket)),
        TlsMode::Prefer(handshaker) => (false, handshaker),
        TlsMode::Require(handshaker) => (true, handshaker),
    };

    try!(socket.write_message(&Frontend::SslRequest { code: message::SSL_CODE }));
    try!(socket.flush());

    if try!(socket.read_u8()) == b'N' {
        if tls_required {
            return Err(ConnectError::Ssl("the server does not support TLS".into()));
        } else {
            return Ok(Box::new(socket));
        }
    }

    let host = match params.target {
        ConnectTarget::Tcp(ref host) => host,
        // Postgres doesn't support TLS over unix sockets
        #[cfg(any(feature = "with-unix_socket", all(unix, feature = "nightly")))]
        ConnectTarget::Unix(_) => return Err(ConnectError::Io(::bad_response())),
    };

    handshaker.tls_handshake(host, socket).map_err(ConnectError::Ssl)
}
<|endoftext|>


<commit_before>use command::Command;
use vm::VM;

pub struct Program {
    instructions: Vec<Command>,
    instruction_pointer: Option<usize>,
    current_depth: u64,
    pub status: ProgramStatus,
}

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum ProgramStatus {
    Normal,
    Seeking(u64),
}

impl Program {
    pub fn new() -> Program {
        Program {
            instructions: Vec::new(),
            instruction_pointer: None,
            current_depth: 0,
            status: ProgramStatus::Normal,
        }
    }

    pub fn append(&mut self, instructions: &[Command]) {
        self.instructions.extend(instructions.iter().cloned());
        if self.instruction_pointer.is_none() {
            self.instruction_pointer = Some(0);
        }
    }

    pub fn execute(&mut self, vm: &mut VM) {
        match (self.instruction_pointer, self.status) {
            (Some(index), ProgramStatus::Seeking(_)) => {
                let (new_index, new_depth, new_status) = self.handle_jump_forward(vm, index);
                self.instruction_pointer = Some(new_index);
                self.current_depth = new_depth;
                self.status = new_status;
                if new_index < self.instructions.len() { self.execute(vm); }
            }

            (Some(mut index), ProgramStatus::Normal) => {
                while index < self.instructions.len() {
                    match self.instructions[index] {
                        Command::JumpBackward => self.handle_jump_backward(vm, &mut index),

                        Command::JumpForward => {
                            let (new_index, new_depth, new_status) = self.handle_jump_forward(vm, index);
                            index = new_index;
                            self.current_depth = new_depth;
                            self.status = new_status;
                        }

                        command => {
                            vm.apply(command);
                            index += 1;
                        }
                    }
                }

                self.instruction_pointer = Some(index);
            }

            _ => {}
        }
    }

    fn handle_jump_backward(&mut self, vm: &VM, index_ref: &mut usize) {
        match vm.cells[vm.data_pointer] {
            0 => {
                self.current_depth -= 1;
                *index_ref += 1;
            }

            _ => {
                let goal_depth = self.current_depth;
                for index in (0..*index_ref).rev() {
                    match self.instructions[index] {
                        Command::JumpBackward => self.current_depth += 1,
                        Command::JumpForward => {
                            if self.current_depth == goal_depth {
                                *index_ref = index + 1;
                                return;
                            }
                            self.current_depth -= 1;
                        }
                        _ => {}
                    }
                }
                panic!("No starting brace found!");
            }
        }
    }

    fn seek_forward(&self, starting_index: usize) -> (usize, u64, ProgramStatus) {
        match self.status {
            ProgramStatus::Seeking(goal_depth) => {
                let mut depth = self.current_depth;
                for index in starting_index..self.instructions.len() {
                    match self.instructions[index] {
                        Command::JumpForward => depth += 1,
                        Command::JumpBackward => depth  -= 1,
                        _ => {}
                    }
                    if depth == goal_depth {
                        return (index + 1, self.current_depth, ProgramStatus::Normal);
                    }
                }

                return (self.instructions.len()
                       , self.current_depth
                       , ProgramStatus::Seeking(goal_depth));
            }

            ProgramStatus::Normal => return (starting_index, self.current_depth, self.status)
        }
    }

    fn handle_jump_forward(&self, vm: &VM, index: usize) -> (usize, u64, ProgramStatus){
        match (vm.cells[vm.data_pointer], self.status) {
            (0, ProgramStatus::Normal) => self.seek_forward(index),
            (_, ProgramStatus::Normal) => (index + 1, self.current_depth + 1, ProgramStatus::Normal),
            (_, ProgramStatus::Seeking(_)) => self.seek_forward(index),

        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    pub fn test_seek_forward_normal() {
        let program = Program {
            instruction_pointer: None,
            current_depth: 0,
            status: ProgramStatus::Seeking(0),
            instructions: vec![
                Command::JumpForward,
                Command::JumpForward,
                Command::JumpBackward,
                Command::JumpBackward,
            ],
        };
        let (new_index, new_depth, new_status) = program.seek_forward(0);
        assert_eq!(new_depth, 0);
        assert_eq!(new_index, 4);
        assert_eq!(new_status, ProgramStatus::Normal);
    }

    #[test]
    pub fn test_seek_forward_seeking() {
        let program = Program {
            instruction_pointer: None,
            current_depth: 0,
            status: ProgramStatus::Seeking(0),
            instructions: vec![
                Command::JumpForward,
                Command::JumpForward,
                Command::JumpBackward,
            ],
        };
        let (new_index, new_depth, new_status) = program.seek_forward(0);
        assert_eq!(new_depth, 1);
        assert_eq!(new_index, 3);
        assert_eq!(new_status, ProgramStatus::Seeking(0));
    }
}
<commit_msg>Start from scratch on execute logic..<commit_after>use command::Command;
use vm::VM;

pub struct Program {
    instructions: Vec<Command>,
    instruction_pointer: Option<usize>,
    current_depth: u64,
    pub status: ProgramStatus,
}

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum ProgramStatus {
    Normal,
    Seeking(u64),
}

impl Program {
    pub fn new() -> Program {
        Program {
            instructions: Vec::new(),
            instruction_pointer: None,
            current_depth: 0,
            status: ProgramStatus::Normal,
        }
    }

    pub fn append(&mut self, instructions: &[Command]) {
        self.instructions.extend(instructions.iter().cloned());
        if self.instruction_pointer.is_none() {
            self.instruction_pointer = Some(0);
        }
    }

    pub fn execute(&mut self, vm: &mut VM) {
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::ffi::OsStr;
use std::fs;
use std::fmt;
use std::path::{Path, PathBuf};
use std::result::Result as StdResult;
use std::str;

use java_properties;
use toml;
use walkdir::{DirEntry, WalkDir, WalkDirIterator};

use super::errors::*;
use super::format::Style;
use super::fsutils;
use super::template::Template;

type Context = HashMap<String, String>;

#[derive(Debug)]
pub struct Project {
    pub root_path: Option<String>,
    pub config_format: ConfigFormat,
    pub style: Style,
}

#[derive(Copy, Clone, Debug)]
pub enum ConfigFormat {
    JavaProps,
    Toml,
}

impl fmt::Display for ConfigFormat {
    fn fmt(&self, f: &mut fmt::Formatter) -> StdResult<(), fmt::Error> {
        let name = match *self {
            ConfigFormat::JavaProps => "properties",
            ConfigFormat::Toml => "toml",
        };
        write!(f, "default.{}", &name)
    }
}

impl Default for Project {
    fn default() -> Project {
        Project {
            root_path: None,
            config_format: ConfigFormat::Toml,
            style: Style::Simple,
        }
    }
}

impl Project {
    pub fn new_g8(root: Option<&str>) -> Project {
        Project {
            root_path: root.map(|v| v.to_string()),
            config_format: ConfigFormat::JavaProps,
            style: Style::Giter8,
        }
    }

    pub fn set_root_dir(&mut self, root: &str) -> &mut Project {
        self.root_path = Some(root.into());
        self
    }

    pub fn resolve_root_dir(&self, clone_root: &Path) -> PathBuf {
        let mut buf = clone_root.to_path_buf();

        if let Some(ref inner) = self.root_path {
            if fsutils::exists(clone_root.join(inner)) {
                buf.push(inner);
            }
        }
        buf
    }

    pub fn default_context(&self, clone_root: &Path) -> Result<Context> {
        let root = self.resolve_root_dir(clone_root);
        get_default_context(self, &root)
    }

    // TODO: give clear `Err` type
    // TODO: make it run async
    pub fn generate(&self,
                    context: &Context,
                    clone_root: &Path,
                    dest: &Path,
                    dry_run: bool)
                    -> Result<()> {

        let root = self.resolve_root_dir(clone_root);
        let walker = WalkDir::new(&root).into_iter();

        let mut file_map: HashMap<String, String> = HashMap::new();
        let default_ctx = root.join(format!("{}", &self.config_format));

        if !dry_run {
            fs::create_dir_all(dest).unwrap();
        }

        for entry in walker.filter_entry(|e| !is_git_metadata(e)) {
            let entry = entry.unwrap();

            if entry.path() == &root || entry.path() == &default_ctx {
                debug!("skipping {:?}", entry.file_name());
                continue;
            }

            let mut segment: Vec<&OsStr> = Vec::new();
            let mut rel_path_up = entry.path().parent();
            let mut upwards = 1;
            while let Some(parent) = rel_path_up {
                if upwards >= entry.depth() {
                    break;
                } else {
                    segment.push(parent.file_name().unwrap_or("".as_ref()));
                }
                upwards += 1;
                rel_path_up = parent.parent();
            }

            let base = entry.file_name().to_string_lossy().to_string();
            let mut dest = dest.to_path_buf();
            if !segment.is_empty() {
                segment.reverse();
                for part in segment {
                    if let Some(rep) = file_map.get(&part.to_string_lossy().to_string()) {
                        debug!("File tree altered: {:?} => {:?}", &part, rep);
                        dest.push(rep);
                    } else {
                        dest.push(part);
                    }
                }
            }

            let mut writer = Vec::new();
            Template::compile_inline(&mut writer,
                                     Style::Pathname,
                                     &base,
                                     context)
                                     .unwrap();

            let name = str::from_utf8(&writer).unwrap();
            if name != &base {
                file_map.insert(base.clone(), name.to_string());
            }
            dest.push(name);
            debug!("Destination entry: {:?}", dest);

            // TODO:
            if !dry_run {
                if entry.file_type().is_file() {
                    let mut tpl = Template::read_file(self.style.clone(), &entry.path()).unwrap();
                    let mut f = fs::OpenOptions::new()
                        .write(true)
                        .truncate(true)
                        .create(true)
                        .open(dest.as_path())
                        .unwrap();

                    tpl.write(&mut f, context).unwrap();
                    f.sync_data().unwrap();
                    // fs::copy(&entry.path(), dest.as_path()).expect("Failed to copy file");
                } else if entry.file_type().is_dir() {
                    fs::create_dir_all(dest.as_path()).expect("Failed to copy directory");
                }
            }
        }
        debug!("{:?}", &file_map);

        Ok(())
    }
}

fn is_git_metadata(entry: &DirEntry) -> bool {
    let is_git = entry.file_name().to_str().map(|s| s == ".git").unwrap_or(false);
    fsutils::is_directory(entry.path()) && is_git
}

fn get_default_context(project: &Project, root_dir: &Path) -> Result<Context> {
    let default_ctx = root_dir.join(format!("{}", project.config_format));

    match project.config_format {
        ConfigFormat::JavaProps => {
            fs::File::open(&default_ctx)
                .map(|f| java_properties::read(f).unwrap())
                .map_err(|e| ErrorKind::Io(e).into())
        }
        ConfigFormat::Toml => {
            fsutils::read_file(&default_ctx)
                .map(|s| toml::decode_str::<HashMap<String, String>>(&s).unwrap())
                .chain_err(|| ErrorKind::TomlDecodeFailure)
        }
    }
}
<commit_msg>project: changed key type of cache to OsString from String, used in renaming plaeholders as pathnames<commit_after>use std::collections::HashMap;
use std::ffi::{OsStr, OsString};
use std::fs;
use std::fmt;
use std::path::{Path, PathBuf};
use std::result::Result as StdResult;
use std::str;

use java_properties;
use toml;
use walkdir::{DirEntry, WalkDir, WalkDirIterator};

use super::errors::*;
use super::format::Style;
use super::fsutils;
use super::template::Template;

type Context = HashMap<String, String>;

#[derive(Debug)]
pub struct Project {
    pub root_path: Option<String>,
    pub config_format: ConfigFormat,
    pub style: Style,
}

#[derive(Copy, Clone, Debug)]
pub enum ConfigFormat {
    JavaProps,
    Toml,
}

impl fmt::Display for ConfigFormat {
    fn fmt(&self, f: &mut fmt::Formatter) -> StdResult<(), fmt::Error> {
        let name = match *self {
            ConfigFormat::JavaProps => "properties",
            ConfigFormat::Toml => "toml",
        };
        write!(f, "default.{}", &name)
    }
}

impl Default for Project {
    fn default() -> Project {
        Project {
            root_path: None,
            config_format: ConfigFormat::Toml,
            style: Style::Simple,
        }
    }
}

impl Project {
    pub fn new_g8(root: Option<&str>) -> Project {
        Project {
            root_path: root.map(|v| v.to_string()),
            config_format: ConfigFormat::JavaProps,
            style: Style::Giter8,
        }
    }

    pub fn set_root_dir(&mut self, root: &str) -> &mut Project {
        self.root_path = Some(root.into());
        self
    }

    pub fn resolve_root_dir(&self, clone_root: &Path) -> PathBuf {
        let mut buf = clone_root.to_path_buf();

        if let Some(ref inner) = self.root_path {
            if fsutils::exists(clone_root.join(inner)) {
                buf.push(inner);
            }
        }
        buf
    }

    pub fn default_context(&self, clone_root: &Path) -> Result<Context> {
        let root = self.resolve_root_dir(clone_root);
        get_default_context(self, &root)
    }

    // TODO: give clear `Err` type
    // TODO: make it run async
    pub fn generate(&self,
                    context: &Context,
                    clone_root: &Path,
                    dest: &Path,
                    dry_run: bool)
                    -> Result<()> {

        let root = self.resolve_root_dir(clone_root);
        let walker = WalkDir::new(&root).into_iter();

        let mut file_map: HashMap<OsString, String> = HashMap::new();
        let default_ctx = root.join(format!("{}", &self.config_format));

        if !dry_run {
            fs::create_dir_all(dest).unwrap();
        }

        for entry in walker.filter_entry(|e| !is_git_metadata(e)) {
            let entry = entry.unwrap();

            if entry.path() == &root || entry.path() == &default_ctx {
                debug!("skipping {:?}", entry.file_name());
                continue;
            }

            let mut segment: Vec<&OsStr> = Vec::new();
            let mut rel_path_up = entry.path().parent();
            let mut upwards = 1;
            while let Some(parent) = rel_path_up {
                if upwards >= entry.depth() {
                    break;
                } else {
                    segment.push(parent.file_name().unwrap_or("".as_ref()));
                }
                upwards += 1;
                rel_path_up = parent.parent();
            }

            let base = entry.file_name();
            let mut dest = dest.to_path_buf();
            if !segment.is_empty() {
                segment.reverse();
                for part in segment {
                    if let Some(rep) = file_map.get(part) {
                        debug!("File tree altered: {:?} => {:?}", part, rep);
                        dest.push(rep);
                    } else {
                        dest.push(part);
                    }
                }
            }

            let mut buf = Vec::new();
            Template::compile_inline(&mut buf,
                                     Style::Pathname,
                                     &base.to_string_lossy(),
                                     context)
                                     .unwrap();

            let name = String::from_utf8(buf).unwrap();
            if &name != base.to_string_lossy().as_ref() {
                file_map.insert(base.to_os_string(), name.clone());
            }
            dest.push(&name);
            debug!("Destination entry: {:?}", dest);

            // TODO:
            if !dry_run {
                if entry.file_type().is_file() {
                    let mut tpl = Template::read_file(self.style.clone(), &entry.path()).unwrap();
                    let mut f = fs::OpenOptions::new()
                        .write(true)
                        .truncate(true)
                        .create(true)
                        .open(dest.as_path())
                        .unwrap();

                    tpl.write(&mut f, context).unwrap();
                    f.sync_data().unwrap();
                    // fs::copy(&entry.path(), dest.as_path()).expect("Failed to copy file");
                } else if entry.file_type().is_dir() {
                    fs::create_dir_all(dest.as_path()).expect("Failed to copy directory");
                }
            }
        }
        debug!("{:?}", &file_map);

        Ok(())
    }
}

fn is_git_metadata(entry: &DirEntry) -> bool {
    let is_git = entry.file_name().to_str().map(|s| s == ".git").unwrap_or(false);
    fsutils::is_directory(entry.path()) && is_git
}

fn get_default_context(project: &Project, root_dir: &Path) -> Result<Context> {
    let default_ctx = root_dir.join(format!("{}", project.config_format));

    match project.config_format {
        ConfigFormat::JavaProps => {
            fs::File::open(&default_ctx)
                .map(|f| java_properties::read(f).unwrap())
                .map_err(|e| ErrorKind::Io(e).into())
        }
        ConfigFormat::Toml => {
            fsutils::read_file(&default_ctx)
                .map(|s| toml::decode_str::<HashMap<String, String>>(&s).unwrap())
                .chain_err(|| ErrorKind::TomlDecodeFailure)
        }
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use api::{BuiltDisplayList, ColorF, DynamicProperties, Epoch, LayerSize, LayoutSize};
use api::{FilterOp, LayoutTransform, PipelineId, PropertyBinding, PropertyBindingId};
use api::{ItemRange, MixBlendMode, StackingContext};
use internal_types::FastHashMap;
use std::sync::Arc;

/// Stores a map of the animated property bindings for the current display list. These
/// can be used to animate the transform and/or opacity of a display list without
/// re-submitting the display list itself.
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(Clone)]
pub struct SceneProperties {
    transform_properties: FastHashMap<PropertyBindingId, LayoutTransform>,
    float_properties: FastHashMap<PropertyBindingId, f32>,
}

impl SceneProperties {
    pub fn new() -> Self {
        SceneProperties {
            transform_properties: FastHashMap::default(),
            float_properties: FastHashMap::default(),
        }
    }

    /// Set the current property list for this display list.
    pub fn set_properties(&mut self, properties: DynamicProperties) {
        self.transform_properties.clear();
        self.float_properties.clear();

        for property in properties.transforms {
            self.transform_properties
                .insert(property.key.id, property.value);
        }

        for property in properties.floats {
            self.float_properties
                .insert(property.key.id, property.value);
        }
    }

    /// Get the current value for a transform property.
    pub fn resolve_layout_transform(
        &self,
        property: &PropertyBinding<LayoutTransform>,
    ) -> LayoutTransform {
        match *property {
            PropertyBinding::Value(value) => value,
            PropertyBinding::Binding(ref key) => {
                self.transform_properties
                    .get(&key.id)
                    .cloned()
                    .unwrap_or_else(|| {
                        warn!("Property binding has an invalid value.");
                        debug!("key={:?}", key);
                        LayoutTransform::identity()
                    })
            }
        }
    }

    /// Get the current value for a float property.
    pub fn resolve_float(
        &self,
        property: &PropertyBinding<f32>,
        default_value: f32
    ) -> f32 {
        match *property {
            PropertyBinding::Value(value) => value,
            PropertyBinding::Binding(ref key) => {
                self.float_properties
                    .get(&key.id)
                    .cloned()
                    .unwrap_or_else(|| {
                        warn!("Property binding has an invalid value.");
                        debug!("key={:?}", key);
                        default_value
                    })
            }
        }
    }
}

/// A representation of the layout within the display port for a given document or iframe.
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(Clone)]
pub struct ScenePipeline {
    pub pipeline_id: PipelineId,
    pub viewport_size: LayerSize,
    pub content_size: LayoutSize,
    pub background_color: Option<ColorF>,
    pub display_list: BuiltDisplayList,
}

/// A complete representation of the layout bundling visible pipelines together.
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(Clone)]
pub struct Scene {
    pub root_pipeline_id: Option<PipelineId>,
    pub pipelines: FastHashMap<PipelineId, Arc<ScenePipeline>>,
    pub pipeline_epochs: FastHashMap<PipelineId, Epoch>,
}

impl Scene {
    pub fn new() -> Self {
        Scene {
            root_pipeline_id: None,
            pipelines: FastHashMap::default(),
            pipeline_epochs: FastHashMap::default(),
        }
    }

    pub fn set_root_pipeline_id(&mut self, pipeline_id: PipelineId) {
        self.root_pipeline_id = Some(pipeline_id);
    }

    pub fn set_display_list(
        &mut self,
        pipeline_id: PipelineId,
        epoch: Epoch,
        display_list: BuiltDisplayList,
        background_color: Option<ColorF>,
        viewport_size: LayerSize,
        content_size: LayoutSize,
    ) {
        let new_pipeline = ScenePipeline {
            pipeline_id,
            viewport_size,
            content_size,
            background_color,
            display_list,
        };

        self.pipelines.insert(pipeline_id, Arc::new(new_pipeline));
        self.pipeline_epochs.insert(pipeline_id, epoch);
    }

    pub fn remove_pipeline(&mut self, pipeline_id: PipelineId) {
        if self.root_pipeline_id == Some(pipeline_id) {
            self.root_pipeline_id = None;
        }
        self.pipelines.remove(&pipeline_id);
    }

    pub fn update_epoch(&mut self, pipeline_id: PipelineId, epoch: Epoch) {
        self.pipeline_epochs.insert(pipeline_id, epoch);
    }
}

/// An arbitrary number which we assume opacity is invisible below.
pub const OPACITY_EPSILON: f32 = 0.001;

pub trait FilterOpHelpers {
    fn is_visible(&self) -> bool;
    fn is_noop(&self) -> bool;
}

impl FilterOpHelpers for FilterOp {
    fn is_visible(&self) -> bool {
        match *self {
            FilterOp::Blur(..) |
            FilterOp::Brightness(..) |
            FilterOp::Contrast(..) |
            FilterOp::Grayscale(..) |
            FilterOp::HueRotate(..) |
            FilterOp::Invert(..) |
            FilterOp::Saturate(..) |
            FilterOp::Sepia(..) |
            FilterOp::DropShadow(..) |
            FilterOp::ColorMatrix(..) => true,
            FilterOp::Opacity(_, amount) => {
                amount > OPACITY_EPSILON
            }
        }
    }

    fn is_noop(&self) -> bool {
        match *self {
            FilterOp::Blur(length) => length == 0.0,
            FilterOp::Brightness(amount) => amount == 1.0,
            FilterOp::Contrast(amount) => amount == 1.0,
            FilterOp::Grayscale(amount) => amount == 0.0,
            FilterOp::HueRotate(amount) => amount == 0.0,
            FilterOp::Invert(amount) => amount == 0.0,
            FilterOp::Opacity(_, amount) => amount >= 1.0,
            FilterOp::Saturate(amount) => amount == 1.0,
            FilterOp::Sepia(amount) => amount == 0.0,
            FilterOp::DropShadow(offset, blur, _) => {
                offset.x == 0.0 && offset.y == 0.0 && blur == 0.0
            },
            FilterOp::ColorMatrix(matrix) => {
                matrix == [1.0, 0.0, 0.0, 0.0,
                           0.0, 1.0, 0.0, 0.0,
                           0.0, 0.0, 1.0, 0.0,
                           0.0, 0.0, 0.0, 1.0,
                           0.0, 0.0, 0.0, 0.0]
            }
        }
    }
}

pub trait StackingContextHelpers {
    fn mix_blend_mode_for_compositing(&self) -> Option<MixBlendMode>;
    fn filter_ops_for_compositing(
        &self,
        display_list: &BuiltDisplayList,
        input_filters: ItemRange<FilterOp>,
    ) -> Vec<FilterOp>;
}

impl StackingContextHelpers for StackingContext {
    fn mix_blend_mode_for_compositing(&self) -> Option<MixBlendMode> {
        match self.mix_blend_mode {
            MixBlendMode::Normal => None,
            _ => Some(self.mix_blend_mode),
        }
    }

    fn filter_ops_for_compositing(
        &self,
        display_list: &BuiltDisplayList,
        input_filters: ItemRange<FilterOp>,
    ) -> Vec<FilterOp> {
        // TODO(gw): Now that we resolve these later on,
        //           we could probably make it a bit
        //           more efficient than cloning these here.
        let mut filters = vec![];
        for filter in display_list.get(input_filters) {
            filters.push(filter);
        }
        filters
    }
}
<commit_msg>Remove the pipeline's epoch from the scene when removing the pipeline itself.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use api::{BuiltDisplayList, ColorF, DynamicProperties, Epoch, LayerSize, LayoutSize};
use api::{FilterOp, LayoutTransform, PipelineId, PropertyBinding, PropertyBindingId};
use api::{ItemRange, MixBlendMode, StackingContext};
use internal_types::FastHashMap;
use std::sync::Arc;

/// Stores a map of the animated property bindings for the current display list. These
/// can be used to animate the transform and/or opacity of a display list without
/// re-submitting the display list itself.
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(Clone)]
pub struct SceneProperties {
    transform_properties: FastHashMap<PropertyBindingId, LayoutTransform>,
    float_properties: FastHashMap<PropertyBindingId, f32>,
}

impl SceneProperties {
    pub fn new() -> Self {
        SceneProperties {
            transform_properties: FastHashMap::default(),
            float_properties: FastHashMap::default(),
        }
    }

    /// Set the current property list for this display list.
    pub fn set_properties(&mut self, properties: DynamicProperties) {
        self.transform_properties.clear();
        self.float_properties.clear();

        for property in properties.transforms {
            self.transform_properties
                .insert(property.key.id, property.value);
        }

        for property in properties.floats {
            self.float_properties
                .insert(property.key.id, property.value);
        }
    }

    /// Get the current value for a transform property.
    pub fn resolve_layout_transform(
        &self,
        property: &PropertyBinding<LayoutTransform>,
    ) -> LayoutTransform {
        match *property {
            PropertyBinding::Value(value) => value,
            PropertyBinding::Binding(ref key) => {
                self.transform_properties
                    .get(&key.id)
                    .cloned()
                    .unwrap_or_else(|| {
                        warn!("Property binding has an invalid value.");
                        debug!("key={:?}", key);
                        LayoutTransform::identity()
                    })
            }
        }
    }

    /// Get the current value for a float property.
    pub fn resolve_float(
        &self,
        property: &PropertyBinding<f32>,
        default_value: f32
    ) -> f32 {
        match *property {
            PropertyBinding::Value(value) => value,
            PropertyBinding::Binding(ref key) => {
                self.float_properties
                    .get(&key.id)
                    .cloned()
                    .unwrap_or_else(|| {
                        warn!("Property binding has an invalid value.");
                        debug!("key={:?}", key);
                        default_value
                    })
            }
        }
    }
}

/// A representation of the layout within the display port for a given document or iframe.
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(Clone)]
pub struct ScenePipeline {
    pub pipeline_id: PipelineId,
    pub viewport_size: LayerSize,
    pub content_size: LayoutSize,
    pub background_color: Option<ColorF>,
    pub display_list: BuiltDisplayList,
}

/// A complete representation of the layout bundling visible pipelines together.
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(Clone)]
pub struct Scene {
    pub root_pipeline_id: Option<PipelineId>,
    pub pipelines: FastHashMap<PipelineId, Arc<ScenePipeline>>,
    pub pipeline_epochs: FastHashMap<PipelineId, Epoch>,
}

impl Scene {
    pub fn new() -> Self {
        Scene {
            root_pipeline_id: None,
            pipelines: FastHashMap::default(),
            pipeline_epochs: FastHashMap::default(),
        }
    }

    pub fn set_root_pipeline_id(&mut self, pipeline_id: PipelineId) {
        self.root_pipeline_id = Some(pipeline_id);
    }

    pub fn set_display_list(
        &mut self,
        pipeline_id: PipelineId,
        epoch: Epoch,
        display_list: BuiltDisplayList,
        background_color: Option<ColorF>,
        viewport_size: LayerSize,
        content_size: LayoutSize,
    ) {
        let new_pipeline = ScenePipeline {
            pipeline_id,
            viewport_size,
            content_size,
            background_color,
            display_list,
        };

        self.pipelines.insert(pipeline_id, Arc::new(new_pipeline));
        self.pipeline_epochs.insert(pipeline_id, epoch);
    }

    pub fn remove_pipeline(&mut self, pipeline_id: PipelineId) {
        if self.root_pipeline_id == Some(pipeline_id) {
            self.root_pipeline_id = None;
        }
        self.pipelines.remove(&pipeline_id);
        self.pipeline_epochs.remove(&pipeline_id);
    }

    pub fn update_epoch(&mut self, pipeline_id: PipelineId, epoch: Epoch) {
        self.pipeline_epochs.insert(pipeline_id, epoch);
    }
}

/// An arbitrary number which we assume opacity is invisible below.
pub const OPACITY_EPSILON: f32 = 0.001;

pub trait FilterOpHelpers {
    fn is_visible(&self) -> bool;
    fn is_noop(&self) -> bool;
}

impl FilterOpHelpers for FilterOp {
    fn is_visible(&self) -> bool {
        match *self {
            FilterOp::Blur(..) |
            FilterOp::Brightness(..) |
            FilterOp::Contrast(..) |
            FilterOp::Grayscale(..) |
            FilterOp::HueRotate(..) |
            FilterOp::Invert(..) |
            FilterOp::Saturate(..) |
            FilterOp::Sepia(..) |
            FilterOp::DropShadow(..) |
            FilterOp::ColorMatrix(..) => true,
            FilterOp::Opacity(_, amount) => {
                amount > OPACITY_EPSILON
            }
        }
    }

    fn is_noop(&self) -> bool {
        match *self {
            FilterOp::Blur(length) => length == 0.0,
            FilterOp::Brightness(amount) => amount == 1.0,
            FilterOp::Contrast(amount) => amount == 1.0,
            FilterOp::Grayscale(amount) => amount == 0.0,
            FilterOp::HueRotate(amount) => amount == 0.0,
            FilterOp::Invert(amount) => amount == 0.0,
            FilterOp::Opacity(_, amount) => amount >= 1.0,
            FilterOp::Saturate(amount) => amount == 1.0,
            FilterOp::Sepia(amount) => amount == 0.0,
            FilterOp::DropShadow(offset, blur, _) => {
                offset.x == 0.0 && offset.y == 0.0 && blur == 0.0
            },
            FilterOp::ColorMatrix(matrix) => {
                matrix == [1.0, 0.0, 0.0, 0.0,
                           0.0, 1.0, 0.0, 0.0,
                           0.0, 0.0, 1.0, 0.0,
                           0.0, 0.0, 0.0, 1.0,
                           0.0, 0.0, 0.0, 0.0]
            }
        }
    }
}

pub trait StackingContextHelpers {
    fn mix_blend_mode_for_compositing(&self) -> Option<MixBlendMode>;
    fn filter_ops_for_compositing(
        &self,
        display_list: &BuiltDisplayList,
        input_filters: ItemRange<FilterOp>,
    ) -> Vec<FilterOp>;
}

impl StackingContextHelpers for StackingContext {
    fn mix_blend_mode_for_compositing(&self) -> Option<MixBlendMode> {
        match self.mix_blend_mode {
            MixBlendMode::Normal => None,
            _ => Some(self.mix_blend_mode),
        }
    }

    fn filter_ops_for_compositing(
        &self,
        display_list: &BuiltDisplayList,
        input_filters: ItemRange<FilterOp>,
    ) -> Vec<FilterOp> {
        // TODO(gw): Now that we resolve these later on,
        //           we could probably make it a bit
        //           more efficient than cloning these here.
        let mut filters = vec![];
        for filter in display_list.get(input_filters) {
            filters.push(filter);
        }
        filters
    }
}
<|endoftext|>


<commit_before>
use ndarray::*;
use super::traits::*;

pub struct TimeSeries<'a, TEO, S, D>
    where S: DataMut,
          D: Dimension,
          TEO: TimeEvolutionBase<S, D> + 'a
{
    state: ArrayBase<S, D>,
    teo: &'a TEO,
}

pub fn time_series<'a, TEO, S, D>(x0: ArrayBase<S, D>, teo: &'a TEO) -> TimeSeries<'a, TEO, S, D>
    where S: DataMut,
          D: Dimension,
          TEO: TimeEvolutionBase<S, D>
{
    TimeSeries {
        state: x0,
        teo: teo,
    }
}

impl<'a, TEO, S, D> TimeSeries<'a, TEO, S, D>
    where S: DataMut + DataClone,
          D: Dimension,
          TEO: TimeEvolutionBase<S, D>
{
    pub fn iterate(&mut self) {
        self.teo.iterate(&mut self.state);
    }
}

impl<'a, TEO, S, D> Iterator for TimeSeries<'a, TEO, S, D>
    where S: DataMut + DataClone,
          D: Dimension,
          TEO: TimeEvolutionBase<S, D>
{
    type Item = ArrayBase<S, D>;
    fn next(&mut self) -> Option<Self::Item> {
        self.iterate();
        Some(self.state.clone())
    }
}
<commit_msg>NStep adaptor<commit_after>
use ndarray::*;
use ndarray_linalg::*;
use super::traits::*;

pub struct TimeSeries<'a, TEO, S, D>
    where S: DataMut,
          D: Dimension,
          TEO: TimeEvolutionBase<S, D> + 'a
{
    state: ArrayBase<S, D>,
    teo: &'a TEO,
}

pub fn time_series<'a, TEO, S, D>(x0: ArrayBase<S, D>, teo: &'a TEO) -> TimeSeries<'a, TEO, S, D>
    where S: DataMut,
          D: Dimension,
          TEO: TimeEvolutionBase<S, D>
{
    TimeSeries {
        state: x0,
        teo: teo,
    }
}

impl<'a, TEO, S, D> TimeSeries<'a, TEO, S, D>
    where S: DataMut + DataClone,
          D: Dimension,
          TEO: TimeEvolutionBase<S, D>
{
    pub fn iterate(&mut self) {
        self.teo.iterate(&mut self.state);
    }
}

impl<'a, TEO, S, D> Iterator for TimeSeries<'a, TEO, S, D>
    where S: DataMut + DataClone,
          D: Dimension,
          TEO: TimeEvolutionBase<S, D>
{
    type Item = ArrayBase<S, D>;
    fn next(&mut self) -> Option<Self::Item> {
        self.iterate();
        Some(self.state.clone())
    }
}

#[derive(new)]
pub struct NStep<TEO> {
    teo: TEO,
    n: usize,
}

impl<TEO, D> ModelSize<D> for NStep<TEO>
    where TEO: ModelSize<D>,
          D: Dimension
{
    fn model_size(&self) -> D::Pattern {
        self.teo.model_size()
    }
}

impl<TEO> TimeStep for NStep<TEO>
    where TEO: TimeStep
{
    type Time = TEO::Time;

    fn get_dt(&self) -> Self::Time {
        self.teo.get_dt() * into_scalar(self.n as f64)
    }

    fn set_dt(&mut self, dt: Self::Time) {
        self.teo.set_dt(dt / into_scalar(self.n as f64));
    }
}

impl<TEO, S, D> TimeEvolutionBase<S, D> for NStep<TEO>
    where TEO: TimeEvolutionBase<S, D>,
          S: DataMut,
          D: Dimension
{
    type Scalar = TEO::Scalar;
    type Time = TEO::Time;

    fn iterate<'a>(&self, x: &'a mut ArrayBase<S, D>) -> &'a mut ArrayBase<S, D> {
        for _ in 0..self.n {
            self.teo.iterate(x);
        }
        x
    }
}
<|endoftext|>


<commit_before>#[cfg(test)]
mod test;

use std::fmt;

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Type {
    Array,
    Bool,
    Int,
    Str,
    Void,
}

impl Type {
    pub fn as_string_with_article(&self) -> &str {
        // Returns the name of the type with the correct English indefinite article prepended.
        match *self {
            Type::Array => "an array",
            Type::Bool => "a boolean",
            Type::Int => "an int",
            Type::Str => "a string",
            Type::Void => "nothing",
        }
    }
}

impl fmt::Display for Type {
    fn fmt(&self, mut fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Type::Array => write!(fmt, "array"),
            Type::Bool => write!(fmt, "boolean"),
            Type::Int => write!(fmt, "int"),
            Type::Str => write!(fmt, "string"),
            Type::Void => write!(fmt, "void"),
        }
    }
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Value {
    Array(Vec<Value>),
    Bool(bool),
    Int(i64),
    Str(String),
}

impl Value {
    // Returns the value's type with the correct English indefinite article prepended.
    pub fn type_string_with_article(&self) -> &str {
        match *self {
            Value::Array(_) => "an array",
            Value::Bool(_) => "a boolean",
            Value::Int(_) => "an int",
            Value::Str(_) => "a string",
        }
    }

    // Checks whether the value is of a certain type.
    pub fn is_a(&self, t: &Type) -> bool {
        match (self, t) {
            (&Value::Array(_), &Type::Array) |
            (&Value::Bool(_), &Type::Bool) |
            (&Value::Int(_), &Type::Int) |
            (&Value::Str(_), &Type::Str) => true,
            _ => false
        }
    }
}

impl fmt::Display for Value {
    fn fmt(&self, mut fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Value::Array(ref vec) => {
                try!(write!(fmt, "["));

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

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

                write!(fmt, "]")
            }
            Value::Bool(b) => write!(fmt, "{}", b),
            Value::Int(i) => write!(fmt, "{}", i),
            Value::Str(ref s) => write!(fmt, "{}", s),
        }
    }
}

#[derive(Clone, Debug)]
pub enum BinOp {
    // Boolean
    And,
    Or,

    // Comparisons
    Equal,
    NotEqual,
    GreaterOrEqual,
    GreaterThan,
    LessOrEqual,
    LessThan,

    // Arithmetic
    Plus,
    Minus,
    Times,
    Divide,
    Modulus,
}

impl BinOp {
    // Gets the precedence of an operator.
    fn precedence(&self) -> Precedence {
        match *self {
            BinOp::And => Precedence::And,
            BinOp::Or => Precedence::Or,
            BinOp::Equal | BinOp::NotEqual => Precedence::Equality,
            BinOp::GreaterOrEqual | BinOp::GreaterThan | BinOp::LessOrEqual | BinOp::LessThan =>
                Precedence::Inequality,
            BinOp::Plus | BinOp::Minus => Precedence::Addition,
            BinOp::Times | BinOp::Divide | BinOp::Modulus => Precedence::Multiplication,
        }
    }
}

#[derive(PartialEq, Eq, PartialOrd, Ord)]
enum Precedence {
    // Ordered correctly for derivation to be sound; each variant has higher precedence than the previous
    Or,
    And,
    Equality,
    Inequality,
    Addition,
    Multiplication,
    Constant,
}

impl fmt::Display for BinOp {
    fn fmt(&self, mut fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            BinOp::And => write!(fmt, "&&"),
            BinOp::Or => write!(fmt, "||"),
            BinOp::Equal => write!(fmt, "=="),
            BinOp::NotEqual => write!(fmt, "!="),
            BinOp::GreaterOrEqual => write!(fmt, ">="),
            BinOp::GreaterThan => write!(fmt, ">"),
            BinOp::LessOrEqual => write!(fmt, "<="),
            BinOp::LessThan => write!(fmt, "<"),
            BinOp::Plus => write!(fmt, "+"),
            BinOp::Minus => write!(fmt, "-"),
            BinOp::Times => write!(fmt, "*"),
            BinOp::Divide => write!(fmt, "/"),
            BinOp::Modulus => write!(fmt, "%"),
        }
    }
}

#[derive(Clone, Debug)]
pub enum Expr {
    Array(Vec<Expr>),
    ArrayElement(String, Box<Expr>, Vec<Expr>),
    BinExp(Box<Expr>, BinOp, Box<Expr>),
    Call(String, Vec<Expr>),
    Not(Box<Expr>),
    Value(Value),
    Var(String),
}

impl Expr {
    // Returns the precedence level of the expression.
    fn precedence(&self) -> Precedence {
        match *self {
            Expr::BinExp(_, ref o, _) => o.precedence(),
            _ => Precedence::Constant,
        }
    }
}

impl fmt::Display for Expr {
    fn fmt(&self, mut fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Expr::Array(ref vec) => {
                try!(write!(fmt, "["));

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

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

                write!(fmt, "]")
            }
            Expr::ArrayElement(ref var, ref index, ref indexes) => {
                try!(write!(fmt, "{}[{}]", var, index));

                for i in indexes.iter() {
                    try!(write!(fmt, "[{}]", i));
                }

                Ok(())
            }
            Expr::BinExp(ref exp1, ref op, ref exp2) => {
                let op_precendence = op.precedence();

                // Wrap the left-hand side in parentheses if its precedence is lower than the operator
                if exp1.precedence() < op_precendence {
                    try!(write!(fmt, "({})", exp1));
                } else {
                    try!(write!(fmt, "{}", exp1));
                }

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

                // Wrap the left-hand side in parentheses if its precedence is not greater than the operator
                if exp2.precedence() <= op_precendence {
                    write!(fmt, "({})", exp2)
                } else {
                    write!(fmt, "{}", exp2)
                }
            }
            Expr::Call(ref func, ref args) => {
                try!(write!(fmt, "{}(", func));

                // Write the arguments, separated by commas
                for (i, arg) in args.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

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

                write!(fmt, ")")
            }
            Expr::Not(ref exp) => write!(fmt, "!{}", exp),
            Expr::Value(ref val) => write!(fmt, "{}", val),
            Expr::Var(ref var) => write!(fmt, "{}", var),
        }
    }
}

#[derive(Clone, Debug)]
pub enum Statement {
    ArrayElemAssign(String, Expr, Vec<Expr>, Expr),
    VarAssign(String, Expr),
    Defun(Type, String, Vec<String>, Vec<Statement>),
    If(Expr, Vec<Statement>, Vec<Statement>),
    Let(String, Expr),
    Print(Expr),
    Return(Expr),
    VoidCall(String, Vec<Expr>),
    While(Expr, Vec<Statement>),
}

impl Statement {
    // Formats the expression with indentation before it.
    fn fmt_with_indent(&self, mut fmt: &mut fmt::Formatter, indent_level: u32) -> fmt::Result {
        // Creates a new string that is as many spaces as `indent level * 4`.
        let indentation : String = (0..indent_level * 4).map(|_| " ").collect();

        match *self {
            Statement::ArrayElemAssign(ref var, ref index, ref indexes, ref exp) => {
                try!(write!(fmt, "{}{}[{}]", indentation, var, index));

                for i in indexes.iter() {
                    try!(write!(fmt, "[{}]", i));
                }

                write!(fmt, " = {};", exp)
            }
            Statement::Defun(ref return_type, ref name, ref params, ref body) => {
                try!(write!(fmt, "{}{} {}(", indentation, return_type, name));

                // Write the parameters, separated by commas
                for (i, param) in params.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

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

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

                // Write the function body statements with one more level of indentation
                for stmt in body.iter() {
                    try!(stmt.fmt_with_indent(fmt, indent_level + 1));
                }

                writeln!(fmt, "{}}}", indentation)
            }
            Statement::If(ref clause, ref true_block, ref false_block) => {
                try!(writeln!(fmt, "{}if ({}) {{", indentation, clause));

                // Write the block statements with one more level of indentation
                for stmt in true_block.iter() {
                    try!(stmt.fmt_with_indent(fmt, indent_level + 1));
                }

                // Don't write the "else" clause/block unless there is something in the block.
                if false_block.is_empty() {
                    return Ok(());
                }

                try!(writeln!(fmt, "{}}} else {{", indentation));

                // Write the block statements with one more level of indentation
                for stmt in false_block.iter() {
                    try!(stmt.fmt_with_indent(fmt, indent_level + 1));
                }

                writeln!(fmt, "{}}}", indentation)
            }
            Statement::Let(ref var, ref exp) => writeln!(fmt, "{}let {} = {};", indentation, var, exp),
            Statement::Print(ref exp) => writeln!(fmt, "{}print {};", indentation, exp),
            Statement::Return(ref exp) => writeln!(fmt, "{}return {};", indentation, exp),
            Statement::VarAssign(ref var, ref exp) => writeln!(fmt, "{}{} = {};", indentation, var, exp),
            Statement::VoidCall(ref name, ref args) => {
                try!(write!(fmt, "{}{}(", indentation, name));

                // Write the arguments, separated by commas
                for (i, arg) in args.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

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

                write!(fmt, ");")
            }
            Statement::While(ref clause, ref block) => {
                try!(writeln!(fmt, "{}while ({}) {{", indentation, clause));

                // Write the block statements with one more level of indentation
                for stmt in block.iter() {
                    try!(stmt.fmt_with_indent(fmt, indent_level + 1));
                }

                writeln!(fmt, "{}}}", indentation)
            }
        }
    }
}

impl fmt::Display for Statement {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        self.fmt_with_indent(fmt, 0)
    }
}
<commit_msg>fix mistake<commit_after>#[cfg(test)]
mod test;

use std::fmt;

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Type {
    Array,
    Bool,
    Int,
    Str,
    Void,
}

impl Type {
    pub fn as_string_with_article(&self) -> &str {
        // Returns the name of the type with the correct English indefinite article prepended.
        match *self {
            Type::Array => "an array",
            Type::Bool => "a boolean",
            Type::Int => "an int",
            Type::Str => "a string",
            Type::Void => "nothing",
        }
    }
}

impl fmt::Display for Type {
    fn fmt(&self, mut fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Type::Array => write!(fmt, "array"),
            Type::Bool => write!(fmt, "boolean"),
            Type::Int => write!(fmt, "int"),
            Type::Str => write!(fmt, "string"),
            Type::Void => write!(fmt, "void"),
        }
    }
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Value {
    Array(Vec<Value>),
    Bool(bool),
    Int(i64),
    Str(String),
}

impl Value {
    // Returns the value's type with the correct English indefinite article prepended.
    pub fn type_string_with_article(&self) -> &str {
        match *self {
            Value::Array(_) => "an array",
            Value::Bool(_) => "a boolean",
            Value::Int(_) => "an int",
            Value::Str(_) => "a string",
        }
    }

    // Checks whether the value is of a certain type.
    pub fn is_a(&self, t: &Type) -> bool {
        match (self, t) {
            (&Value::Array(_), &Type::Array) |
            (&Value::Bool(_), &Type::Bool) |
            (&Value::Int(_), &Type::Int) |
            (&Value::Str(_), &Type::Str) => true,
            _ => false
        }
    }
}

impl fmt::Display for Value {
    fn fmt(&self, mut fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Value::Array(ref vec) => {
                try!(write!(fmt, "["));

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

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

                write!(fmt, "]")
            }
            Value::Bool(b) => write!(fmt, "{}", b),
            Value::Int(i) => write!(fmt, "{}", i),
            Value::Str(ref s) => write!(fmt, "{}", s),
        }
    }
}

#[derive(Clone, Debug)]
pub enum BinOp {
    // Boolean
    And,
    Or,

    // Comparisons
    Equal,
    NotEqual,
    GreaterOrEqual,
    GreaterThan,
    LessOrEqual,
    LessThan,

    // Arithmetic
    Plus,
    Minus,
    Times,
    Divide,
    Modulus,
}

impl BinOp {
    // Gets the precedence of an operator.
    fn precedence(&self) -> Precedence {
        match *self {
            BinOp::And => Precedence::And,
            BinOp::Or => Precedence::Or,
            BinOp::Equal | BinOp::NotEqual => Precedence::Equality,
            BinOp::GreaterOrEqual | BinOp::GreaterThan | BinOp::LessOrEqual | BinOp::LessThan =>
                Precedence::Inequality,
            BinOp::Plus | BinOp::Minus => Precedence::Addition,
            BinOp::Times | BinOp::Divide | BinOp::Modulus => Precedence::Multiplication,
        }
    }
}

#[derive(PartialEq, Eq, PartialOrd, Ord)]
enum Precedence {
    // Ordered correctly for derivation to be sound; each variant has higher precedence than the previous
    Or,
    And,
    Equality,
    Inequality,
    Addition,
    Multiplication,
    Constant,
}

impl fmt::Display for BinOp {
    fn fmt(&self, mut fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            BinOp::And => write!(fmt, "&&"),
            BinOp::Or => write!(fmt, "||"),
            BinOp::Equal => write!(fmt, "=="),
            BinOp::NotEqual => write!(fmt, "!="),
            BinOp::GreaterOrEqual => write!(fmt, ">="),
            BinOp::GreaterThan => write!(fmt, ">"),
            BinOp::LessOrEqual => write!(fmt, "<="),
            BinOp::LessThan => write!(fmt, "<"),
            BinOp::Plus => write!(fmt, "+"),
            BinOp::Minus => write!(fmt, "-"),
            BinOp::Times => write!(fmt, "*"),
            BinOp::Divide => write!(fmt, "/"),
            BinOp::Modulus => write!(fmt, "%"),
        }
    }
}

#[derive(Clone, Debug)]
pub enum Expr {
    Array(Vec<Expr>),
    ArrayElement(String, Box<Expr>, Vec<Expr>),
    BinExp(Box<Expr>, BinOp, Box<Expr>),
    Call(String, Vec<Expr>),
    Not(Box<Expr>),
    Value(Value),
    Var(String),
}

impl Expr {
    // Returns the precedence level of the expression.
    fn precedence(&self) -> Precedence {
        match *self {
            Expr::BinExp(_, ref o, _) => o.precedence(),
            _ => Precedence::Constant,
        }
    }
}

impl fmt::Display for Expr {
    fn fmt(&self, mut fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Expr::Array(ref vec) => {
                try!(write!(fmt, "["));

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

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

                write!(fmt, "]")
            }
            Expr::ArrayElement(ref var, ref index, ref indexes) => {
                try!(write!(fmt, "{}[{}]", var, index));

                for i in indexes.iter() {
                    try!(write!(fmt, "[{}]", i));
                }

                Ok(())
            }
            Expr::BinExp(ref exp1, ref op, ref exp2) => {
                let op_precendence = op.precedence();

                // Wrap the left-hand side in parentheses if its precedence is lower than the operator
                if exp1.precedence() < op_precendence {
                    try!(write!(fmt, "({})", exp1));
                } else {
                    try!(write!(fmt, "{}", exp1));
                }

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

                // Wrap the left-hand side in parentheses if its precedence is not greater than the operator
                if exp2.precedence() <= op_precendence {
                    write!(fmt, "({})", exp2)
                } else {
                    write!(fmt, "{}", exp2)
                }
            }
            Expr::Call(ref func, ref args) => {
                try!(write!(fmt, "{}(", func));

                // Write the arguments, separated by commas
                for (i, arg) in args.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

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

                write!(fmt, ")")
            }
            Expr::Not(ref exp) => write!(fmt, "!{}", exp),
            Expr::Value(ref val) => write!(fmt, "{}", val),
            Expr::Var(ref var) => write!(fmt, "{}", var),
        }
    }
}

#[derive(Clone, Debug)]
pub enum Statement {
    ArrayElemAssign(String, Expr, Vec<Expr>, Expr),
    VarAssign(String, Expr),
    Defun(Type, String, Vec<String>, Vec<Statement>),
    If(Expr, Vec<Statement>, Vec<Statement>),
    Let(String, Expr),
    Print(Expr),
    Return(Expr),
    VoidCall(String, Vec<Expr>),
    While(Expr, Vec<Statement>),
}

impl Statement {
    // Formats the expression with indentation before it.
    fn fmt_with_indent(&self, mut fmt: &mut fmt::Formatter, indent_level: u32) -> fmt::Result {
        // Creates a new string that is as many spaces as `indent level * 4`.
        let indentation : String = (0..indent_level * 4).map(|_| " ").collect();

        match *self {
            Statement::ArrayElemAssign(ref var, ref index, ref indexes, ref exp) => {
                try!(write!(fmt, "{}{}[{}]", indentation, var, index));

                for i in indexes.iter() {
                    try!(write!(fmt, "[{}]", i));
                }

                writeln!(fmt, " = {};", exp)
            }
            Statement::Defun(ref return_type, ref name, ref params, ref body) => {
                try!(write!(fmt, "{}{} {}(", indentation, return_type, name));

                // Write the parameters, separated by commas
                for (i, param) in params.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

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

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

                // Write the function body statements with one more level of indentation
                for stmt in body.iter() {
                    try!(stmt.fmt_with_indent(fmt, indent_level + 1));
                }

                writeln!(fmt, "{}}}", indentation)
            }
            Statement::If(ref clause, ref true_block, ref false_block) => {
                try!(writeln!(fmt, "{}if ({}) {{", indentation, clause));

                // Write the block statements with one more level of indentation
                for stmt in true_block.iter() {
                    try!(stmt.fmt_with_indent(fmt, indent_level + 1));
                }

                // Don't write the "else" clause/block unless there is something in the block.
                if false_block.is_empty() {
                    return Ok(());
                }

                try!(writeln!(fmt, "{}}} else {{", indentation));

                // Write the block statements with one more level of indentation
                for stmt in false_block.iter() {
                    try!(stmt.fmt_with_indent(fmt, indent_level + 1));
                }

                writeln!(fmt, "{}}}", indentation)
            }
            Statement::Let(ref var, ref exp) => writeln!(fmt, "{}let {} = {};", indentation, var, exp),
            Statement::Print(ref exp) => writeln!(fmt, "{}print {};", indentation, exp),
            Statement::Return(ref exp) => writeln!(fmt, "{}return {};", indentation, exp),
            Statement::VarAssign(ref var, ref exp) => writeln!(fmt, "{}{} = {};", indentation, var, exp),
            Statement::VoidCall(ref name, ref args) => {
                try!(write!(fmt, "{}{}(", indentation, name));

                // Write the arguments, separated by commas
                for (i, arg) in args.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

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

                write!(fmt, ");")
            }
            Statement::While(ref clause, ref block) => {
                try!(writeln!(fmt, "{}while ({}) {{", indentation, clause));

                // Write the block statements with one more level of indentation
                for stmt in block.iter() {
                    try!(stmt.fmt_with_indent(fmt, indent_level + 1));
                }

                writeln!(fmt, "{}}}", indentation)
            }
        }
    }
}

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


<commit_before>//!
//! Raw communication channel to the FUSE kernel driver.
//!

use std::io;
use std::ffi::{CString, CStr, OsStr, AsOsStr};
use std::os::unix::ffi::OsStrExt;
use std::path::{PathBuf, Path};
use libc::{c_char, c_int, c_void, size_t};
use fuse::{fuse_args, fuse_mount_compat25};

// Libc provides iovec based I/O using readv and writev functions
#[allow(dead_code, non_camel_case_types)]
mod libc {
    use libc::{c_char, c_int, c_void, size_t, ssize_t};

    /// Iovec data structure for readv and writev calls.
    #[repr(C)]
    pub struct iovec {
        pub iov_base: *const c_void,
        pub iov_len: size_t,
    }

    extern "system" {
        /// Read data from fd into multiple buffers
        pub fn readv (fd: c_int, iov: *mut iovec, iovcnt: c_int) -> ssize_t;
        /// Write data from multiple buffers to fd
        pub fn writev (fd: c_int, iov: *const iovec, iovcnt: c_int) -> ssize_t;

        pub fn realpath (file_name: *const c_char, resolved_name: *mut c_char) -> *const c_char;

        #[cfg(target_os = "macos")]
        pub fn unmount(dir: *const c_char, flags: c_int) -> c_int;
        #[cfg(not(target_os = "macos"))]
        pub fn umount(dir: *const c_char) -> c_int;
    }

    /// Max length for path names. 4096 should be reasonable safe (OS X uses 1024, Linux uses 4096)
    pub const PATH_MAX: usize = 4096;
}

/// Wrapper around libc's realpath.  Returns the errno value if the real path cannot be obtained.
/// FIXME: Use Rust's realpath method once available in std (see also https://github.com/mozilla/rust/issues/11857)
fn real_path (path: &CStr) -> io::Result<CString> {
    let mut resolved: Vec<c_char> = Vec::with_capacity(libc::PATH_MAX);
    unsafe {
        if libc::realpath(path.as_ptr(), resolved.as_mut_ptr()).is_null() {
            Err(io::Error::last_os_error())
        } else {
            // Using CStr::from_ptr gets the correct string length via strlen()
            let cresolved = CStr::from_ptr(resolved.as_ptr());
            Ok(CString::new(cresolved.to_bytes()).unwrap())
        }
    }
}

/// Helper function to provide options as a fuse_args struct
/// (which contains an argc count and an argv pointer)
fn with_fuse_args<T, F: FnOnce(&fuse_args) -> T> (options: &[&OsStr], f: F) -> T {
    let mut args: Vec<CString> = vec![CString::new("rust-fuse").unwrap()];
    args.extend(options.iter().map(|s| s.to_cstring().unwrap() ));
    let argptrs: Vec<*const i8> = args.iter().map(|s| s.as_ptr()).collect();
    f(&fuse_args { argc: argptrs.len() as i32, argv: argptrs.as_ptr(), allocated: 0 })
}

/// A raw communication channel to the FUSE kernel driver
pub struct Channel {
    mountpoint: PathBuf,
    fd: c_int,
}

impl Channel {
    /// Create a new communication channel to the kernel driver by mounting the
    /// given path. The kernel driver will delegate filesystem operations of
    /// the given path to the channel. If the channel is dropped, the path is
    /// unmounted.
    pub fn new (mountpoint: &Path, options: &[&OsStr]) -> io::Result<Channel> {
        let mnt = try!(mountpoint.as_os_str().to_cstring());
        real_path(&mnt).and_then(|mnt| {
            with_fuse_args(options, |args| {
                let fd = unsafe { fuse_mount_compat25(mnt.as_ptr(), args) };
                if fd < 0 {
                    Err(io::Error::last_os_error())
                } else {
                    let mountpoint = PathBuf::from(<OsStr as OsStrExt>::from_bytes(mnt.as_bytes()));
                    Ok(Channel { mountpoint: mountpoint, fd: fd })
                }
            })
        })
    }

    /// Return path of the mounted filesystem
    pub fn mountpoint (&self) -> &Path {
        &self.mountpoint
    }

    /// Receives data up to the capacity of the given buffer (can block).
    pub fn receive (&self, buffer: &mut Vec<u8>) -> io::Result<()> {
        let rc = unsafe { ::libc::read(self.fd, buffer.as_ptr() as *mut c_void, buffer.capacity() as size_t) };
        if rc < 0 {
            Err(io::Error::last_os_error())
        } else {
            unsafe { buffer.set_len(rc as usize); }
            Ok(())
        }
    }

    /// Returns a sender object for this channel. The sender object can be
    /// used to send to the channel. Multiple sender objects can be used
    /// and they can safely be sent to other threads.
    pub fn sender (&self) -> ChannelSender {
        // Since write/writev syscalls are threadsafe, we can simply create
        // a sender by using the same fd and use it in other threads. Only
        // the channel closes the fd when dropped. If any sender is used after
        // dropping the channel, it'll return an EBADF error.
        ChannelSender { fd: self.fd }
    }
}

impl Drop for Channel {
    fn drop (&mut self) {
        // TODO: send ioctl FUSEDEVIOCSETDAEMONDEAD on OS X before closing the fd
        // Close the communication channel to the kernel driver
        // (closing it before unnmount prevents sync unmount deadlock)
        unsafe { ::libc::close(self.fd); }
        // Unmount this channel's mount point
        let _ = unmount(&self.mountpoint);
    }
}

#[derive(Clone, Copy)]
pub struct ChannelSender {
    fd: c_int,
}

impl ChannelSender {
    /// Send all data in the slice of slice of bytes in a single write (can block).
    pub fn send (&self, buffer: &[&[u8]]) -> io::Result<()> {
        let iovecs: Vec<libc::iovec> = buffer.iter().map(|d| {
            libc::iovec { iov_base: d.as_ptr() as *const c_void, iov_len: d.len() as size_t }
        }).collect();
        let rc = unsafe { libc::writev(self.fd, iovecs.as_ptr(), iovecs.len() as c_int) };
        if rc < 0 {
            Err(io::Error::last_os_error())
        } else {
            Ok(())
        }
    }
}

/// Unmount an arbitrary mount point
pub fn unmount (mountpoint: &Path) -> io::Result<()> {
    // fuse_unmount_compat22 unfortunately doesn't return a status. Additionally,
    // it attempts to call realpath, which in turn calls into the filesystem. So
    // if the filesystem returns an error, the unmount does not take place, with
    // no indication of the error available to the caller. So we call unmount
    // directly, which is what osxfuse does anyway, since we already converted
    // to the real path when we first mounted.
    #[cfg(target_os = "macos")] #[inline]
    fn libc_umount (mnt: &CStr) -> c_int { unsafe { libc::unmount(mnt.as_ptr(), 0) } }
    #[cfg(not(target_os = "macos"))] #[inline]
    fn libc_umount (mnt: &CStr) -> c_int { unsafe { libc::umount(mnt.as_ptr()) } }

    let mnt = try!(mountpoint.as_os_str().to_cstring());
    let rc = libc_umount(&mnt);
    if rc < 0 {
        Err(io::Error::last_os_error())
    } else {
        Ok(())
    }
}

#[cfg(test)]
mod test {
    use super::with_fuse_args;
    use std::ffi::{CStr, OsStr};

    #[test]
    fn fuse_args () {
        with_fuse_args(&[OsStr::from_str("foo"), OsStr::from_str("bar")], |args| {
            assert_eq!(args.argc, 3);
            assert_eq!(unsafe { CStr::from_ptr(*args.argv.offset(0)).to_bytes() }, b"rust-fuse");
            assert_eq!(unsafe { CStr::from_ptr(*args.argv.offset(1)).to_bytes() }, b"foo");
            assert_eq!(unsafe { CStr::from_ptr(*args.argv.offset(2)).to_bytes() }, b"bar");
        });
    }
}
<commit_msg>convert OsStr::from_str() to OsStr::new()<commit_after>//!
//! Raw communication channel to the FUSE kernel driver.
//!

use std::io;
use std::ffi::{CString, CStr, OsStr, AsOsStr};
use std::os::unix::ffi::OsStrExt;
use std::path::{PathBuf, Path};
use libc::{c_char, c_int, c_void, size_t};
use fuse::{fuse_args, fuse_mount_compat25};

// Libc provides iovec based I/O using readv and writev functions
#[allow(dead_code, non_camel_case_types)]
mod libc {
    use libc::{c_char, c_int, c_void, size_t, ssize_t};

    /// Iovec data structure for readv and writev calls.
    #[repr(C)]
    pub struct iovec {
        pub iov_base: *const c_void,
        pub iov_len: size_t,
    }

    extern "system" {
        /// Read data from fd into multiple buffers
        pub fn readv (fd: c_int, iov: *mut iovec, iovcnt: c_int) -> ssize_t;
        /// Write data from multiple buffers to fd
        pub fn writev (fd: c_int, iov: *const iovec, iovcnt: c_int) -> ssize_t;

        pub fn realpath (file_name: *const c_char, resolved_name: *mut c_char) -> *const c_char;

        #[cfg(target_os = "macos")]
        pub fn unmount(dir: *const c_char, flags: c_int) -> c_int;
        #[cfg(not(target_os = "macos"))]
        pub fn umount(dir: *const c_char) -> c_int;
    }

    /// Max length for path names. 4096 should be reasonable safe (OS X uses 1024, Linux uses 4096)
    pub const PATH_MAX: usize = 4096;
}

/// Wrapper around libc's realpath.  Returns the errno value if the real path cannot be obtained.
/// FIXME: Use Rust's realpath method once available in std (see also https://github.com/mozilla/rust/issues/11857)
fn real_path (path: &CStr) -> io::Result<CString> {
    let mut resolved: Vec<c_char> = Vec::with_capacity(libc::PATH_MAX);
    unsafe {
        if libc::realpath(path.as_ptr(), resolved.as_mut_ptr()).is_null() {
            Err(io::Error::last_os_error())
        } else {
            // Using CStr::from_ptr gets the correct string length via strlen()
            let cresolved = CStr::from_ptr(resolved.as_ptr());
            Ok(CString::new(cresolved.to_bytes()).unwrap())
        }
    }
}

/// Helper function to provide options as a fuse_args struct
/// (which contains an argc count and an argv pointer)
fn with_fuse_args<T, F: FnOnce(&fuse_args) -> T> (options: &[&OsStr], f: F) -> T {
    let mut args: Vec<CString> = vec![CString::new("rust-fuse").unwrap()];
    args.extend(options.iter().map(|s| s.to_cstring().unwrap() ));
    let argptrs: Vec<*const i8> = args.iter().map(|s| s.as_ptr()).collect();
    f(&fuse_args { argc: argptrs.len() as i32, argv: argptrs.as_ptr(), allocated: 0 })
}

/// A raw communication channel to the FUSE kernel driver
pub struct Channel {
    mountpoint: PathBuf,
    fd: c_int,
}

impl Channel {
    /// Create a new communication channel to the kernel driver by mounting the
    /// given path. The kernel driver will delegate filesystem operations of
    /// the given path to the channel. If the channel is dropped, the path is
    /// unmounted.
    pub fn new (mountpoint: &Path, options: &[&OsStr]) -> io::Result<Channel> {
        let mnt = try!(mountpoint.as_os_str().to_cstring());
        real_path(&mnt).and_then(|mnt| {
            with_fuse_args(options, |args| {
                let fd = unsafe { fuse_mount_compat25(mnt.as_ptr(), args) };
                if fd < 0 {
                    Err(io::Error::last_os_error())
                } else {
                    let mountpoint = PathBuf::from(<OsStr as OsStrExt>::from_bytes(mnt.as_bytes()));
                    Ok(Channel { mountpoint: mountpoint, fd: fd })
                }
            })
        })
    }

    /// Return path of the mounted filesystem
    pub fn mountpoint (&self) -> &Path {
        &self.mountpoint
    }

    /// Receives data up to the capacity of the given buffer (can block).
    pub fn receive (&self, buffer: &mut Vec<u8>) -> io::Result<()> {
        let rc = unsafe { ::libc::read(self.fd, buffer.as_ptr() as *mut c_void, buffer.capacity() as size_t) };
        if rc < 0 {
            Err(io::Error::last_os_error())
        } else {
            unsafe { buffer.set_len(rc as usize); }
            Ok(())
        }
    }

    /// Returns a sender object for this channel. The sender object can be
    /// used to send to the channel. Multiple sender objects can be used
    /// and they can safely be sent to other threads.
    pub fn sender (&self) -> ChannelSender {
        // Since write/writev syscalls are threadsafe, we can simply create
        // a sender by using the same fd and use it in other threads. Only
        // the channel closes the fd when dropped. If any sender is used after
        // dropping the channel, it'll return an EBADF error.
        ChannelSender { fd: self.fd }
    }
}

impl Drop for Channel {
    fn drop (&mut self) {
        // TODO: send ioctl FUSEDEVIOCSETDAEMONDEAD on OS X before closing the fd
        // Close the communication channel to the kernel driver
        // (closing it before unnmount prevents sync unmount deadlock)
        unsafe { ::libc::close(self.fd); }
        // Unmount this channel's mount point
        let _ = unmount(&self.mountpoint);
    }
}

#[derive(Clone, Copy)]
pub struct ChannelSender {
    fd: c_int,
}

impl ChannelSender {
    /// Send all data in the slice of slice of bytes in a single write (can block).
    pub fn send (&self, buffer: &[&[u8]]) -> io::Result<()> {
        let iovecs: Vec<libc::iovec> = buffer.iter().map(|d| {
            libc::iovec { iov_base: d.as_ptr() as *const c_void, iov_len: d.len() as size_t }
        }).collect();
        let rc = unsafe { libc::writev(self.fd, iovecs.as_ptr(), iovecs.len() as c_int) };
        if rc < 0 {
            Err(io::Error::last_os_error())
        } else {
            Ok(())
        }
    }
}

/// Unmount an arbitrary mount point
pub fn unmount (mountpoint: &Path) -> io::Result<()> {
    // fuse_unmount_compat22 unfortunately doesn't return a status. Additionally,
    // it attempts to call realpath, which in turn calls into the filesystem. So
    // if the filesystem returns an error, the unmount does not take place, with
    // no indication of the error available to the caller. So we call unmount
    // directly, which is what osxfuse does anyway, since we already converted
    // to the real path when we first mounted.
    #[cfg(target_os = "macos")] #[inline]
    fn libc_umount (mnt: &CStr) -> c_int { unsafe { libc::unmount(mnt.as_ptr(), 0) } }
    #[cfg(not(target_os = "macos"))] #[inline]
    fn libc_umount (mnt: &CStr) -> c_int { unsafe { libc::umount(mnt.as_ptr()) } }

    let mnt = try!(mountpoint.as_os_str().to_cstring());
    let rc = libc_umount(&mnt);
    if rc < 0 {
        Err(io::Error::last_os_error())
    } else {
        Ok(())
    }
}

#[cfg(test)]
mod test {
    use super::with_fuse_args;
    use std::ffi::{CStr, OsStr};

    #[test]
    fn fuse_args () {
        with_fuse_args(&[OsStr::new("foo"), OsStr::new("bar")], |args| {
            assert_eq!(args.argc, 3);
            assert_eq!(unsafe { CStr::from_ptr(*args.argv.offset(0)).to_bytes() }, b"rust-fuse");
            assert_eq!(unsafe { CStr::from_ptr(*args.argv.offset(1)).to_bytes() }, b"foo");
            assert_eq!(unsafe { CStr::from_ptr(*args.argv.offset(2)).to_bytes() }, b"bar");
        });
    }
}
<|endoftext|>


<commit_before>extern crate semver;

use std::collections::HashMap;
use std::io::net::ip::IpAddr;
use std::hash::Hash;
use std::any::Any;
use std::fmt::Show;

#[deriving(PartialEq, Show, Clone)]
pub enum Scheme {
    Http,
    Https
}

#[deriving(PartialEq, Show, Clone)]
pub enum Host<'a> {
    HostName(&'a str),
    HostIp(IpAddr)
}

#[deriving(PartialEq, Hash, Eq, Show, Clone)]
pub enum Method {
    Get,
    Post,
    Put,
    Delete,
    Head,
    Connect,
    Options,
    Trace,

    // RFC-5789
    Patch,
    Purge,

    // WebDAV, Subversion, UPNP
    Other(&'static str)
}

/// A Dictionary for extensions provided by the server or middleware
pub type Extensions = HashMap<&'static str, Box<Any>>;

pub trait Request {
    /// The version of HTTP being used
    fn http_version(&self) -> semver::Version;

    /// The version of the conduit spec being used
    fn conduit_version(&self) -> semver::Version;

    /// The request method, such as GET, POST, PUT, DELETE or PATCH
    fn method(&self) -> Method;

    /// The scheme part of the request URL
    fn scheme(&self) -> Scheme;

    /// The host part of the requested URL
    fn host<'a>(&'a self) -> Host<'a>;

    /// The initial part of the request URL's path that corresponds
    /// to a virtual root. This allows an application to have a
    /// virtual location that consumes part of the path.
    fn virtual_root<'a>(&'a self) -> Option<&'a str>;

    /// The remainder of the path.
    fn path<'a>(&'a self) -> &'a str;

    /// The portion of the request URL that follows the "?"
    fn query_string<'a>(&'a self) -> Option<&'a str>;

    /// The remote IP address of the client or the last proxy that
    /// sent the request.
    fn remote_ip(&self) -> IpAddr;

    /// The byte-size of the body, if any
    fn content_length(&self) -> Option<uint>;

    /// The request's headers, as conduit::Headers.
    fn headers<'a>(&'a self) -> &'a Headers;

    /// A Reader for the body of the request
    fn body<'a>(&'a mut self) -> &'a mut Reader;

    /// A readable map of extensions
    fn extensions<'a>(&'a self) -> &'a Extensions;

    /// A mutable map of extensions
    fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions;
}

pub type HeaderEntries<'a> = Box<Iterator<(&'a str, Vec<&'a str>)>>;

pub trait Headers {
    /// Find the value of a given header. Multi-line headers are represented
    /// as an array.
    fn find<'a>(&'a self, key: &str) -> Option<Vec<&'a str>>;

    /// Returns true if a particular header exists
    fn has(&self, key: &str) -> bool;

    /// Iterate over all of the available headers.
    fn iter<'a>(&'a self) -> HeaderEntries<'a>;
}

pub struct Response {
    /// The status code as a tuple of the return code and status string
    pub status: (uint, &'static str),

    /// A Map of the headers
    pub headers: HashMap<String, Vec<String>>,

    /// A Writer for body of the response
    pub body: Box<Reader + Send>
}

/// A Handler takes a request and returns a response or an error.
/// By default, a bare function implements `Handler`.
pub trait Handler {
    fn call(&self, request: &mut Request) -> Result<Response, Box<Show>>;
}

impl<T: 'static + Show> Handler for fn(&mut Request) -> Result<Response, T> {
    fn call(&self, request: &mut Request) -> Result<Response, Box<Show>> {
        { (*self)(request) }.map_err(|e| box e as Box<Show>)
    }
}
<commit_msg>Don't try to be so clever<commit_after>extern crate semver;

use std::collections::HashMap;
use std::io::net::ip::IpAddr;
use std::hash::Hash;
use std::any::Any;
use std::fmt::Show;

#[deriving(PartialEq, Show, Clone)]
pub enum Scheme {
    Http,
    Https
}

#[deriving(PartialEq, Show, Clone)]
pub enum Host<'a> {
    HostName(&'a str),
    HostIp(IpAddr)
}

#[deriving(PartialEq, Hash, Eq, Show, Clone)]
pub enum Method {
    Get,
    Post,
    Put,
    Delete,
    Head,
    Connect,
    Options,
    Trace,

    // RFC-5789
    Patch,
    Purge,

    // WebDAV, Subversion, UPNP
    Other(&'static str)
}

/// A Dictionary for extensions provided by the server or middleware
pub type Extensions = HashMap<&'static str, Box<Any>>;

pub trait Request {
    /// The version of HTTP being used
    fn http_version(&self) -> semver::Version;

    /// The version of the conduit spec being used
    fn conduit_version(&self) -> semver::Version;

    /// The request method, such as GET, POST, PUT, DELETE or PATCH
    fn method(&self) -> Method;

    /// The scheme part of the request URL
    fn scheme(&self) -> Scheme;

    /// The host part of the requested URL
    fn host<'a>(&'a self) -> Host<'a>;

    /// The initial part of the request URL's path that corresponds
    /// to a virtual root. This allows an application to have a
    /// virtual location that consumes part of the path.
    fn virtual_root<'a>(&'a self) -> Option<&'a str>;

    /// The remainder of the path.
    fn path<'a>(&'a self) -> &'a str;

    /// The portion of the request URL that follows the "?"
    fn query_string<'a>(&'a self) -> Option<&'a str>;

    /// The remote IP address of the client or the last proxy that
    /// sent the request.
    fn remote_ip(&self) -> IpAddr;

    /// The byte-size of the body, if any
    fn content_length(&self) -> Option<uint>;

    /// The request's headers, as conduit::Headers.
    fn headers<'a>(&'a self) -> &'a Headers;

    /// A Reader for the body of the request
    fn body<'a>(&'a mut self) -> &'a mut Reader;

    /// A readable map of extensions
    fn extensions<'a>(&'a self) -> &'a Extensions;

    /// A mutable map of extensions
    fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions;
}

pub type HeaderEntries<'a> = Box<Iterator<(&'a str, Vec<&'a str>)>>;

pub trait Headers {
    /// Find the value of a given header. Multi-line headers are represented
    /// as an array.
    fn find<'a>(&'a self, key: &str) -> Option<Vec<&'a str>>;

    /// Returns true if a particular header exists
    fn has(&self, key: &str) -> bool;

    /// Iterate over all of the available headers.
    fn iter<'a>(&'a self) -> HeaderEntries<'a>;
}

pub struct Response {
    /// The status code as a tuple of the return code and status string
    pub status: (uint, &'static str),

    /// A Map of the headers
    pub headers: HashMap<String, Vec<String>>,

    /// A Writer for body of the response
    pub body: Box<Reader + Send>
}

/// A Handler takes a request and returns a response or an error.
/// By default, a bare function implements `Handler`.
pub trait Handler {
    fn call(&self, request: &mut Request) -> Result<Response, Box<Show>>;
}

impl Handler for fn(&mut Request) -> Result<Response, Box<Show>> {
    fn call(&self, request: &mut Request) -> Result<Response, Box<Show>> {
        { (*self)(request) }
    }
}
<|endoftext|>


<commit_before>use raw::*;
use std::mem;
use util::NativeRef;
use {CompiledFunction, Type, UncompiledFunction};
/// Holds all of the functions you have built and compiled. There can be
/// multiple, but normally there is only one.
pub struct Context {
    _context: jit_context_t
}
native_ref!(Context, _context, jit_context_t)

/// A context that is in the build phase while generating IR
#[allow(missing_copy_implementations)]
pub struct Builder {
    _context: jit_context_t
}
native_ref!(Builder, _context, jit_context_t)

impl Context {
    #[inline(always)]
    /// Create a new JIT Context
    pub fn new() -> Context {
        unsafe {
            NativeRef::from_ptr(jit_context_create())
        }
    }
    #[inline(always)]
    /// Lock the context so you can safely generate IR
    pub fn build<'a, R, F:FnOnce(&'a Builder) -> R>(&'a self, cb: F) -> R {
        unsafe {
            jit_context_build_start(self.as_ptr());
            let r = cb(mem::transmute(self));
            jit_context_build_end(self.as_ptr());
            r
        }
    }
    #[inline(always)]
    /// Lock the context so you can safely generate IR in a new function on the context which is
    /// compiled for you
    pub fn build_func<'a, F:FnOnce(&UncompiledFunction<'a>)>(&'a self, signature: Type, cb: F) -> CompiledFunction<'a> {
        unsafe {
            jit_context_build_start(self.as_ptr());
            let func = UncompiledFunction::new(mem::transmute(self), signature.clone());
            cb(mem::transmute(self));
            jit_context_build_end(self.as_ptr());
            func.compile()
        }
    }
}

#[unsafe_destructor]
impl Drop for Context {
    #[inline(always)]
    fn drop(&mut self) {
        unsafe {
            jit_context_destroy(self.as_ptr());
        }
    }
}<commit_msg>Implement `NoSync` & `NoSend` for `Builder`<commit_after>use raw::*;
use std::mem;
use std::kinds::marker::{NoSync, NoSend};
use util::NativeRef;
use {CompiledFunction, Type, UncompiledFunction};
/// Holds all of the functions you have built and compiled. There can be
/// multiple, but normally there is only one.
pub struct Context {
    _context: jit_context_t
}
native_ref!(Context, _context, jit_context_t)

/// A context that is in the build phase while generating IR
pub struct Builder {
    _context: jit_context_t,
    no_sync: NoSync,
    no_send: NoSend
}
impl NativeRef for Builder {
    #[inline(always)]
    unsafe fn as_ptr(&self) -> jit_context_t {
        self._context
    }
    #[inline(always)]
    unsafe fn from_ptr(ptr:jit_context_t) -> Builder {
        Builder {
            _context: ptr,
            no_sync: NoSync,
            no_send: NoSend
        }
    }
}

impl Context {
    #[inline(always)]
    /// Create a new JIT Context
    pub fn new() -> Context {
        unsafe {
            NativeRef::from_ptr(jit_context_create())
        }
    }
    #[inline(always)]
    /// Lock the context so you can safely generate IR
    pub fn build<'a, R, F:FnOnce(&'a Builder) -> R>(&'a self, cb: F) -> R {
        unsafe {
            jit_context_build_start(self.as_ptr());
            let r = cb(mem::transmute(self));
            jit_context_build_end(self.as_ptr());
            r
        }
    }
    #[inline(always)]
    /// Lock the context so you can safely generate IR in a new function on the context which is
    /// compiled for you
    pub fn build_func<'a, F:FnOnce(&UncompiledFunction<'a>)>(&'a self, signature: Type, cb: F) -> CompiledFunction<'a> {
        unsafe {
            jit_context_build_start(self.as_ptr());
            let func = UncompiledFunction::new(mem::transmute(self), signature.clone());
            cb(mem::transmute(self));
            jit_context_build_end(self.as_ptr());
            func.compile()
        }
    }
}
#[unsafe_destructor]
impl Drop for Context {
    #[inline(always)]
    fn drop(&mut self) {
        unsafe {
            jit_context_destroy(self.as_ptr());
        }
    }
}<|endoftext|>