<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/.

extern crate cc3200_sys;

use collections::String;
use collections::Vec;

use core::convert::TryFrom;
use core::ptr;

use self::cc3200_sys::simplelink::*;

macro_rules! try_fs {
    ($e:expr) => ({
        let rc: i32 = unsafe { $e };
        if rc < 0 {
            return Err(SimpleLinkError::FileSystem(try!(FileSystemError::try_from(rc))));
        }
        rc
    })
}

pub trait Read {
    fn read(&mut self, buf: &mut[u8]) -> Result<usize, SimpleLinkError>;
    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize, SimpleLinkError>;
    fn read_to_string(&mut self, str: &mut String) -> Result<usize, SimpleLinkError>;
}

pub trait Write {
    fn write(&mut self, buf: &[u8]) -> Result<usize, SimpleLinkError>;
}

pub trait Seek {
    fn seek(&mut self, pos: u64) -> Result<u64, SimpleLinkError>;
}

pub struct File {
    offset: usize,
    file_handle: i32,
}

impl File {
    /// Returns a file's info structure from the file system
    pub fn get_info(file_name: &str) -> Result<SlFsFileInfo, SimpleLinkError> {
        let mut file_info = SlFsFileInfo {
            flags : 0,
            file_length : 0,
            allocated_length : 0,
            token : [0; 4]
        };
        try_fs!(sl_FsGetInfo(file_name.as_ptr(), 0, &mut file_info) as i32);
        Ok(file_info)
    }

    /// Removes a file fro the file system
    pub fn remove(file_name: &str) -> Result<(), SimpleLinkError> {
        try_fs!(sl_FsDel(file_name.as_ptr(), 0) as i32);
        Ok(())
    }

    /// Opens a file for reading
    pub fn open(file_name: &str) -> Result<File, SimpleLinkError> {
        File::open_with_mode(file_name, File::mode(false, false, false, 0))
    }

    /// Opens a file for writing; possibly creating it in the process
    pub fn create(file_name: &str, max_len: usize, failsafe: bool) -> Result<File, SimpleLinkError> {
        File::open_with_mode(file_name, File::mode(true, true, failsafe, max_len as u32))
    }

    // Returns the file-open mode
    fn mode(write: bool, create: bool, failsafe: bool, max_size: u32) -> u32 {
        unsafe { sl_FsMode(write, create, failsafe, max_size) }
    }

    // Open file with the specified mode
    fn open_with_mode(file_name: &str, mode: u32) -> Result<File, SimpleLinkError> {
        let mut file_handle = -1 as i32;
        try_fs!(sl_FsOpen(file_name.as_ptr(), mode, ptr::null(), &mut file_handle));
        Ok(File { offset: 0, file_handle: file_handle })
    }

    // Read at specific offset
    fn read_at(&self, buf: &mut[u8], offset: usize) -> Result<usize, SimpleLinkError> {
        Ok(try_fs!(sl_FsRead(self.file_handle,
                             offset as u32,
                             buf.as_mut_ptr(),
                             buf.len() as u32)) as usize)
    }

    // Write at specific offset
    fn write_at(&self, buf: &[u8], offset: usize) -> Result<usize, SimpleLinkError> {
        Ok(try_fs!(sl_FsWrite(self.file_handle,
                              offset as u32,
                              buf.as_ptr(),
                              buf.len() as u32)) as usize)
    }
}

impl Drop for File {
    fn drop(&mut self) {
        unsafe {
            sl_FsClose(self.file_handle, ptr::null(), ptr::null(), 0);
        }
    }
}

impl Read for File {
    fn read(&mut self, buf: &mut[u8]) -> Result<usize, SimpleLinkError> {
        let len = try!(self.read_at(buf, self.offset));
        self.offset += len;
        Ok(len)
    }

    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize, SimpleLinkError> {

        let incr_buffer_size = 64;

        let mut offset = self.offset;
        let mut len = 0; // number of valid bytes in buf

        loop {
            if len == buf.len() {
                let resize = buf.len() + incr_buffer_size;
                buf.resize(resize, 0);
            }

            let readlen = try!(self.read_at(&mut buf[len..], offset));

            len += readlen;
            offset += readlen;

            if len < buf.len() {
                break; // EOF
            }
        }

        buf.truncate(len);
        self.offset = offset;

        Ok(len)
    }

    fn read_to_string(&mut self, str: &mut String) -> Result<usize, SimpleLinkError> {
        let mut buf: Vec<u8> = Vec::new();
        let len = try!(self.read_to_end(&mut buf));

        match String::from_utf8(buf) {
            Ok(res) => {
                str.clear();
                str.push_str(&res);
            },
            Err(_) => {
                return Result::Err(SimpleLinkError::FileSystem(FileSystemError::NOT_SUPPORTED))
            },
        }

        Ok(len)
    }
}

impl Write for File {
    fn write(&mut self, buf: &[u8]) -> Result<usize, SimpleLinkError> {
        let len = try!(self.write_at(buf, self.offset));
        self.offset += len;
        Ok(len)
    }
}

impl Seek for File {
    fn seek(&mut self, pos: u64) -> Result<u64, SimpleLinkError> {
        self.offset = pos as usize;
        Ok(self.offset as u64)
    }
}
<commit_msg>io::File: Convert file-name strings from Rust to C<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/.

extern crate cc3200_sys;

use collections::String;
use collections::Vec;

use core::convert::TryFrom;
use core::ptr;

use self::cc3200_sys::simplelink::*;

macro_rules! try_fs {
    ($e:expr) => ({
        let rc: i32 = unsafe { $e };
        if rc < 0 {
            return Err(SimpleLinkError::FileSystem(try!(FileSystemError::try_from(rc))));
        }
        rc
    })
}

pub trait Read {
    fn read(&mut self, buf: &mut[u8]) -> Result<usize, SimpleLinkError>;
    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize, SimpleLinkError>;
    fn read_to_string(&mut self, str: &mut String) -> Result<usize, SimpleLinkError>;
}

pub trait Write {
    fn write(&mut self, buf: &[u8]) -> Result<usize, SimpleLinkError>;
}

pub trait Seek {
    fn seek(&mut self, pos: u64) -> Result<u64, SimpleLinkError>;
}

pub struct File {
    offset: usize,
    file_handle: i32,
}

impl File {
    /// Returns a file's info structure from the file system
    pub fn get_info(file_name: &str) -> Result<SlFsFileInfo, SimpleLinkError> {
        let mut file_info = SlFsFileInfo {
            flags : 0,
            file_length : 0,
            allocated_length : 0,
            token : [0; 4]
        };
        try_fs!(sl_FsGetInfo(File::to_cstr(file_name).as_ptr(), 0, &mut file_info) as i32);
        Ok(file_info)
    }

    /// Removes a file fro the file system
    pub fn remove(file_name: &str) -> Result<(), SimpleLinkError> {
        try_fs!(sl_FsDel(File::to_cstr(file_name).as_ptr(), 0) as i32);
        Ok(())
    }

    /// Opens a file for reading
    pub fn open(file_name: &str) -> Result<File, SimpleLinkError> {
        File::open_with_mode(file_name, File::mode(false, false, false, 0))
    }

    /// Opens a file for writing; possibly creating it in the process
    pub fn create(file_name: &str, max_len: usize, failsafe: bool) -> Result<File, SimpleLinkError> {
        File::open_with_mode(file_name, File::mode(true, true, failsafe, max_len as u32))
    }

    // Returns the file-open mode
    fn mode(write: bool, create: bool, failsafe: bool, max_size: u32) -> u32 {
        unsafe { sl_FsMode(write, create, failsafe, max_size) }
    }

    // Open file with the specified mode
    fn open_with_mode(file_name: &str, mode: u32) -> Result<File, SimpleLinkError> {

        let mut file_handle = -1 as i32;
        try_fs!(sl_FsOpen(File::to_cstr(file_name).as_ptr(), mode, ptr::null(), &mut file_handle));
        Ok(File { offset: 0, file_handle: file_handle })
    }

    // Read at specific offset
    fn read_at(&self, buf: &mut[u8], offset: usize) -> Result<usize, SimpleLinkError> {
        Ok(try_fs!(sl_FsRead(self.file_handle,
                             offset as u32,
                             buf.as_mut_ptr(),
                             buf.len() as u32)) as usize)
    }

    // Write at specific offset
    fn write_at(&self, buf: &[u8], offset: usize) -> Result<usize, SimpleLinkError> {
        Ok(try_fs!(sl_FsWrite(self.file_handle,
                              offset as u32,
                              buf.as_ptr(),
                              buf.len() as u32)) as usize)
    }

    fn to_cstr(rstr: &str) -> Vec<u8> {
        let mut cstr: Vec<u8> = Vec::with_capacity(1 + rstr.len());
        for c in rstr.chars() {
            cstr.push(c as u8);
        }
        cstr.push('\0' as u8);
        cstr
    }
}

impl Drop for File {
    fn drop(&mut self) {
        unsafe {
            sl_FsClose(self.file_handle, ptr::null(), ptr::null(), 0);
        }
    }
}

impl Read for File {
    fn read(&mut self, buf: &mut[u8]) -> Result<usize, SimpleLinkError> {
        let len = try!(self.read_at(buf, self.offset));
        self.offset += len;
        Ok(len)
    }

    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize, SimpleLinkError> {

        let incr_buffer_size = 64;

        let mut offset = self.offset;
        let mut len = 0; // number of valid bytes in buf

        loop {
            if len == buf.len() {
                let resize = buf.len() + incr_buffer_size;
                buf.resize(resize, 0);
            }

            let readlen = try!(self.read_at(&mut buf[len..], offset));

            len += readlen;
            offset += readlen;

            if len < buf.len() {
                break; // EOF
            }
        }

        buf.truncate(len);
        self.offset = offset;

        Ok(len)
    }

    fn read_to_string(&mut self, str: &mut String) -> Result<usize, SimpleLinkError> {
        let mut buf: Vec<u8> = Vec::new();
        let len = try!(self.read_to_end(&mut buf));

        match String::from_utf8(buf) {
            Ok(res) => {
                str.clear();
                str.push_str(&res);
            },
            Err(_) => {
                return Result::Err(SimpleLinkError::FileSystem(FileSystemError::NOT_SUPPORTED))
            },
        }

        Ok(len)
    }
}

impl Write for File {
    fn write(&mut self, buf: &[u8]) -> Result<usize, SimpleLinkError> {
        let len = try!(self.write_at(buf, self.offset));
        self.offset += len;
        Ok(len)
    }
}

impl Seek for File {
    fn seek(&mut self, pos: u64) -> Result<u64, SimpleLinkError> {
        self.offset = pos as usize;
        Ok(self.offset as u64)
    }
}
<|endoftext|>


<commit_before>use {Poll, EventSet, PollOpt, Token};

// Re-export the io::Result / Error types for convenience
pub use std::io::{Read, Write, Result, Error, ErrorKind};

/// A value that may be registered with an `EventLoop`
pub trait Evented {
    fn register(&self, poll: &Poll, token: Token, interest: EventSet, opts: PollOpt) -> Result<()>;

    fn reregister(&self, poll: &Poll, token: Token, interest: EventSet, opts: PollOpt) -> Result<()>;

    fn deregister(&self, poll: &Poll) -> Result<()>;
}

pub trait TryAccept {
    type Output;

    fn accept(&self) -> Result<Option<Self::Output>>;
}

// TODO: Delete this
/// A helper trait to provide the map_non_block function on Results.
pub trait MapNonBlock<T> {
    /// Maps a `Result<T>` to a `Result<Option<T>>` by converting
    /// operation-would-block errors into `Ok(None)`.
    fn map_non_block(self) -> Result<Option<T>>;
}

impl<T> MapNonBlock<T> for Result<T> {
    fn map_non_block(self) -> Result<Option<T>> {
        use std::io::ErrorKind::WouldBlock;

        match self {
            Ok(value) => Ok(Some(value)),
            Err(err) => {
                if let WouldBlock = err.kind() {
                    Ok(None)
                } else {
                    Err(err)
                }
            }
        }
    }
}

#[cfg(unix)]
const WOULDBLOCK: i32 = ::libc::EAGAIN;

#[cfg(windows)]
const WOULDBLOCK: i32 = ::winapi::winerror::WSAEWOULDBLOCK;

/// Returns a std `WouldBlock` error without allocating
pub fn would_block() -> ::std::io::Error {
    ::std::io::Error::from_raw_os_error(WOULDBLOCK)
}
<commit_msg>Fix Windows WOULDBLOCK constant<commit_after>use {Poll, EventSet, PollOpt, Token};

// Re-export the io::Result / Error types for convenience
pub use std::io::{Read, Write, Result, Error, ErrorKind};

/// A value that may be registered with an `EventLoop`
pub trait Evented {
    fn register(&self, poll: &Poll, token: Token, interest: EventSet, opts: PollOpt) -> Result<()>;

    fn reregister(&self, poll: &Poll, token: Token, interest: EventSet, opts: PollOpt) -> Result<()>;

    fn deregister(&self, poll: &Poll) -> Result<()>;
}

pub trait TryAccept {
    type Output;

    fn accept(&self) -> Result<Option<Self::Output>>;
}

// TODO: Delete this
/// A helper trait to provide the map_non_block function on Results.
pub trait MapNonBlock<T> {
    /// Maps a `Result<T>` to a `Result<Option<T>>` by converting
    /// operation-would-block errors into `Ok(None)`.
    fn map_non_block(self) -> Result<Option<T>>;
}

impl<T> MapNonBlock<T> for Result<T> {
    fn map_non_block(self) -> Result<Option<T>> {
        use std::io::ErrorKind::WouldBlock;

        match self {
            Ok(value) => Ok(Some(value)),
            Err(err) => {
                if let WouldBlock = err.kind() {
                    Ok(None)
                } else {
                    Err(err)
                }
            }
        }
    }
}

#[cfg(unix)]
const WOULDBLOCK: i32 = ::libc::EAGAIN;

#[cfg(windows)]
const WOULDBLOCK: i32 = ::winapi::winerror::WSAEWOULDBLOCK as i32;

/// Returns a std `WouldBlock` error without allocating
pub fn would_block() -> ::std::io::Error {
    ::std::io::Error::from_raw_os_error(WOULDBLOCK)
}
<|endoftext|>


<commit_before>#[derive(Debug)]
pub struct Request(pub RequestId, pub Vec<u8>);

#[derive(Debug)]
pub enum AttrMacro {
    All,
    Fast,
    Full,
}

#[derive(Debug)]
pub enum Response<'a> {
    Capabilities(Vec<&'a str>),
    Done(RequestId, Status, Option<ResponseCode<'a>>, Option<&'a str>),
    Data(Status, Option<ResponseCode<'a>>, Option<&'a str>),
    Expunge(u32),
    Fetch(u32, Vec<AttributeValue<'a>>),
    MailboxData(MailboxDatum<'a>),
}

#[derive(Debug)]
pub enum Status {
    Ok,
    No,
    Bad,
    PreAuth,
    Bye,
}

#[derive(Debug)]
pub enum ResponseCode<'a> {
    HighestModSeq(u64), // RFC 4551, section 3.1.1
    PermanentFlags(Vec<&'a str>),
    ReadOnly,
    ReadWrite,
    TryCreate,
    UidNext(u32),
    UidValidity(u32),
}

#[derive(Debug)]
pub enum MailboxDatum<'a> {
    Exists(u32),
    Flags(Vec<&'a str>),
    List(Vec<&'a str>, &'a str, &'a str),
    Recent(u32),
}

#[derive(Debug)]
pub enum Attribute {
    Body,
    Envelope,
    Flags,
    InternalDate,
    ModSeq, // RFC 4551, section 3.3.2
    Rfc822,
    Rfc822Size,
    Uid,
}

#[derive(Debug)]
pub enum AttributeValue<'a> {
    Envelope(Envelope<'a>),
    Flags(Vec<&'a str>),
    InternalDate(&'a str),
    ModSeq(u64), // RFC 4551, section 3.3.2
    Rfc822(Option<&'a [u8]>),
    Rfc822Size(u32),
    Uid(u32),
}

#[derive(Debug)]
pub struct Envelope<'a> {
    pub date: Option<&'a str>,
    pub subject: Option<&'a str>,
    pub from: Option<Vec<Address<'a>>>,
    pub sender: Option<Vec<Address<'a>>>,
    pub reply_to: Option<Vec<Address<'a>>>,
    pub to: Option<Vec<Address<'a>>>,
    pub cc: Option<Vec<Address<'a>>>,
    pub bcc: Option<Vec<Address<'a>>>,
    pub in_reply_to: Option<&'a str>,
    pub message_id: Option<&'a str>,
}

#[derive(Debug)]
pub struct Address<'a> {
    pub name: Option<&'a str>,
    pub adl: Option<&'a str>,
    pub mailbox: Option<&'a str>,
    pub host: Option<&'a str>,
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct RequestId(pub String);

impl RequestId {
    pub fn as_bytes(&self) -> &[u8] {
        self.0.as_bytes()
    }
}

pub enum State {
    NotAuthenticated,
    Authenticated,
    Selected,
    Logout,
}
<commit_msg>Implement Eq and PartialEq for data types (fixes #3)<commit_after>#[derive(Debug, Eq, PartialEq)]
pub struct Request(pub RequestId, pub Vec<u8>);

#[derive(Debug, Eq, PartialEq)]
pub enum AttrMacro {
    All,
    Fast,
    Full,
}

#[derive(Debug, Eq, PartialEq)]
pub enum Response<'a> {
    Capabilities(Vec<&'a str>),
    Done(RequestId, Status, Option<ResponseCode<'a>>, Option<&'a str>),
    Data(Status, Option<ResponseCode<'a>>, Option<&'a str>),
    Expunge(u32),
    Fetch(u32, Vec<AttributeValue<'a>>),
    MailboxData(MailboxDatum<'a>),
}

#[derive(Debug, Eq, PartialEq)]
pub enum Status {
    Ok,
    No,
    Bad,
    PreAuth,
    Bye,
}

#[derive(Debug, Eq, PartialEq)]
pub enum ResponseCode<'a> {
    HighestModSeq(u64), // RFC 4551, section 3.1.1
    PermanentFlags(Vec<&'a str>),
    ReadOnly,
    ReadWrite,
    TryCreate,
    UidNext(u32),
    UidValidity(u32),
}

#[derive(Debug, Eq, PartialEq)]
pub enum MailboxDatum<'a> {
    Exists(u32),
    Flags(Vec<&'a str>),
    List(Vec<&'a str>, &'a str, &'a str),
    Recent(u32),
}

#[derive(Debug, Eq, PartialEq)]
pub enum Attribute {
    Body,
    Envelope,
    Flags,
    InternalDate,
    ModSeq, // RFC 4551, section 3.3.2
    Rfc822,
    Rfc822Size,
    Uid,
}

#[derive(Debug, Eq, PartialEq)]
pub enum AttributeValue<'a> {
    Envelope(Envelope<'a>),
    Flags(Vec<&'a str>),
    InternalDate(&'a str),
    ModSeq(u64), // RFC 4551, section 3.3.2
    Rfc822(Option<&'a [u8]>),
    Rfc822Size(u32),
    Uid(u32),
}

#[derive(Debug, Eq, PartialEq)]
pub struct Envelope<'a> {
    pub date: Option<&'a str>,
    pub subject: Option<&'a str>,
    pub from: Option<Vec<Address<'a>>>,
    pub sender: Option<Vec<Address<'a>>>,
    pub reply_to: Option<Vec<Address<'a>>>,
    pub to: Option<Vec<Address<'a>>>,
    pub cc: Option<Vec<Address<'a>>>,
    pub bcc: Option<Vec<Address<'a>>>,
    pub in_reply_to: Option<&'a str>,
    pub message_id: Option<&'a str>,
}

#[derive(Debug, Eq, PartialEq)]
pub struct Address<'a> {
    pub name: Option<&'a str>,
    pub adl: Option<&'a str>,
    pub mailbox: Option<&'a str>,
    pub host: Option<&'a str>,
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct RequestId(pub String);

impl RequestId {
    pub fn as_bytes(&self) -> &[u8] {
        self.0.as_bytes()
    }
}

#[derive(Debug, Eq, PartialEq)]
pub enum State {
    NotAuthenticated,
    Authenticated,
    Selected,
    Logout,
}
<|endoftext|>


<commit_before>extern crate rustbox;

use utils;

pub struct UIBuffer {
    cells: Vec<Vec<Cell>>
}

impl UIBuffer {
    pub fn new() -> UIBuffer {
        let cells = Cell::create_grid(' ');

        UIBuffer {
            cells: cells,
        }
    }

    pub fn draw_range(&self, start: uint, stop: uint) {
        let rows = self.cells.slice(start, stop);
        for row in rows.iter() {
            for cell in row.iter() {
                rustbox::print(cell.x, cell.y, rustbox::Normal, cell.fg, cell.bg, String::from_char(1, cell.ch));
            }
        }
    }

    /// Recreated the entire grid, will cells containing `ch`.
    pub fn fill(&mut self, ch: char) {
        self.cells = Cell::create_grid(ch);
    }

    /// Update the `ch` attribute of an individual cell
    pub fn update_cell_content(&mut self, x: uint, y: uint, ch: char) {
        self.cells[y][x].ch = ch
    }

    /// Update the `ch`, `fg`, and `bg` attributes of an indivudual cell
    pub fn update_cell(&mut self, x: uint, y: uint, ch: char, fg: rustbox::Color, bg: rustbox::Color) {
        let cell = &mut self.cells[y][x];
        cell.ch = ch;
        cell.fg = fg;
        cell.bg = bg;
    }
}

pub struct Cell {
    pub bg: rustbox::Color,
    pub fg: rustbox::Color,
    pub ch: char,
    pub x: uint,
    pub y: uint,
}

impl Cell {
    pub fn new() -> Cell {
        Cell {
            bg: rustbox::Color::Default,
            fg: rustbox::Color::White,
            ch: ' ',
            x: 0,
            y: 0,
        }
    }

    pub fn create_grid(ch: char) -> Vec<Vec<Cell>> {
        let term_height = utils::get_term_height();
        let term_width = utils::get_term_width();

        let mut rows = Vec::new();
        for voffset in range(0, term_height) {
            let mut cells = Vec::new();
            for boffset in range(0, term_width) {
                let mut cell = Cell::new();
                cell.x = boffset;
                cell.y = voffset;
                cell.ch = ch;
                cells.push(cell);
            }
            rows.push(cells);
        }

        return rows
    }
}

<commit_msg>Use print_char instead of print<commit_after>extern crate rustbox;

use utils;

pub struct UIBuffer {
    cells: Vec<Vec<Cell>>
}

impl UIBuffer {
    pub fn new() -> UIBuffer {
        let cells = Cell::create_grid(' ');

        UIBuffer {
            cells: cells,
        }
    }

    pub fn draw_range(&self, start: uint, stop: uint) {
        let rows = self.cells.slice(start, stop);
        for row in rows.iter() {
            for cell in row.iter() {
                rustbox::print_char(cell.x, cell.y, rustbox::Normal, cell.fg, cell.bg, cell.ch);
            }
        }
    }

    /// Recreated the entire grid, will cells containing `ch`.
    pub fn fill(&mut self, ch: char) {
        self.cells = Cell::create_grid(ch);
    }

    /// Update the `ch` attribute of an individual cell
    pub fn update_cell_content(&mut self, x: uint, y: uint, ch: char) {
        self.cells[y][x].ch = ch
    }

    /// Update the `ch`, `fg`, and `bg` attributes of an indivudual cell
    pub fn update_cell(&mut self, x: uint, y: uint, ch: char, fg: rustbox::Color, bg: rustbox::Color) {
        let cell = &mut self.cells[y][x];
        cell.ch = ch;
        cell.fg = fg;
        cell.bg = bg;
    }
}

pub struct Cell {
    pub bg: rustbox::Color,
    pub fg: rustbox::Color,
    pub ch: char,
    pub x: uint,
    pub y: uint,
}

impl Cell {
    pub fn new() -> Cell {
        Cell {
            bg: rustbox::Color::Default,
            fg: rustbox::Color::White,
            ch: ' ',
            x: 0,
            y: 0,
        }
    }

    pub fn create_grid(ch: char) -> Vec<Vec<Cell>> {
        let term_height = utils::get_term_height();
        let term_width = utils::get_term_width();

        let mut rows = Vec::new();
        for voffset in range(0, term_height) {
            let mut cells = Vec::new();
            for boffset in range(0, term_width) {
                let mut cell = Cell::new();
                cell.x = boffset;
                cell.y = voffset;
                cell.ch = ch;
                cells.push(cell);
            }
            rows.push(cells);
        }

        return rows
    }
}

<|endoftext|>


<commit_before>// Copyright 2016 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

use std::io::Result;

pub trait SocketOpt {
    fn set_send_buffer_size(&self, _size: usize) -> Result<()>;
    fn send_buffer_size(&self) -> Result<usize>;
    fn set_recv_buffer_size(&self, _size: usize) -> Result<()>;
    fn recv_buffer_size(&self) -> Result<usize>;
}

#[cfg(unix)]
mod unix {
    use super::SocketOpt;

    use std::io::{Result, Error};
    use std::os::unix::io::AsRawFd;

    use mio::tcp::TcpStream;
    use nix::Error as NixError;
    use nix::sys::socket;
    use nix::sys::socket::sockopt;

    impl SocketOpt for TcpStream {
        fn set_send_buffer_size(&self, size: usize) -> Result<()> {
            socket::setsockopt(self.as_raw_fd(), sockopt::SndBuf, &size).map_err(from_nix_error)
        }

        fn send_buffer_size(&self) -> Result<usize> {
            socket::getsockopt(self.as_raw_fd(), sockopt::SndBuf).map_err(from_nix_error)
        }

        fn set_recv_buffer_size(&self, size: usize) -> Result<()> {
            socket::setsockopt(self.as_raw_fd(), sockopt::RcvBuf, &size).map_err(from_nix_error)
        }

        fn recv_buffer_size(&self) -> Result<usize> {
            socket::getsockopt(self.as_raw_fd(), sockopt::RcvBuf).map_err(from_nix_error)
        }
    }

    fn from_nix_error(err: NixError) -> Error {
        Error::from_raw_os_error(err.errno() as i32)
    }
}

#[cfg(windows)]
mod windows {
    use mio::tcp::TcpStream;
    use std::io::Result;

    impl SocketOpt for TcpStream {
        fn set_send_buffer_size(&self, _size: usize) -> Result<()> {
            error!("set_send_buffer_size is not supported in windows now");
            Ok(())
        }

        fn send_buffer_size(&self) -> Result<usize> {
            error!("send_buffer_size is not supported in windows now");
            Ok(0)
        }

        fn set_recv_buffer_size(&self, _size: usize) -> Result<()> {
            error!("set_recv_buffer_size is not supported in windows now");
            Ok(())
        }

        fn recv_buffer_size(&self) -> Result<usize> {
            error!("recv_buffer_size is not supported in windows now");
            Ok(0)
        }
    }
}

#[cfg(unix)]
pub use self::unix::*;

#[cfg(windows)]
pub use self::windows::*;

#[cfg(test)]
mod tests {
    use mio::tcp::{TcpListener, TcpStream};

    use super::SocketOpt;

    #[cfg(unix)]
    #[test]
    fn test_sock_opt() {
        let addr = "127.0.0.1:0".parse().unwrap();

        let server = TcpListener::bind(&addr).unwrap();
        let addr = &format!("{}", server.local_addr().unwrap());

        let sock = TcpStream::connect(&addr.parse().unwrap()).unwrap();

        // For linux, getsockopt will return doubled value set by setsockopt.
        // But for Mac OS X, getsockopt may return the same value. So we can only
        // check value changed.
        sock.set_send_buffer_size(4096).unwrap();
        let s1 = sock.send_buffer_size().unwrap();
        sock.set_send_buffer_size(8192).unwrap();
        let s2 = sock.send_buffer_size().unwrap();
        assert!(s2 != s1, format!("{} should not equal {}", s2, s1));

        sock.set_recv_buffer_size(4096).unwrap();
        let r1 = sock.recv_buffer_size().unwrap();
        sock.set_recv_buffer_size(8192).unwrap();
        let r2 = sock.recv_buffer_size().unwrap();
        assert!(r2 != r1, format!("{} should not equal {}", r2, r1));
    }
}
<commit_msg>util: impl SocketOpt for AsRawFd (#869)<commit_after>// Copyright 2016 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

use std::io::Result;

pub trait SocketOpt {
    fn set_send_buffer_size(&self, _size: usize) -> Result<()>;
    fn send_buffer_size(&self) -> Result<usize>;
    fn set_recv_buffer_size(&self, _size: usize) -> Result<()>;
    fn recv_buffer_size(&self) -> Result<usize>;
}

#[cfg(unix)]
mod unix {
    use super::SocketOpt;

    use std::io::{Result, Error};
    use std::os::unix::io::AsRawFd;

    use nix::Error as NixError;
    use nix::sys::socket;
    use nix::sys::socket::sockopt;

    impl<T: AsRawFd> SocketOpt for T {
        fn set_send_buffer_size(&self, size: usize) -> Result<()> {
            socket::setsockopt(self.as_raw_fd(), sockopt::SndBuf, &size).map_err(from_nix_error)
        }

        fn send_buffer_size(&self) -> Result<usize> {
            socket::getsockopt(self.as_raw_fd(), sockopt::SndBuf).map_err(from_nix_error)
        }

        fn set_recv_buffer_size(&self, size: usize) -> Result<()> {
            socket::setsockopt(self.as_raw_fd(), sockopt::RcvBuf, &size).map_err(from_nix_error)
        }

        fn recv_buffer_size(&self) -> Result<usize> {
            socket::getsockopt(self.as_raw_fd(), sockopt::RcvBuf).map_err(from_nix_error)
        }
    }

    fn from_nix_error(err: NixError) -> Error {
        Error::from_raw_os_error(err.errno() as i32)
    }
}

#[cfg(windows)]
mod windows {
    use mio::tcp::TcpStream;
    use std::io::Result;

    impl SocketOpt for TcpStream {
        fn set_send_buffer_size(&self, _size: usize) -> Result<()> {
            error!("set_send_buffer_size is not supported in windows now");
            Ok(())
        }

        fn send_buffer_size(&self) -> Result<usize> {
            error!("send_buffer_size is not supported in windows now");
            Ok(0)
        }

        fn set_recv_buffer_size(&self, _size: usize) -> Result<()> {
            error!("set_recv_buffer_size is not supported in windows now");
            Ok(())
        }

        fn recv_buffer_size(&self) -> Result<usize> {
            error!("recv_buffer_size is not supported in windows now");
            Ok(0)
        }
    }
}

#[cfg(unix)]
pub use self::unix::*;

#[cfg(windows)]
pub use self::windows::*;

#[cfg(test)]
mod tests {
    use std::os::unix::io::AsRawFd;
    use std::net::{SocketAddr, TcpListener as StdTcpListener, TcpStream as StdTcpStream};
    use mio::tcp::{TcpListener as MioTcpListener, TcpStream as MioTcpStream};

    use super::SocketOpt;

    #[cfg(unix)]
    fn test_sock_opt<T: AsRawFd>(socket: &T) {
        // For linux, getsockopt will return doubled value set by setsockopt.
        // But for Mac OS X, getsockopt may return the same value. So we can only
        // check value changed.
        socket.set_send_buffer_size(4096).unwrap();
        let mio_s1 = socket.send_buffer_size().unwrap();
        socket.set_send_buffer_size(8192).unwrap();
        let mio_s2 = socket.send_buffer_size().unwrap();
        assert!(mio_s2 != mio_s1,
                format!("{} should not equal {}", mio_s2, mio_s1));

        socket.set_recv_buffer_size(4096).unwrap();
        let mio_r1 = socket.recv_buffer_size().unwrap();
        socket.set_recv_buffer_size(8192).unwrap();
        let mio_r2 = socket.recv_buffer_size().unwrap();
        assert!(mio_r2 != mio_r1,
                format!("{} should not equal {}", mio_r2, mio_r1));
    }

    #[cfg(unix)]
    #[test]
    fn test_mio_sock_opt() {
        let addr = "127.0.0.1:0".parse().unwrap();
        let mio_server = MioTcpListener::bind(&addr).unwrap();
        let mio_addr = &format!("{}", mio_server.local_addr().unwrap());
        let mio_sock = MioTcpStream::connect(&mio_addr.parse().unwrap()).unwrap();

        test_sock_opt(&mio_sock);
    }

    #[cfg(unix)]
    #[test]
    fn test_std_sock_opt() {
        let std_server = StdTcpListener::bind("127.0.0.1:0").unwrap();
        let std_addr: SocketAddr =
            (&format!("{}", std_server.local_addr().unwrap())).parse().unwrap();
        let std_sock = StdTcpStream::connect(std_addr).unwrap();

        test_sock_opt(&std_sock);
    }
}
<|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/.

//! Physical Volumes

use std::fs::File;
use std::io;
use std::io::ErrorKind::Other;
use std::io::{BufRead, BufReader};
use std::path::PathBuf;

use devicemapper::Device;

use crate::parser::{status_from_textmap, Entry, LvmTextMap, TextMapOps};
use crate::{Error, Result};

pub fn dev_from_textmap(map: &LvmTextMap) -> Result<Device> {
    let entry = map
        .get("device")
        .ok_or_else(|| Error::Io(io::Error::new(Other, "device textmap parsing error")))?;

    let val = match entry {
        Entry::String(ref s) => s
            .parse::<i64>()
            .map_err(|_| Error::Io(io::Error::new(Other, "device textmap parsing error")))?,
        &Entry::Number(x) => x,
        _ => {
            return Err(Error::Io(io::Error::new(
                Other,
                "device textmap parsing error",
            )))
        }
    };

    Ok(Device::from(val as u64))
}

/// A Physical Volume that is part of a Volume Group.
#[derive(Debug, PartialEq)]
pub struct PV {
    /// Its UUID
    pub id: String,
    /// Device number for the block device the PV is on
    pub device: Device,
    /// Status
    pub status: Vec<String>,
    /// Flags
    pub flags: Vec<String>,
    /// The device's size, in sectors
    pub dev_size: u64,
    /// The offset in sectors of where the first extent starts
    pub pe_start: u64,
    /// The number of extents in the PV
    pub pe_count: u64,
}

impl PV {
    pub fn path(&self) -> Option<PathBuf> {
        let f = File::open("/proc/partitions")
            .ok()
            .expect("Could not open /proc/partitions");

        let reader = BufReader::new(f);

        for line in reader.lines().skip(2) {
            if let Ok(line) = line {
                let spl: Vec<_> = line.split_whitespace().collect();

                if spl[0].parse::<u32>().unwrap() == self.device.major
                    && spl[1].parse::<u32>().unwrap() == self.device.minor
                {
                    return Some(PathBuf::from(format!("/dev/{}", spl[3])));
                }
            }
        }
        None
    }
}

/// Construct a PV from an LvmTextMap.
pub fn from_textmap(map: &LvmTextMap) -> Result<PV> {
    let err = || Error::Io(io::Error::new(Other, "pv textmap parsing error"));

    let id = map.string_from_textmap("id").ok_or_else(err)?;
    let device = dev_from_textmap(map)?;
    let dev_size = map.i64_from_textmap("dev_size").ok_or_else(err)?;
    let pe_start = map.i64_from_textmap("pe_start").ok_or_else(err)?;
    let pe_count = map.i64_from_textmap("pe_count").ok_or_else(err)?;

    let status = status_from_textmap(map)?;

    let flags: Vec<_> = map
        .list_from_textmap("flags")
        .ok_or_else(err)?
        .iter()
        .filter_map(|item| match item {
            Entry::String(ref x) => Some(x.clone()),
            _ => None,
        })
        .collect();

    Ok(PV {
        id: id.to_string(),
        device,
        status,
        flags,
        dev_size: dev_size as u64,
        pe_start: pe_start as u64,
        pe_count: pe_count as u64,
    })
}

pub fn to_textmap(pv: &PV) -> LvmTextMap {
    let mut map = LvmTextMap::new();

    map.insert("id".to_string(), Entry::String(pv.id.clone()));
    let tmp: u64 = pv.device.into();
    map.insert("device".to_string(), Entry::Number(tmp as i64));

    map.insert(
        "status".to_string(),
        Entry::List(
            pv.status.iter().map(|x| Entry::String(x.clone())).collect(),
        ),
    );

    map.insert(
        "flags".to_string(),
        Entry::List(
            pv.flags.iter().map(|x| Entry::String(x.clone())).collect(),
        ),
    );

    map.insert("dev_size".to_string(), Entry::Number(pv.dev_size as i64));
    map.insert("pe_start".to_string(), Entry::Number(pv.pe_start as i64));
    map.insert("pe_count".to_string(), Entry::Number(pv.pe_count as i64));

    map
}
<commit_msg>Clippy: ok in ok().expect("") is redundant<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/.

//! Physical Volumes

use std::fs::File;
use std::io;
use std::io::ErrorKind::Other;
use std::io::{BufRead, BufReader};
use std::path::PathBuf;

use devicemapper::Device;

use crate::parser::{status_from_textmap, Entry, LvmTextMap, TextMapOps};
use crate::{Error, Result};

pub fn dev_from_textmap(map: &LvmTextMap) -> Result<Device> {
    let entry = map
        .get("device")
        .ok_or_else(|| Error::Io(io::Error::new(Other, "device textmap parsing error")))?;

    let val = match entry {
        Entry::String(ref s) => s
            .parse::<i64>()
            .map_err(|_| Error::Io(io::Error::new(Other, "device textmap parsing error")))?,
        &Entry::Number(x) => x,
        _ => {
            return Err(Error::Io(io::Error::new(
                Other,
                "device textmap parsing error",
            )))
        }
    };

    Ok(Device::from(val as u64))
}

/// A Physical Volume that is part of a Volume Group.
#[derive(Debug, PartialEq)]
pub struct PV {
    /// Its UUID
    pub id: String,
    /// Device number for the block device the PV is on
    pub device: Device,
    /// Status
    pub status: Vec<String>,
    /// Flags
    pub flags: Vec<String>,
    /// The device's size, in sectors
    pub dev_size: u64,
    /// The offset in sectors of where the first extent starts
    pub pe_start: u64,
    /// The number of extents in the PV
    pub pe_count: u64,
}

impl PV {
    pub fn path(&self) -> Option<PathBuf> {
        let f = File::open("/proc/partitions")
            .expect("Could not open /proc/partitions");

        let reader = BufReader::new(f);

        for line in reader.lines().skip(2) {
            if let Ok(line) = line {
                let spl: Vec<_> = line.split_whitespace().collect();

                if spl[0].parse::<u32>().unwrap() == self.device.major
                    && spl[1].parse::<u32>().unwrap() == self.device.minor
                {
                    return Some(PathBuf::from(format!("/dev/{}", spl[3])));
                }
            }
        }
        None
    }
}

/// Construct a PV from an LvmTextMap.
pub fn from_textmap(map: &LvmTextMap) -> Result<PV> {
    let err = || Error::Io(io::Error::new(Other, "pv textmap parsing error"));

    let id = map.string_from_textmap("id").ok_or_else(err)?;
    let device = dev_from_textmap(map)?;
    let dev_size = map.i64_from_textmap("dev_size").ok_or_else(err)?;
    let pe_start = map.i64_from_textmap("pe_start").ok_or_else(err)?;
    let pe_count = map.i64_from_textmap("pe_count").ok_or_else(err)?;

    let status = status_from_textmap(map)?;

    let flags: Vec<_> = map
        .list_from_textmap("flags")
        .ok_or_else(err)?
        .iter()
        .filter_map(|item| match item {
            Entry::String(ref x) => Some(x.clone()),
            _ => None,
        })
        .collect();

    Ok(PV {
        id: id.to_string(),
        device,
        status,
        flags,
        dev_size: dev_size as u64,
        pe_start: pe_start as u64,
        pe_count: pe_count as u64,
    })
}

pub fn to_textmap(pv: &PV) -> LvmTextMap {
    let mut map = LvmTextMap::new();

    map.insert("id".to_string(), Entry::String(pv.id.clone()));
    let tmp: u64 = pv.device.into();
    map.insert("device".to_string(), Entry::Number(tmp as i64));

    map.insert(
        "status".to_string(),
        Entry::List(
            pv.status.iter().map(|x| Entry::String(x.clone())).collect(),
        ),
    );

    map.insert(
        "flags".to_string(),
        Entry::List(
            pv.flags.iter().map(|x| Entry::String(x.clone())).collect(),
        ),
    );

    map.insert("dev_size".to_string(), Entry::Number(pv.dev_size as i64));
    map.insert("pe_start".to_string(), Entry::Number(pv.pe_start as i64));
    map.insert("pe_count".to_string(), Entry::Number(pv.pe_count as i64));

    map
}
<|endoftext|>


<commit_before>/*
 * VM model
 */

use hypervisor_framework::*;
use std::sync::{Arc, atomic};
use std::rc::Rc;
use std::mem;
use rlibc::*;
use util::bitmap::*;

extern "C" {
    fn valloc(size: usize) -> *mut ::std::os::raw::c_void;
}

/*
 * VM allocated memory region
 */
#[derive(Debug)]
pub struct memory_region
{
    pub data: hv_uvaddr_t,
    pub size: usize,
}

impl memory_region {

    pub fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> usize {
        if offset >= self.size {
            return 0;
        }

        let toread = if offset + buf.len() > self.size {
            self.size - offset
        } else {
            buf.len()
        };

        unsafe {
            memcpy(buf.as_mut_ptr(), (self.data as *const u8).offset(offset as isize), toread);
        }

        toread
    }

    pub fn write_bytes(&self, offset: usize, buf: &[u8]) -> usize {
        if offset >= self.size {
            return 0;
        }

        let towrite = if offset + buf.len() > self.size {
            self.size - offset
        } else {
            buf.len()
        };

        unsafe {
            memcpy((self.data as *mut u8).offset(offset as isize), buf.as_ptr(), towrite);
        }

        towrite
    }
}

#[derive(Debug)]
pub struct memory_mapping
{
    pub region: Arc<memory_region>,
    pub base: hv_gpaddr_t,
    pub flags: hv_memory_flags_t,
}

pub trait io_handler
{
    fn io_read(&self, addr: u16, size: u8) -> IoOperandType;
    fn io_write(&self, addr: u16, data: IoOperandType);
}

pub struct io_region
{
    base: u16,
    size: u8,
    ops: Rc<io_handler>,
}

/**
 * Interrupt controller trait
 */
pub trait interrupt_controller
{
    /**
     * Assert given IRQ line.
     * \param irq   IRQ line to assert
     */
    fn assert_irq(&self, irq: u8);

    /**
     * Notify interrupt controller that interrupt vector has been injected in guest
     * \param vec   Interrupt vector that was previously raise with raise_external_interrupt
     */
    fn ack(&self, vec: u8);
}

/*
 * VM state
 *
 * TODO: drop trait to clean up and call hv_vm_destroy
 * TODO: a better lookup for memory mappings
 */
struct vm {
    /* HV vcpu id */
    vcpu: hv_vcpuid_t,

    /* Interrupt state */
    pic: Option<Rc<interrupt_controller>>,
    pending_ext_ints: Bitmap,

    /* Mapped memory regions */
    memory: Vec<memory_mapping>,

    /* Registred PIO regions */
    io: Vec<io_region>,
}

/*
 * Unsafe heap pointer to global VM state
 *
 * HV framework internally creates a single global VM context for process context which means
 * that dynamic instanses of this struct don't really make sense.
 *
 * Use get_vm() to safely unwrap this pointer.
 *
 * TODO: We are single threaded now, but remeber to add proper sync in case of multiple threads
 */
static mut VM: Option<*mut vm> = Option::None;
static RUNNING: atomic::AtomicBool = atomic::ATOMIC_BOOL_INIT;

fn get_vm() -> &'static mut vm
{
    unsafe {
        mem::transmute(VM.unwrap())
    }
}

fn get_pic() -> Rc<interrupt_controller>
{
    get_vm().pic.clone().unwrap()
}

pub fn create()
{
    unsafe {
        let res = hv_vm_create(HV_VM_DEFAULT);
        assert!(res == HV_SUCCESS);

        let vm = vm {
                    vcpu: vcpu_create(),
                    pic: Option::None,
                    pending_ext_ints: Bitmap::new(256),
                    memory: Vec::new(),
                    io: Vec::new()
        };

        VM = Option::Some(mem::transmute(Box::new(vm)));
    }
}

pub fn register_interrupt_controller(pic: Rc<interrupt_controller>)
{
    get_vm().pic = Option::Some(pic);
}

pub fn assert_irq(vec: u8)
{
    get_pic().assert_irq(vec);
}

pub fn has_pending_interrupts() -> bool
{
    get_vm().pending_ext_ints.has_any_set()
}

pub fn raise_external_interrupt(vec: u8)
{
    get_vm().pending_ext_ints.set(vec as usize);
}

pub fn cancel_all_external_interrupts()
{
    get_vm().pending_ext_ints.clear_all();
}

pub fn next_external_interrupt() -> Option<u8>
{
    match get_vm().pending_ext_ints.bsf() {
        Some(vec) => {
            /* ACK interrupt */
            get_vm().pending_ext_ints.clear(vec);
            get_pic().ack(vec as u8);
            return Option::Some(vec as u8);
        }

        None => Option::None,
    }
}

pub fn interrupt_guest()
{
    unsafe {
        let mut vcpus: [hv_vcpuid_t; 1] = [vcpu(); 1];
        let res = hv_vcpu_interrupt(vcpus.as_mut_ptr(), 2);
        if res != 0 {
            panic!("hv_vcpu_interrupt failed with {:x}", res);
        }
    }
}

pub fn get_guest_exec_time() -> u64
{
    unsafe {
        let mut time: u64 = 0;
        let res = hv_vcpu_get_exec_time(vcpu(), &mut time as *mut u64);
        if res != 0 {
            panic!("hv_vcpu_get_exec_time failed with {:x}", res);
        }

        time
    }
}

fn alloc_pages(size: usize) -> hv_uvaddr_t
{
    unsafe {
        let va = valloc(size);
        assert!(!va.is_null());
        return va;
    }
}

pub fn vcpu() -> hv_vcpuid_t
{
    //VM.unwrap().vcpu
    get_vm().vcpu
}

pub fn alloc_memory_region(size: usize) -> Arc<memory_region>
{
    let va = alloc_pages(size);
    Arc::new(memory_region { size: size, data: va })
}

pub fn map_memory_region(base: hv_gpaddr_t, flags: hv_memory_flags_t, region: Arc<memory_region>)
{
    unsafe {
        let res = hv_vm_map(region.data, base, region.size, flags);
        assert!(res == HV_SUCCESS);
    }

    get_vm().memory.push(memory_mapping { region: region, base: base, flags: flags });
}

pub fn find_memory_mapping(addr: hv_gpaddr_t) -> Option<&'static memory_mapping>
{
    for i in &get_vm().memory {
        if addr >= i.base && addr < i.base + i.region.size as u64 {
            return Some(i);
        }
    }

    return None;
}

pub fn read_guest_memory(addr: hv_gpaddr_t, buf: &mut [u8]) -> usize
{
    let mapping = match find_memory_mapping(addr) {
        Some(mapping) => mapping,
        None => return 0,
    };

    assert!(addr >= mapping.base);
    mapping.region.read_bytes((addr - mapping.base) as usize, buf)
}

pub fn vcpu_create() -> hv_vcpuid_t
{
    unsafe {
        let mut vcpu: hv_vcpuid_t = 0;
        let res = hv_vcpu_create(&mut vcpu, HV_VCPU_DEFAULT);
        assert!(res == HV_SUCCESS);
        vcpu
    }
}

pub fn run() -> hv_return_t
{
    let res: hv_return_t;

    RUNNING.store(true, atomic::Ordering::Release);
    unsafe {
        res = hv_vcpu_run(vcpu())
    }
    RUNNING.store(false, atomic::Ordering::Release);

    return res;
}

pub fn is_running() -> bool
{
    RUNNING.load(atomic::Ordering::Acquire)
}

pub fn register_io_region(handler: Rc<io_handler>, base: u16, len: u8)
{
    // TODO: check if range intersects
    get_vm().io.push(io_region {
        ops: handler,
        base: base,
        size: len
    });
}

#[derive(Clone, Copy)]
pub enum IoOperandType {
    byte(u8),
    word(u16),
    dword(u32),
}

#[allow(dead_code)]
impl IoOperandType {
    pub fn unwrap_byte(&self) -> u8 {
        match self {
            &IoOperandType::byte(v) => v,
            _ => panic!(),
        }
    }

    pub fn unwrap_word(&self) -> u16 {
        match self {
            &IoOperandType::word(v) => v,
            _ => panic!(),
        }
    }

    pub fn unwrap_dword(&self) -> u32 {
        match self {
            &IoOperandType::dword(v) => v,
            _ => panic!(),
        }
    }

    pub fn make_unhandled(size: u8) -> IoOperandType {
        match size {
            1 => IoOperandType::byte(0xFF),
            2 => IoOperandType::word(0xFFFF),
            4 => IoOperandType::dword(0xFFFFFFFF),
            _ => panic!(),
        }
    }
}

pub fn handle_io_read(port: u16, size: u8) -> IoOperandType
{
    for i in &get_vm().io {
        if port == i.base {
            return i.ops.io_read(port, size);
        }
    }

    panic!("Unhandled IO read from port {:x}", port);
}

pub fn handle_io_write(port: u16, data: IoOperandType)
{
    for i in &get_vm().io {
        if port == i.base {
            i.ops.io_write(port, data);
            return;

        }
    }

    panic!("Unhandled IO write to port {:x}", port);
}
<commit_msg>vm: correct number of vcpus given to hv_vcpu_interrupt<commit_after>/*
 * VM model
 */

use hypervisor_framework::*;
use std::sync::{Arc, atomic};
use std::rc::Rc;
use std::mem;
use rlibc::*;
use util::bitmap::*;

extern "C" {
    fn valloc(size: usize) -> *mut ::std::os::raw::c_void;
}

/*
 * VM allocated memory region
 */
#[derive(Debug)]
pub struct memory_region
{
    pub data: hv_uvaddr_t,
    pub size: usize,
}

impl memory_region {

    pub fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> usize {
        if offset >= self.size {
            return 0;
        }

        let toread = if offset + buf.len() > self.size {
            self.size - offset
        } else {
            buf.len()
        };

        unsafe {
            memcpy(buf.as_mut_ptr(), (self.data as *const u8).offset(offset as isize), toread);
        }

        toread
    }

    pub fn write_bytes(&self, offset: usize, buf: &[u8]) -> usize {
        if offset >= self.size {
            return 0;
        }

        let towrite = if offset + buf.len() > self.size {
            self.size - offset
        } else {
            buf.len()
        };

        unsafe {
            memcpy((self.data as *mut u8).offset(offset as isize), buf.as_ptr(), towrite);
        }

        towrite
    }
}

#[derive(Debug)]
pub struct memory_mapping
{
    pub region: Arc<memory_region>,
    pub base: hv_gpaddr_t,
    pub flags: hv_memory_flags_t,
}

pub trait io_handler
{
    fn io_read(&self, addr: u16, size: u8) -> IoOperandType;
    fn io_write(&self, addr: u16, data: IoOperandType);
}

pub struct io_region
{
    base: u16,
    size: u8,
    ops: Rc<io_handler>,
}

/**
 * Interrupt controller trait
 */
pub trait interrupt_controller
{
    /**
     * Assert given IRQ line.
     * \param irq   IRQ line to assert
     */
    fn assert_irq(&self, irq: u8);

    /**
     * Notify interrupt controller that interrupt vector has been injected in guest
     * \param vec   Interrupt vector that was previously raise with raise_external_interrupt
     */
    fn ack(&self, vec: u8);
}

/*
 * VM state
 *
 * TODO: drop trait to clean up and call hv_vm_destroy
 * TODO: a better lookup for memory mappings
 */
struct vm {
    /* HV vcpu id */
    vcpu: hv_vcpuid_t,

    /* Interrupt state */
    pic: Option<Rc<interrupt_controller>>,
    pending_ext_ints: Bitmap,

    /* Mapped memory regions */
    memory: Vec<memory_mapping>,

    /* Registred PIO regions */
    io: Vec<io_region>,
}

/*
 * Unsafe heap pointer to global VM state
 *
 * HV framework internally creates a single global VM context for process context which means
 * that dynamic instanses of this struct don't really make sense.
 *
 * Use get_vm() to safely unwrap this pointer.
 *
 * TODO: We are single threaded now, but remeber to add proper sync in case of multiple threads
 */
static mut VM: Option<*mut vm> = Option::None;
static RUNNING: atomic::AtomicBool = atomic::ATOMIC_BOOL_INIT;

fn get_vm() -> &'static mut vm
{
    unsafe {
        mem::transmute(VM.unwrap())
    }
}

fn get_pic() -> Rc<interrupt_controller>
{
    get_vm().pic.clone().unwrap()
}

pub fn create()
{
    unsafe {
        let res = hv_vm_create(HV_VM_DEFAULT);
        assert!(res == HV_SUCCESS);

        let vm = vm {
                    vcpu: vcpu_create(),
                    pic: Option::None,
                    pending_ext_ints: Bitmap::new(256),
                    memory: Vec::new(),
                    io: Vec::new()
        };

        VM = Option::Some(mem::transmute(Box::new(vm)));
    }
}

pub fn register_interrupt_controller(pic: Rc<interrupt_controller>)
{
    get_vm().pic = Option::Some(pic);
}

pub fn assert_irq(vec: u8)
{
    get_pic().assert_irq(vec);
}

pub fn has_pending_interrupts() -> bool
{
    get_vm().pending_ext_ints.has_any_set()
}

pub fn raise_external_interrupt(vec: u8)
{
    get_vm().pending_ext_ints.set(vec as usize);
}

pub fn cancel_all_external_interrupts()
{
    get_vm().pending_ext_ints.clear_all();
}

pub fn next_external_interrupt() -> Option<u8>
{
    match get_vm().pending_ext_ints.bsf() {
        Some(vec) => {
            /* ACK interrupt */
            get_vm().pending_ext_ints.clear(vec);
            get_pic().ack(vec as u8);
            return Option::Some(vec as u8);
        }

        None => Option::None,
    }
}

pub fn interrupt_guest()
{
    unsafe {
        let mut vcpus: [hv_vcpuid_t; 1] = [vcpu(); 1];
        let res = hv_vcpu_interrupt(vcpus.as_mut_ptr(), vcpus.len() as u32);
        if res != 0 {
            panic!("hv_vcpu_interrupt failed with {:x}", res);
        }
    }
}

pub fn get_guest_exec_time() -> u64
{
    unsafe {
        let mut time: u64 = 0;
        let res = hv_vcpu_get_exec_time(vcpu(), &mut time as *mut u64);
        if res != 0 {
            panic!("hv_vcpu_get_exec_time failed with {:x}", res);
        }

        time
    }
}

fn alloc_pages(size: usize) -> hv_uvaddr_t
{
    unsafe {
        let va = valloc(size);
        assert!(!va.is_null());
        return va;
    }
}

pub fn vcpu() -> hv_vcpuid_t
{
    //VM.unwrap().vcpu
    get_vm().vcpu
}

pub fn alloc_memory_region(size: usize) -> Arc<memory_region>
{
    let va = alloc_pages(size);
    Arc::new(memory_region { size: size, data: va })
}

pub fn map_memory_region(base: hv_gpaddr_t, flags: hv_memory_flags_t, region: Arc<memory_region>)
{
    unsafe {
        let res = hv_vm_map(region.data, base, region.size, flags);
        assert!(res == HV_SUCCESS);
    }

    get_vm().memory.push(memory_mapping { region: region, base: base, flags: flags });
}

pub fn find_memory_mapping(addr: hv_gpaddr_t) -> Option<&'static memory_mapping>
{
    for i in &get_vm().memory {
        if addr >= i.base && addr < i.base + i.region.size as u64 {
            return Some(i);
        }
    }

    return None;
}

pub fn read_guest_memory(addr: hv_gpaddr_t, buf: &mut [u8]) -> usize
{
    let mapping = match find_memory_mapping(addr) {
        Some(mapping) => mapping,
        None => return 0,
    };

    assert!(addr >= mapping.base);
    mapping.region.read_bytes((addr - mapping.base) as usize, buf)
}

pub fn vcpu_create() -> hv_vcpuid_t
{
    unsafe {
        let mut vcpu: hv_vcpuid_t = 0;
        let res = hv_vcpu_create(&mut vcpu, HV_VCPU_DEFAULT);
        assert!(res == HV_SUCCESS);
        vcpu
    }
}

pub fn run() -> hv_return_t
{
    let res: hv_return_t;

    RUNNING.store(true, atomic::Ordering::Release);
    unsafe {
        res = hv_vcpu_run(vcpu())
    }
    RUNNING.store(false, atomic::Ordering::Release);

    return res;
}

pub fn is_running() -> bool
{
    RUNNING.load(atomic::Ordering::Acquire)
}

pub fn register_io_region(handler: Rc<io_handler>, base: u16, len: u8)
{
    // TODO: check if range intersects
    get_vm().io.push(io_region {
        ops: handler,
        base: base,
        size: len
    });
}

#[derive(Clone, Copy)]
pub enum IoOperandType {
    byte(u8),
    word(u16),
    dword(u32),
}

#[allow(dead_code)]
impl IoOperandType {
    pub fn unwrap_byte(&self) -> u8 {
        match self {
            &IoOperandType::byte(v) => v,
            _ => panic!(),
        }
    }

    pub fn unwrap_word(&self) -> u16 {
        match self {
            &IoOperandType::word(v) => v,
            _ => panic!(),
        }
    }

    pub fn unwrap_dword(&self) -> u32 {
        match self {
            &IoOperandType::dword(v) => v,
            _ => panic!(),
        }
    }

    pub fn make_unhandled(size: u8) -> IoOperandType {
        match size {
            1 => IoOperandType::byte(0xFF),
            2 => IoOperandType::word(0xFFFF),
            4 => IoOperandType::dword(0xFFFFFFFF),
            _ => panic!(),
        }
    }
}

pub fn handle_io_read(port: u16, size: u8) -> IoOperandType
{
    for i in &get_vm().io {
        if port == i.base {
            return i.ops.io_read(port, size);
        }
    }

    panic!("Unhandled IO read from port {:x}", port);
}

pub fn handle_io_write(port: u16, data: IoOperandType)
{
    for i in &get_vm().io {
        if port == i.base {
            i.ops.io_write(port, data);
            return;

        }
    }

    panic!("Unhandled IO write to port {:x}", port);
}
<|endoftext|>


<commit_before>use std::io;
use std::io::Read;
use command::Command;

type Cell = u8;

pub struct VM {
    cells: [Cell; 30_000],
    data_pointer: usize,
}

impl VM {
    pub fn new() -> VM {
        VM { cells: [0; 30_000], data_pointer: 0 }
    }

    pub fn output(&self) {
        print!("{}", self.cells[self.data_pointer] as char);
    }

    pub fn input(&self) {
        let mut buffer = [0; 1];
        let mut stdin = io::stdin();
        stdin.read_exact(&mut buffer).unwrap();
    }

    pub fn increment(&mut self) {
        self.cells[self.data_pointer] = self.cells[self.data_pointer] + 1;
    }

    pub fn decrement(&mut self) {
        self.cells[self.data_pointer] = self.cells[self.data_pointer] - 1;
    }

    pub fn right_shift(&mut self) {
        self.data_pointer = self.data_pointer + 1;
    }

    pub fn left_shift(&mut self) {
        self.data_pointer = self.data_pointer - 1;
    }

    pub fn apply(&mut self, command: &Command) {
        match command {
            &Command::Output => self.output(),
            &Command::Input => self.input(),
            &Command::Increment => self.increment(),
            &Command::Decrement => self.decrement(),
            &Command::RightShift => self.right_shift(),
            &Command::LeftShift => self.left_shift(),
        }
    }

    pub fn apply_many(&mut self, commands: &[Command]) {
        for command in commands {
            self.apply(&command)
        }
    }
}
<commit_msg>Correct implementation of vm.input<commit_after>use std::io;
use std::io::Read;
use command::Command;

type Cell = u8;

pub struct VM {
    cells: [Cell; 30_000],
    data_pointer: usize,
}

impl VM {
    pub fn new() -> VM {
        VM { cells: [0; 30_000], data_pointer: 0 }
    }

    pub fn output(&self) {
        print!("{}", self.cells[self.data_pointer] as char);
    }

    pub fn input(&mut self) {
        match io::stdin().bytes().next() {
            Some(res) => match res {
                Ok(value) => self.cells[self.data_pointer] = value,
                Err(error) => {},
            },
            None => {}
        }
    }

    pub fn increment(&mut self) {
        self.cells[self.data_pointer] = self.cells[self.data_pointer] + 1;
    }

    pub fn decrement(&mut self) {
        self.cells[self.data_pointer] = self.cells[self.data_pointer] - 1;
    }

    pub fn right_shift(&mut self) {
        self.data_pointer = self.data_pointer + 1;
    }

    pub fn left_shift(&mut self) {
        self.data_pointer = self.data_pointer - 1;
    }

    pub fn apply(&mut self, command: &Command) {
        match command {
            &Command::Output => self.output(),
            &Command::Input => self.input(),
            &Command::Increment => self.increment(),
            &Command::Decrement => self.decrement(),
            &Command::RightShift => self.right_shift(),
            &Command::LeftShift => self.left_shift(),
        }
    }

    pub fn apply_many(&mut self, commands: &[Command]) {
        for command in commands {
            self.apply(&command)
        }
    }
}
<|endoftext|>


<commit_before>use grammar::*;
use ast::*;
use std::collections::BTreeMap;
use std::rc::Rc;
use std::cell::RefCell;
use num::rational::BigRational;

#[derive(Clone, Eq, Debug, PartialEq)]
pub enum Value {
    Number(BigRational),
    CharString(String),
    Boolean(bool),
    Map(BTreeMap<Rc<Value>, Rc<Value>>),
    Closure(Box<Vec<String>>, Closure),
}

#[derive(Clone, Eq, Debug, PartialEq)]
pub enum Instruction {
    Push(Literal),
    Fetch(String),
    LocalAssign(String),
    Assign(String),
    Call(usize),
    Nop,
    // Set(String, Value),
}

pub type InstructionSequence = Vec<Instruction>;

#[derive(Clone, Eq, Debug, PartialEq)]
pub struct BindingMap {
    map: Rc<RefCell<BTreeMap<String, Value>>>,
    parent: Option<Box<BindingMap>>,
}

impl BindingMap {
    fn new(parent: Option<&BindingMap>) -> BindingMap {
        let parent = match parent {
            Some(map) => Some(Box::new(map.clone())),
            None => None,
        };
        BindingMap {
            map: Rc::new(RefCell::new(BTreeMap::new())),
            parent: parent,
        }
    }

    pub fn fetch(&self, binding_name: &String) -> Option<Value> {
        match self.map.borrow().get(binding_name) {
            Some(value) => Some(value.clone()),
            None => {
                match self.parent {
                    Some(ref parent) => parent.fetch(binding_name),
                    None => None,
                }
            },
        }
    }

    pub fn local_assign(&mut self, binding_name: &String, value: Value) {
        self.map.borrow_mut().insert(binding_name.to_owned(), value);
    }

    pub fn assign(&mut self, binding_name: &String, value: Value) {
        match self.has_binding(binding_name) {
            true => self.local_assign(binding_name, value),
            false => match self.parent {
                Some(ref mut parent) => parent.assign(binding_name, value),
                None => panic!("no such binding"),
            }
        }
    }

    pub fn has_binding(&self, binding_name: &String) -> bool {
        self.map.borrow().contains_key(binding_name)
    }
}

#[derive(Clone, Eq, Debug, PartialEq)]
pub struct Closure {
    instructions: Rc<InstructionSequence>,
    parent_bindings: BindingMap,
}

impl Closure {
    pub fn new(instructions: InstructionSequence, parent_bindings: &BindingMap) -> Closure {
        Closure {
            instructions: Rc::new(instructions),
            parent_bindings: parent_bindings.clone(),
        }
    }
}

#[derive(Clone, Eq, Debug, PartialEq)]
struct Frame {
    bindings: BindingMap,
    exception_handlers: Vec<()>,
}

impl Frame {
    pub fn new(bindings: BindingMap) -> Frame {
        Frame {
            bindings: bindings,
            exception_handlers: Vec::new(),
        }
    }
}

fn compile_statement<'a>(statement: &'a Statement) -> InstructionSequence {
    match statement {
        &Statement::Assign(local, ref binding_name, ref expression) => {
            let mut instructions = compile_expression(expression);
            let instruction = match local {
                true => Instruction::LocalAssign(binding_name.to_owned()),
                false => Instruction::Assign(binding_name.to_owned()),
            };
            instructions.push(instruction);
            instructions
        },
        &Statement::Call(ref binding_name, ref expressions) => {
            let mut instructions = expressions
                .iter()
                .flat_map(|exp| compile_expression(exp))
                .collect::<InstructionSequence>();
            instructions.push(Instruction::Fetch(binding_name.to_owned()));
            instructions.push(Instruction::Call(expressions.len()));
            instructions
        },
        // _ => panic!("not implemented"),
    }
}

fn compile_expression<'a>(expression: &'a Expression) -> InstructionSequence {
    match expression {
        &Expression::Literal(ref literal) => {
            vec![Instruction::Push(literal.to_owned())]
        },
        &Expression::Identifier(ref binding_name) => {
            vec![Instruction::Fetch(binding_name.to_owned())]
        }
        _ => panic!("not implemented"),
        // &Expression::Identifier(_) => { vec![] },
        // &Expression::BinOp(_, _, _) => { vec![] },
    }
}

fn compile<'a>(statements: &'a Vec<Statement>) -> InstructionSequence {
    let mut instructions = InstructionSequence::new();

    for statement in statements.iter() {
        instructions.extend(compile_statement(&statement).iter().cloned());
    }

    instructions
}

#[derive(Clone, Eq, Debug, PartialEq)]
pub struct Vm {
    instructions: Rc<InstructionSequence>,
    pc: usize,
    stack: Vec<Value>,
    frames: Vec<Frame>,
}

impl Vm {
    pub fn new(source: &str) -> Vm {
        let stmts = statements(source);
        let instructions = compile(&stmts.unwrap());
        let mut map = BindingMap::new(None);
        let mut frame = Frame::new(map);

        let mut vm = Vm {
            instructions: Rc::new(instructions),
            pc: 0,
            stack: Vec::new(),
            frames: vec![frame],
        };
        vm
    }

    pub fn run<'b>(&'b mut self) {
        loop {
            let insn_result = Vm::next_instruction(self);
            let instruction;

            match insn_result {
                Some(i) => instruction = i,
                None => break,
            }

            match instruction {
                Instruction::Push(ref value) => {
                    let top_bindings = &mut self.frames.last_mut().unwrap().bindings;
                    self.stack.push(Vm::literal_to_value(value, top_bindings))
                },
                Instruction::Assign(ref binding_name) => {
                    let value = self.stack.pop().unwrap();
                    self.frames.last_mut().unwrap().bindings.assign(binding_name, value)
                },
                Instruction::LocalAssign(ref binding_name) => {
                    let value = self.stack.pop().unwrap();
                    self.frames.last_mut().unwrap().bindings.local_assign(binding_name, value)
                },
                Instruction::Call(arg_size) => {
                    let (closure_args, closure) = match self.stack.pop() {
                        Some(Value::Closure(arg_names, closure)) => (arg_names, closure),
                        Some(x) => panic!("expected a closure, got {:?}", x),
                        None => panic!("expected a closure, got None"),
                    };
                    if arg_size != closure_args.len() {
                        panic!(
                            "wrong number of arguments, expected {:?}, got {:?}",
                            closure_args.len(),
                            arg_size
                        )
                    };
                    let mut map = BindingMap::new(Some(&closure.parent_bindings));
                    for arg_name in closure_args.iter().rev() {
                        map.local_assign(arg_name, self.stack.pop().unwrap());
                    }
                    self.frames.push(Frame::new(map));
                    self.instructions = closure.instructions.clone();
                    self.pc = 0;
                },
                Instruction::Fetch(ref binding_name) => {
                    let value = self.frames.last().unwrap().bindings.fetch(binding_name).unwrap();
                    self.stack.push(value);
                },
                _ => panic!("unknown instruction {:?}", instruction),
            };
        };
    }

    fn next_instruction(vm: &mut Vm) -> Option<Instruction> {
        let instruction = match vm.instructions.get(vm.pc) {
            Some(i) => Some(i.clone()),
            None => None,
        };

        vm.pc += 1;

        instruction
    }

    fn literal_to_value<'b>(literal: &'b Literal, top_bindings: &BindingMap) -> Value {
        match literal {
            &Literal::Number(ref num) => Value::Number(num.to_owned()),
            &Literal::CharString(ref str) => Value::CharString(str.to_string()),
            &Literal::Fn(ref args, ref statements) => {
                // Statements should be compiled ahead of time
                let closure = Closure::new(compile(&statements), top_bindings);
                Value::Closure(args.clone(), closure)
            },
            _ => panic!("not implemented"),
        }
    }
}

#[cfg(test)]
mod test_binding_map {
    use super::*;
    use std::collections::BTreeMap;
    use std::rc::Rc;
    use std::cell::RefCell;

    #[test]
    fn test_new() {
        assert_eq!(
            Rc::new(RefCell::new(BTreeMap::new())),
            BindingMap::new(None).map
        )
    }

    #[test]
    fn test_has_binding() {
        let mut map = BindingMap::new(None);
        assert_eq!(
            false,
            map.has_binding(&"toto".to_owned())
        )
    }

    #[test]
    fn test_local_assign() {
        let mut map = BindingMap::new(None);
        map.local_assign(&"toto".to_owned(), Value::CharString("value".to_owned()));
        assert!(map.has_binding(&"toto".to_owned()))
    }

    #[test]
    fn test_fetch() {
        let mut map = BindingMap::new(None);
        map.local_assign(&"toto".to_owned(), Value::CharString("value".to_owned()));
        assert_eq!(
            Some(Value::CharString("value".to_owned())),
            map.fetch(&"toto".to_owned())
        )
    }

    #[test]
    fn test_delegates_fetch() {
        let mut parent = BindingMap::new(None);
        parent.local_assign(&"toto".to_owned(), Value::CharString("value".to_owned()));
        let map = BindingMap::new(Some(&parent));

        assert_eq!(
            Some(Value::CharString("value".to_owned())),
            map.fetch(&"toto".to_owned())
        )
    }

    #[test]
    fn test_delegates_assign() {
        let mut parent = BindingMap::new(None);
        parent.local_assign(&"toto".to_owned(), Value::CharString("value".to_owned()));
        let mut map = BindingMap::new(Some(&parent));
        map.assign(&"toto".to_owned(), Value::CharString("new_value".to_owned()));

        assert_eq!(
            Some(Value::CharString("new_value".to_owned())),
            parent.fetch(&"toto".to_owned())
        )
    }
}

#[cfg(test)]
mod test_vm {
    use super::*;
    use ast::*;
    use std::rc::Rc;
    use grammar::test_helpers::*;

    #[test]
    fn test_new_populates_basic_instructions() {
        let vm = Vm::new("let a = 1\nlet b = \"\"\n");
        assert_eq!(
            Rc::new(vec![
                Instruction::Push(Literal::Number(build_ratio(1, 1))),
                Instruction::LocalAssign("a".to_owned()),
                Instruction::Push(Literal::CharString("".to_string())),
                Instruction::LocalAssign("b".to_owned()),
            ]),
            vm.instructions
        )
    }

    #[test]
    fn test_new_populates_function_instructions() {
        let vm = Vm::new("let b = def(x) do\nend\nb(1)");
        assert_eq!(
            Rc::new(vec![
                Instruction::Push(Literal::Fn(Box::new(vec!["x".to_owned()]), Box::new(vec![]))),
                Instruction::LocalAssign("b".to_owned()),
                Instruction::Push(Literal::Number(build_ratio(1, 1))),
                Instruction::Fetch("b".to_owned()),
                Instruction::Call(1),
            ]),
            vm.instructions
        )
    }

    #[test]
    fn test_run_simple() {
        let mut vm = Vm::new("let a = 1");
        vm.run();
        assert_eq!(
            Value::Number(build_ratio(1, 1)),
            vm.frames.last().unwrap().bindings.fetch(&"a".to_owned()).unwrap().to_owned()
        )
    }

    #[test]
    fn test_function_call() {
        let source =
        "let a = \"\"\
            let x = def() do
              a = 1
            end\
            x()";

        let mut vm = Vm::new(source);
        vm.run();
        assert_eq!(
        Value::Number(build_ratio(1, 1)),
        vm.frames.last().unwrap().bindings.fetch(&"a".to_owned()).unwrap().to_owned()
        )
    }

    #[test]
    fn test_function_call_with_args() {
        let source =
            "\
            let a = \"\"\
            let b = \"\"\
            let x = def(c, d) do
              a = c
              b = d
            end\
            x(1, 2)";

        let mut vm = Vm::new(source);
        vm.run();
        assert_eq!(
            Value::Number(build_ratio(1, 1)),
            vm.frames.last().unwrap().bindings.fetch(&"a".to_owned()).unwrap().to_owned()
        );
        assert_eq!(
            Value::Number(build_ratio(2, 1)),
            vm.frames.last().unwrap().bindings.fetch(&"b".to_owned()).unwrap().to_owned()
        )
    }

    #[test]
    #[should_panic(expected="expected a closure")]
    fn test_calling_non_function() {
        let source =
            "let x = \"\"\
            x()";

        let mut vm = Vm::new(source);
        vm.run();
    }

    #[test]
    #[should_panic(expected="wrong number of arguments")]
    fn test_function_with_wrong_arg_count() {
        let source =
            "let x = def(a, b) do
            end\
            x(1)";

        let mut vm = Vm::new(source);
        vm.run();
    }
}
<commit_msg>Basic Map instructions<commit_after>use grammar::*;
use ast::*;
use std::collections::BTreeMap;
use std::rc::Rc;
use std::cell::RefCell;
use num::rational::BigRational;

#[derive(Clone, Eq, Debug, PartialEq, PartialOrd, Ord)]
pub enum Value {
    Number(BigRational),
    CharString(String),
    Boolean(bool),
    Map(BTreeMap<Rc<Value>, Rc<Value>>),
    Closure(Box<Vec<String>>, Closure),
}

#[derive(Clone, Eq, Debug, PartialEq, PartialOrd, Ord)]
pub enum Instruction {
    Push(Literal),
    Fetch(String),
    LocalAssign(String),
    Assign(String),
    Call(usize),
    MakeMap(usize),
    Nop,
    // Set(String, Value),
}

pub type InstructionSequence = Vec<Instruction>;

#[derive(Clone, Eq, Debug, PartialEq, PartialOrd, Ord)]
pub struct BindingMap {
    map: Rc<RefCell<BTreeMap<String, Value>>>,
    parent: Option<Box<BindingMap>>,
}

impl BindingMap {
    fn new(parent: Option<&BindingMap>) -> BindingMap {
        let parent = match parent {
            Some(map) => Some(Box::new(map.clone())),
            None => None,
        };
        BindingMap {
            map: Rc::new(RefCell::new(BTreeMap::new())),
            parent: parent,
        }
    }

    pub fn fetch(&self, binding_name: &String) -> Option<Value> {
        match self.map.borrow().get(binding_name) {
            Some(value) => Some(value.clone()),
            None => {
                match self.parent {
                    Some(ref parent) => parent.fetch(binding_name),
                    None => None,
                }
            },
        }
    }

    pub fn local_assign(&mut self, binding_name: &String, value: Value) {
        self.map.borrow_mut().insert(binding_name.to_owned(), value);
    }

    pub fn assign(&mut self, binding_name: &String, value: Value) {
        match self.has_binding(binding_name) {
            true => self.local_assign(binding_name, value),
            false => match self.parent {
                Some(ref mut parent) => parent.assign(binding_name, value),
                None => panic!("no such binding"),
            }
        }
    }

    pub fn has_binding(&self, binding_name: &String) -> bool {
        self.map.borrow().contains_key(binding_name)
    }
}

#[derive(Clone, Eq, Debug, PartialEq, PartialOrd, Ord)]
pub struct Closure {
    instructions: Rc<InstructionSequence>,
    parent_bindings: BindingMap,
}

impl Closure {
    pub fn new(instructions: InstructionSequence, parent_bindings: &BindingMap) -> Closure {
        Closure {
            instructions: Rc::new(instructions),
            parent_bindings: parent_bindings.clone(),
        }
    }
}

#[derive(Clone, Eq, Debug, PartialEq)]
struct Frame {
    bindings: BindingMap,
    exception_handlers: Vec<()>,
}

impl Frame {
    pub fn new(bindings: BindingMap) -> Frame {
        Frame {
            bindings: bindings,
            exception_handlers: Vec::new(),
        }
    }
}

fn compile_statement<'a>(statement: &'a Statement) -> InstructionSequence {
    match statement {
        &Statement::Assign(local, ref binding_name, ref expression) => {
            let mut instructions = compile_expression(expression);
            let instruction = match local {
                true => Instruction::LocalAssign(binding_name.to_owned()),
                false => Instruction::Assign(binding_name.to_owned()),
            };
            instructions.push(instruction);
            instructions
        },
        &Statement::Call(ref binding_name, ref expressions) => {
            let mut instructions = expressions
                .iter()
                .flat_map(|exp| compile_expression(exp))
                .collect::<InstructionSequence>();
            instructions.push(Instruction::Fetch(binding_name.to_owned()));
            instructions.push(Instruction::Call(expressions.len()));
            instructions
        },
//         _ => panic!("not implemented"),
    }
}

fn compile_expression<'a>(expression: &'a Expression) -> InstructionSequence {
    match expression {
        &Expression::Literal(ref literal) => {
            match literal {
                &Literal::Map(ref pairs) => {
                    let mut map_instructions =
                        pairs
                            .iter()
                            .flat_map(|&(ref key, ref value)| {
                                let mut insns = compile_expression(key);
                                insns.extend(compile_expression(value).iter().cloned());
                                insns
                            })
                            .collect::<InstructionSequence>();

                    map_instructions.push(Instruction::MakeMap(pairs.len()));
                    map_instructions
                },
                _ => vec![Instruction::Push(literal.to_owned())],
            }
        },
        &Expression::Identifier(ref binding_name) => {
            vec![Instruction::Fetch(binding_name.to_owned())]
        }
        _ => panic!("not implemented"),
        // &Expression::Identifier(_) => { vec![] },
        // &Expression::BinOp(_, _, _) => { vec![] },
    }
}

fn compile<'a>(statements: &'a Vec<Statement>) -> InstructionSequence {
    let mut instructions = InstructionSequence::new();

    for statement in statements.iter() {
        instructions.extend(compile_statement(&statement).iter().cloned());
    }

    instructions
}

#[derive(Clone, Eq, Debug, PartialEq)]
pub struct Vm {
    instructions: Rc<InstructionSequence>,
    pc: usize,
    stack: Vec<Value>,
    frames: Vec<Frame>,
}

impl Vm {
    pub fn new(source: &str) -> Vm {
        let stmts = statements(source);
        let instructions = compile(&stmts.unwrap());
        let mut map = BindingMap::new(None);
        let mut frame = Frame::new(map);

        let mut vm = Vm {
            instructions: Rc::new(instructions),
            pc: 0,
            stack: Vec::new(),
            frames: vec![frame],
        };
        vm
    }

    pub fn run<'b>(&'b mut self) {
        loop {
            let insn_result = Vm::next_instruction(self);
            let instruction;

            match insn_result {
                Some(i) => instruction = i,
                None => break,
            }

            match instruction {
                Instruction::Push(ref value) => {
                    let top_bindings = &mut self.frames.last_mut().unwrap().bindings;
                    self.stack.push(Vm::literal_to_value(value, top_bindings))
                },
                Instruction::Assign(ref binding_name) => {
                    let value = self.stack.pop().unwrap();
                    self.frames.last_mut().unwrap().bindings.assign(binding_name, value)
                },
                Instruction::LocalAssign(ref binding_name) => {
                    let value = self.stack.pop().unwrap();
                    self.frames.last_mut().unwrap().bindings.local_assign(binding_name, value)
                },
                Instruction::Call(arg_size) => {
                    let (closure_args, closure) = match self.stack.pop() {
                        Some(Value::Closure(arg_names, closure)) => (arg_names, closure),
                        Some(x) => panic!("expected a closure, got {:?}", x),
                        None => panic!("expected a closure, got None"),
                    };
                    if arg_size != closure_args.len() {
                        panic!(
                            "wrong number of arguments, expected {:?}, got {:?}",
                            closure_args.len(),
                            arg_size
                        )
                    };
                    let mut map = BindingMap::new(Some(&closure.parent_bindings));
                    for arg_name in closure_args.iter().rev() {
                        map.local_assign(arg_name, self.stack.pop().unwrap());
                    }
                    self.frames.push(Frame::new(map));
                    self.instructions = closure.instructions.clone();
                    self.pc = 0;
                },
                Instruction::Fetch(ref binding_name) => {
                    let value = self.frames.last().unwrap().bindings.fetch(binding_name).unwrap();
                    self.stack.push(value);
                },
                _ => panic!("unknown instruction {:?}", instruction),
            };
        };
    }

    fn next_instruction(vm: &mut Vm) -> Option<Instruction> {
        let instruction = match vm.instructions.get(vm.pc) {
            Some(i) => Some(i.clone()),
            None => None,
        };

        vm.pc += 1;

        instruction
    }

    fn literal_to_value<'b>(literal: &'b Literal, top_bindings: &BindingMap) -> Value {
        match literal {
            &Literal::Number(ref num) => Value::Number(num.to_owned()),
            &Literal::CharString(ref str) => Value::CharString(str.to_string()),
            &Literal::Fn(ref args, ref statements) => {
                // Statements should be compiled ahead of time
                let closure = Closure::new(compile(&statements), top_bindings);
                Value::Closure(args.clone(), closure)
            },
            _ => panic!("not implemented"),
        }
    }
}

#[cfg(test)]
mod test_binding_map {
    use super::*;
    use std::collections::BTreeMap;
    use std::rc::Rc;
    use std::cell::RefCell;

    #[test]
    fn test_new() {
        assert_eq!(
            Rc::new(RefCell::new(BTreeMap::new())),
            BindingMap::new(None).map
        )
    }

    #[test]
    fn test_has_binding() {
        let mut map = BindingMap::new(None);
        assert_eq!(
            false,
            map.has_binding(&"toto".to_owned())
        )
    }

    #[test]
    fn test_local_assign() {
        let mut map = BindingMap::new(None);
        map.local_assign(&"toto".to_owned(), Value::CharString("value".to_owned()));
        assert!(map.has_binding(&"toto".to_owned()))
    }

    #[test]
    fn test_fetch() {
        let mut map = BindingMap::new(None);
        map.local_assign(&"toto".to_owned(), Value::CharString("value".to_owned()));
        assert_eq!(
            Some(Value::CharString("value".to_owned())),
            map.fetch(&"toto".to_owned())
        )
    }

    #[test]
    fn test_delegates_fetch() {
        let mut parent = BindingMap::new(None);
        parent.local_assign(&"toto".to_owned(), Value::CharString("value".to_owned()));
        let map = BindingMap::new(Some(&parent));

        assert_eq!(
            Some(Value::CharString("value".to_owned())),
            map.fetch(&"toto".to_owned())
        )
    }

    #[test]
    fn test_delegates_assign() {
        let mut parent = BindingMap::new(None);
        parent.local_assign(&"toto".to_owned(), Value::CharString("value".to_owned()));
        let mut map = BindingMap::new(Some(&parent));
        map.assign(&"toto".to_owned(), Value::CharString("new_value".to_owned()));

        assert_eq!(
            Some(Value::CharString("new_value".to_owned())),
            parent.fetch(&"toto".to_owned())
        )
    }
}

#[cfg(test)]
mod test_vm {
    use super::*;
    use ast::*;
    use std::rc::Rc;
    use grammar::test_helpers::*;

    #[test]
    fn test_new_populates_basic_instructions() {
        let vm = Vm::new("let a = 1\nlet b = \"\"\n");
        assert_eq!(
            Rc::new(vec![
                Instruction::Push(Literal::Number(build_ratio(1, 1))),
                Instruction::LocalAssign("a".to_owned()),
                Instruction::Push(Literal::CharString("".to_string())),
                Instruction::LocalAssign("b".to_owned()),
            ]),
            vm.instructions
        )
    }

    #[test]
    fn test_new_populates_function_instructions() {
        let source = "\
            let a = { 1 => 1 }
            let b = def(x) do\
            end\
            b(1)";
        let vm = Vm::new(source);
        assert_eq!(
            Rc::new(vec![
                Instruction::Push(Literal::Number(build_ratio(1, 1))),
                Instruction::Push(Literal::Number(build_ratio(1, 1))),
                Instruction::MakeMap(1),
                Instruction::LocalAssign("a".to_owned()),
                Instruction::Push(Literal::Fn(Box::new(vec!["x".to_owned()]), Box::new(vec![]))),
                Instruction::LocalAssign("b".to_owned()),
                Instruction::Push(Literal::Number(build_ratio(1, 1))),
                Instruction::Fetch("b".to_owned()),
                Instruction::Call(1),
            ]),
            vm.instructions
        )
    }

    #[test]
    fn test_run_simple() {
        let mut vm = Vm::new("let a = 1");
        vm.run();
        assert_eq!(
            Value::Number(build_ratio(1, 1)),
            vm.frames.last().unwrap().bindings.fetch(&"a".to_owned()).unwrap().to_owned()
        )
    }

    #[test]
    fn test_function_call() {
        let source =
        "let a = \"\"\
            let x = def() do
              a = 1
            end\
            x()";

        let mut vm = Vm::new(source);
        vm.run();
        assert_eq!(
        Value::Number(build_ratio(1, 1)),
        vm.frames.last().unwrap().bindings.fetch(&"a".to_owned()).unwrap().to_owned()
        )
    }

    #[test]
    fn test_function_call_with_args() {
        let source =
            "\
            let a = \"\"\
            let b = \"\"\
            let x = def(c, d) do
              a = c
              b = d
            end\
            x(1, 2)";

        let mut vm = Vm::new(source);
        vm.run();
        assert_eq!(
            Value::Number(build_ratio(1, 1)),
            vm.frames.last().unwrap().bindings.fetch(&"a".to_owned()).unwrap().to_owned()
        );
        assert_eq!(
            Value::Number(build_ratio(2, 1)),
            vm.frames.last().unwrap().bindings.fetch(&"b".to_owned()).unwrap().to_owned()
        )
    }

    #[test]
    #[should_panic(expected="expected a closure")]
    fn test_calling_non_function() {
        let source =
            "let x = \"\"\
            x()";

        let mut vm = Vm::new(source);
        vm.run();
    }

    #[test]
    #[should_panic(expected="wrong number of arguments")]
    fn test_function_with_wrong_arg_count() {
        let source =
            "let x = def(a, b) do
            end\
            x(1)";

        let mut vm = Vm::new(source);
        vm.run();
    }
}
<|endoftext|>