<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 command_line::command_line_init;
use interfaces::cef_app_t;
use types::{cef_main_args_t, cef_settings_t};

use libc::{c_char, c_int, c_void};
use util::opts;
use std::borrow::ToOwned;
use std::ffi;
use std::str;
use browser;
use std_url::Url;

const MAX_RENDERING_THREADS: usize = 128;

// TODO(pcwalton): Get the home page via the CEF API.
static HOME_URL: &'static str = "http://s27.postimg.org/vqbtrolyr/servo.jpg";

static CEF_API_HASH_UNIVERSAL: &'static [u8] = b"8efd129f4afc344bd04b2feb7f73a149b6c4e27f\0";
#[cfg(target_os="windows")]
static CEF_API_HASH_PLATFORM: &'static [u8] = b"5c7f3e50ff5265985d11dc1a466513e25748bedd\0";
#[cfg(target_os="macos")]
static CEF_API_HASH_PLATFORM: &'static [u8] = b"6813214accbf2ebfb6bdcf8d00654650b251bf3d\0";
#[cfg(target_os="linux")]
static CEF_API_HASH_PLATFORM: &'static [u8] = b"2bc564c3871965ef3a2531b528bda3e17fa17a6d\0";

#[cfg(target_os="linux")]
fn resources_path() -> Option<String> {
    Some("../../servo/resources".to_owned())
}

#[cfg(not(target_os="linux"))]
fn resources_path() -> Option<String> {
    None
}

#[no_mangle]
pub extern "C" fn cef_initialize(args: *const cef_main_args_t,
                                 settings: *mut cef_settings_t,
                                 application: *mut cef_app_t,
                                 _windows_sandbox_info: *const c_void)
                                 -> c_int {
    if args.is_null() {
        return 0;
    }

    unsafe {
        command_line_init((*args).argc, (*args).argv);

        if !application.is_null() {
            (*application).get_browser_process_handler.map(|cb| {
                    let handler = cb(application);
                    if !handler.is_null() {
                        (*handler).on_context_initialized.map(|hcb| hcb(handler));
                    }
            });
        }
    }

    let rendering_threads = unsafe {
        if ((*settings).rendering_threads as usize) < 1 {
            1
        } else if (*settings).rendering_threads as usize > MAX_RENDERING_THREADS {
            MAX_RENDERING_THREADS
        } else {
            (*settings).rendering_threads as usize
        }
    };

    let mut temp_opts = opts::default_opts();
    temp_opts.url = Url::parse(HOME_URL).unwrap();
    temp_opts.paint_threads = rendering_threads;
    temp_opts.layout_threads = rendering_threads;
    temp_opts.headless = false;
    temp_opts.hard_fail = false;
    temp_opts.enable_text_antialiasing = true;
    temp_opts.resources_path = resources_path();
    opts::set(temp_opts);

    return 1
}

#[no_mangle]
pub extern "C" fn cef_shutdown() {
}

#[no_mangle]
pub extern "C" fn cef_run_message_loop() {
    // GWTODO: Support blocking message loop
    // again. Although, will it ever actually
    // be used or will everything use the
    // cef_do_message_loop_work function below
    // as our current miniservo apps do?
    unimplemented!()
}

#[no_mangle]
pub extern "C" fn cef_do_message_loop_work() {
    browser::update();
}

#[no_mangle]
pub extern "C" fn cef_quit_message_loop() {
}

#[no_mangle]
pub extern "C" fn cef_execute_process(_args: *const cef_main_args_t,
                                      _app: *mut cef_app_t,
                                      _windows_sandbox_info: *mut c_void)
                                      -> c_int {
    -1
}

#[no_mangle]
pub extern "C" fn cef_api_hash(entry: c_int) -> *const c_char {
    if entry == 0 {
        &CEF_API_HASH_PLATFORM[0] as *const u8 as *const c_char
    } else {
        &CEF_API_HASH_UNIVERSAL[0] as *const u8 as *const c_char
    }
}

#[no_mangle]
pub extern "C" fn cef_log(_file: *const c_char,
                          _line: c_int,
                          _severity: c_int,
                          message: *const c_char) {
    unsafe {
        let slice = ffi::CStr::from_ptr(message);
        println!("{}", str::from_utf8(slice.to_bytes()).unwrap())
    }
}

#[no_mangle]
pub extern "C" fn cef_get_min_log_level() -> c_int {
    0
}
<commit_msg>unset resources path on linux in embedding crate<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 command_line::command_line_init;
use interfaces::cef_app_t;
use types::{cef_main_args_t, cef_settings_t};

use libc::{c_char, c_int, c_void};
use util::opts;
use std::borrow::ToOwned;
use std::ffi;
use std::str;
use browser;
use std_url::Url;

const MAX_RENDERING_THREADS: usize = 128;

// TODO(pcwalton): Get the home page via the CEF API.
static HOME_URL: &'static str = "http://s27.postimg.org/vqbtrolyr/servo.jpg";

static CEF_API_HASH_UNIVERSAL: &'static [u8] = b"8efd129f4afc344bd04b2feb7f73a149b6c4e27f\0";
#[cfg(target_os="windows")]
static CEF_API_HASH_PLATFORM: &'static [u8] = b"5c7f3e50ff5265985d11dc1a466513e25748bedd\0";
#[cfg(target_os="macos")]
static CEF_API_HASH_PLATFORM: &'static [u8] = b"6813214accbf2ebfb6bdcf8d00654650b251bf3d\0";
#[cfg(target_os="linux")]
static CEF_API_HASH_PLATFORM: &'static [u8] = b"2bc564c3871965ef3a2531b528bda3e17fa17a6d\0";

#[no_mangle]
pub extern "C" fn cef_initialize(args: *const cef_main_args_t,
                                 settings: *mut cef_settings_t,
                                 application: *mut cef_app_t,
                                 _windows_sandbox_info: *const c_void)
                                 -> c_int {
    if args.is_null() {
        return 0;
    }

    unsafe {
        command_line_init((*args).argc, (*args).argv);

        if !application.is_null() {
            (*application).get_browser_process_handler.map(|cb| {
                    let handler = cb(application);
                    if !handler.is_null() {
                        (*handler).on_context_initialized.map(|hcb| hcb(handler));
                    }
            });
        }
    }

    let rendering_threads = unsafe {
        if ((*settings).rendering_threads as usize) < 1 {
            1
        } else if (*settings).rendering_threads as usize > MAX_RENDERING_THREADS {
            MAX_RENDERING_THREADS
        } else {
            (*settings).rendering_threads as usize
        }
    };

    let mut temp_opts = opts::default_opts();
    temp_opts.url = Url::parse(HOME_URL).unwrap();
    temp_opts.paint_threads = rendering_threads;
    temp_opts.layout_threads = rendering_threads;
    temp_opts.headless = false;
    temp_opts.hard_fail = false;
    temp_opts.enable_text_antialiasing = true;
    temp_opts.resources_path = None;
    opts::set(temp_opts);

    return 1
}

#[no_mangle]
pub extern "C" fn cef_shutdown() {
}

#[no_mangle]
pub extern "C" fn cef_run_message_loop() {
    // GWTODO: Support blocking message loop
    // again. Although, will it ever actually
    // be used or will everything use the
    // cef_do_message_loop_work function below
    // as our current miniservo apps do?
    unimplemented!()
}

#[no_mangle]
pub extern "C" fn cef_do_message_loop_work() {
    browser::update();
}

#[no_mangle]
pub extern "C" fn cef_quit_message_loop() {
}

#[no_mangle]
pub extern "C" fn cef_execute_process(_args: *const cef_main_args_t,
                                      _app: *mut cef_app_t,
                                      _windows_sandbox_info: *mut c_void)
                                      -> c_int {
    -1
}

#[no_mangle]
pub extern "C" fn cef_api_hash(entry: c_int) -> *const c_char {
    if entry == 0 {
        &CEF_API_HASH_PLATFORM[0] as *const u8 as *const c_char
    } else {
        &CEF_API_HASH_UNIVERSAL[0] as *const u8 as *const c_char
    }
}

#[no_mangle]
pub extern "C" fn cef_log(_file: *const c_char,
                          _line: c_int,
                          _severity: c_int,
                          message: *const c_char) {
    unsafe {
        let slice = ffi::CStr::from_ptr(message);
        println!("{}", str::from_utf8(slice.to_bytes()).unwrap())
    }
}

#[no_mangle]
pub extern "C" fn cef_get_min_log_level() -> c_int {
    0
}
<|endoftext|>


<commit_before>//! Multi-dimensional arrays with per-dimension specifiable lower bounds

use std::cast;
use std::vec::VecIterator;

#[deriving(Eq, Clone)]
pub struct DimensionInfo {
    len: uint,
    lower_bound: int,
}

pub trait Array<T> {
    fn get_dimension_info<'a>(&'a self) -> &'a [DimensionInfo];
    fn slice<'a>(&'a self, idx: int) -> ArraySlice<'a, T>;
    fn get<'a>(&'a self, idx: int) -> &'a T;
}

pub trait MutableArray<T> : Array<T> {
    fn slice_mut<'a>(&'a mut self, idx: int) -> MutArraySlice<'a, T> {
        MutArraySlice { slice: self.slice(idx) }
    }

    fn get_mut<'a>(&'a mut self, idx: int) -> &'a mut T {
        unsafe { cast::transmute_mut(self.get(idx)) }
    }
}

trait InternalArray<T> : Array<T> {
    fn shift_idx(&self, idx: int) -> uint {
        let shifted_idx = idx - self.get_dimension_info()[0].lower_bound;
        assert!(shifted_idx >= 0, "Out of bounds array access");
        shifted_idx as uint
    }

    fn raw_get<'a>(&'a self, idx: uint, size: uint) -> &'a T;
}

#[deriving(Eq, Clone)]
pub struct ArrayBase<T> {
    priv info: ~[DimensionInfo],
    priv data: ~[T],
}

impl<T> ArrayBase<T> {
    pub fn from_raw(data: ~[T], info: ~[DimensionInfo])
            -> ArrayBase<T> {
        assert!(!info.is_empty(), "Cannot create a 0x0 array");
        assert!(data.len() == info.iter().fold(1, |acc, i| acc * i.len),
                "Size mismatch");
        ArrayBase {
            info: info,
            data: data,
        }
    }

    pub fn from_vec(data: ~[T], lower_bound: int) -> ArrayBase<T> {
        ArrayBase {
            info: ~[DimensionInfo {
                len: data.len(),
                lower_bound: lower_bound
            }],
            data: data
        }
    }

    pub fn wrap(&mut self, lower_bound: int) {
        self.info.unshift(DimensionInfo {
            len: 1,
            lower_bound: lower_bound
        })
    }

    pub fn push_move(&mut self, other: ArrayBase<T>) {
        assert!(self.info.len() - 1 == other.info.len(),
                "Cannot append differently shaped arrays");
        for (info1, info2) in self.info.iter().skip(1).zip(other.info.iter()) {
            assert!(info1 == info2, "Cannot join differently shaped arrays");
        }
        self.info[0].len += 1;
        self.data.push_all_move(other.data);
    }

    pub fn values<'a>(&'a self) -> VecIterator<'a, T> {
        self.data.iter()
    }
}

impl<T> Array<T> for ArrayBase<T> {
    fn get_dimension_info<'a>(&'a self) -> &'a [DimensionInfo] {
        self.info.as_slice()
    }

    fn slice<'a>(&'a self, idx: int) -> ArraySlice<'a, T> {
        assert!(self.info.len() != 1,
                "Attempted to slice a one-dimensional array");
        ArraySlice {
            parent: BaseParent(self),
            idx: self.shift_idx(idx)
        }
    }

    fn get<'a>(&'a self, idx: int) -> &'a T {
        assert!(self.info.len() == 1,
                "Attempted to get from a multi-dimensional array");
        self.raw_get(self.shift_idx(idx), 1)
    }
}

impl<T> MutableArray<T> for ArrayBase<T> {}

impl<T> InternalArray<T> for ArrayBase<T> {
    fn raw_get<'a>(&'a self, idx: uint, _size: uint) -> &'a T {
        &self.data[idx]
    }
}

enum ArrayParent<'parent, T> {
    SliceParent(&'parent ArraySlice<'parent, T>),
    BaseParent(&'parent ArrayBase<T>),
}

pub struct ArraySlice<'parent, T> {
    priv parent: ArrayParent<'parent, T>,
    priv idx: uint,
}

impl<'parent, T> Array<T> for ArraySlice<'parent, T> {
    fn get_dimension_info<'a>(&'a self) -> &'a [DimensionInfo] {
        let info = match self.parent {
            SliceParent(p) => p.get_dimension_info(),
            BaseParent(p) => p.get_dimension_info()
        };
        info.slice_from(1)
    }

    fn slice<'a>(&'a self, idx: int) -> ArraySlice<'a, T> {
        assert!(self.get_dimension_info().len() != 1,
                "Attempted to slice a one-dimensional array");
        ArraySlice {
            parent: SliceParent(self),
            idx: self.shift_idx(idx)
        }
    }

    fn get<'a>(&'a self, idx: int) -> &'a T {
        assert!(self.get_dimension_info().len() == 1,
                "Attempted to get from a multi-dimensional array");
        self.raw_get(self.shift_idx(idx), 1)
    }
}

impl<'parent, T> InternalArray<T> for ArraySlice<'parent, T> {
    fn raw_get<'a>(&'a self, idx: uint, size: uint) -> &'a T {
        let size = size * self.get_dimension_info()[0].len;
        let idx = size * self.idx + idx;
        match self.parent {
            SliceParent(p) => p.raw_get(idx, size),
            BaseParent(p) => p.raw_get(idx, size)
        }
    }
}

pub struct MutArraySlice<'parent, T> {
    priv slice: ArraySlice<'parent, T>
}

impl<'parent, T> Array<T> for MutArraySlice<'parent, T> {
    fn get_dimension_info<'a>(&'a self) -> &'a [DimensionInfo] {
        self.slice.get_dimension_info()
    }

    fn slice<'a>(&'a self, idx: int) -> ArraySlice<'a, T> {
        self.slice.slice(idx)
    }

    fn get<'a>(&'a self, idx: int) -> &'a T {
        self.slice.get(idx)
    }
}

impl<'parent, T> MutableArray<T> for MutArraySlice<'parent, T> {}

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

    #[test]
    fn test_from_vec() {
        let a = ArrayBase::from_vec(~[0, 1, 2], -1);
        assert_eq!([DimensionInfo { len: 3, lower_bound: -1 }],
                   a.get_dimension_info());
        assert_eq!(&0, a.get(-1));
        assert_eq!(&1, a.get(0));
        assert_eq!(&2, a.get(1));
    }

    #[test]
    #[should_fail]
    fn test_get_2d_fail() {
        let mut a = ArrayBase::from_vec(~[0, 1, 2], -1);
        a.wrap(1);
        a.get(1);
    }

    #[test]
    #[should_fail]
    fn test_2d_slice_range_fail() {
        let mut a = ArrayBase::from_vec(~[0, 1, 2], -1);
        a.wrap(1);
        a.slice(0);
    }

    #[test]
    fn test_2d_slice_get() {
        let mut a = ArrayBase::from_vec(~[0, 1, 2], -1);
        a.wrap(1);
        let s = a.slice(1);
        assert_eq!(&0, s.get(-1));
        assert_eq!(&1, s.get(0));
        assert_eq!(&2, s.get(1));
    }

    #[test]
    #[should_fail]
    fn test_push_move_wrong_lower_bound() {
        let mut a = ArrayBase::from_vec(~[1], -1);
        a.push_move(ArrayBase::from_vec(~[2], 0));
    }

    #[test]
    #[should_fail]
    fn test_push_move_wrong_dims() {
        let mut a = ArrayBase::from_vec(~[1], -1);
        a.wrap(1);
        a.push_move(ArrayBase::from_vec(~[1, 2], -1));
    }

    #[test]
    #[should_fail]
    fn test_push_move_wrong_dim_count() {
        let mut a = ArrayBase::from_vec(~[1], -1);
        a.wrap(1);
        let mut b = ArrayBase::from_vec(~[2], -1);
        b.wrap(1);
        a.push_move(b);
    }

    #[test]
    fn test_push_move_ok() {
        let mut a = ArrayBase::from_vec(~[1, 2], 0);
        a.wrap(0);
        a.push_move(ArrayBase::from_vec(~[3, 4], 0));
        let s = a.slice(0);
        assert_eq!(&1, s.get(0));
        assert_eq!(&2, s.get(1));
        let s = a.slice(1);
        assert_eq!(&3, s.get(0));
        assert_eq!(&4, s.get(1));
    }

    #[test]
    fn test_3d() {
        let mut a = ArrayBase::from_vec(~[0, 1], 0);
        a.wrap(0);
        a.push_move(ArrayBase::from_vec(~[2, 3], 0));
        a.wrap(0);
        let mut b = ArrayBase::from_vec(~[4, 5], 0);
        b.wrap(0);
        b.push_move(ArrayBase::from_vec(~[6, 7], 0));
        a.push_move(b);
        let s1 = a.slice(0);
        let s2 = s1.slice(0);
        assert_eq!(&0, s2.get(0));
        assert_eq!(&1, s2.get(1));
        let s2 = s1.slice(1);
        assert_eq!(&2, s2.get(0));
        assert_eq!(&3, s2.get(1));
        let s1 = a.slice(1);
        let s2 = s1.slice(0);
        assert_eq!(&4, s2.get(0));
        assert_eq!(&5, s2.get(1));
        let s2 = s1.slice(1);
        assert_eq!(&6, s2.get(0));
        assert_eq!(&7, s2.get(1));
    }

    #[test]
    fn test_mut() {
        let mut a = ArrayBase::from_vec(~[1, 2], 0);
        a.wrap(0);
        {
            let mut s = a.slice_mut(0);
            *s.get_mut(0) = 3;
        }
        let s = a.slice(0);
        assert_eq!(&3, s.get(0));
    }

    #[test]
    #[should_fail]
    fn test_base_overslice() {
        let a = ArrayBase::from_vec(~[1], 0);
        a.slice(0);
    }

    #[test]
    #[should_fail]
    fn test_slice_overslice() {
        let mut a = ArrayBase::from_vec(~[1], 0);
        a.wrap(0);
        let s = a.slice(0);
        s.slice(0);
    }
}
<commit_msg>Document types::array<commit_after>//! Multi-dimensional arrays with per-dimension specifiable lower bounds

use std::cast;
use std::vec::VecIterator;

/// Information about a dimension of an array
#[deriving(Eq, Clone)]
pub struct DimensionInfo {
    /// The size of the dimension
    len: uint,
    /// The index of the first element of the dimension
    lower_bound: int,
}

/// Specifies methods that can be performed on multi-dimensional arrays
pub trait Array<T> {
    /// Returns information about the dimensions of this array
    fn get_dimension_info<'a>(&'a self) -> &'a [DimensionInfo];

    /// Slices into this array, returning an immutable view of a subarray.
    ///
    /// # Failure
    ///
    /// Fails if the array is one-dimensional or the index is out of bounds.
    fn slice<'a>(&'a self, idx: int) -> ArraySlice<'a, T>;

    /// Retrieves an immutable reference to a value in this array.
    ///
    ///
    /// # Failure
    ///
    /// Fails if the array is multi-dimensional or the index is out of bounds.
    fn get<'a>(&'a self, idx: int) -> &'a T;
}

/// Specifies methods that can be performed on mutable multi-dimensional arrays
pub trait MutableArray<T> : Array<T> {
    /// Slices into this array, returning a mutable view of a subarray.
    ///
    /// # Failure
    ///
    /// Fails if the array is one-dimensional or the index is out of bounds.
    fn slice_mut<'a>(&'a mut self, idx: int) -> MutArraySlice<'a, T> {
        MutArraySlice { slice: self.slice(idx) }
    }

    /// Retrieves a mutable reference to a value in this array.
    ///
    ///
    /// # Failure
    ///
    /// Fails if the array is multi-dimensional or the index is out of bounds.
    fn get_mut<'a>(&'a mut self, idx: int) -> &'a mut T {
        unsafe { cast::transmute_mut(self.get(idx)) }
    }
}

trait InternalArray<T> : Array<T> {
    fn shift_idx(&self, idx: int) -> uint {
        let shifted_idx = idx - self.get_dimension_info()[0].lower_bound;
        assert!(shifted_idx >= 0 &&
                    shifted_idx < self.get_dimension_info()[0].len as int,
                "Out of bounds array access");
        shifted_idx as uint
    }

    fn raw_get<'a>(&'a self, idx: uint, size: uint) -> &'a T;
}

/// A multi-dimensional array
#[deriving(Eq, Clone)]
pub struct ArrayBase<T> {
    priv info: ~[DimensionInfo],
    priv data: ~[T],
}

impl<T> ArrayBase<T> {
    /// Creates a new multi-dimensional array from its underlying components.
    ///
    /// The data array should be provided in the higher-dimensional equivalent
    /// of row-major order.
    ///
    /// # Failure
    ///
    /// Fails if there are 0 dimensions or the number of elements provided does
    /// not match the number of elements specified.
    pub fn from_raw(data: ~[T], info: ~[DimensionInfo])
            -> ArrayBase<T> {
        assert!(!info.is_empty(), "Cannot create a 0x0 array");
        assert!(data.len() == info.iter().fold(1, |acc, i| acc * i.len),
                "Size mismatch");
        ArrayBase {
            info: info,
            data: data,
        }
    }

    /// Creates a new one-dimensional array from a vector.
    pub fn from_vec(data: ~[T], lower_bound: int) -> ArrayBase<T> {
        ArrayBase {
            info: ~[DimensionInfo {
                len: data.len(),
                lower_bound: lower_bound
            }],
            data: data
        }
    }

    /// Wraps this array in a new dimension of size 1.
    ///
    /// For example the one-dimensional array `[1,2]` would turn into
    /// the two-dimensional array `[[1,2]]`.
    pub fn wrap(&mut self, lower_bound: int) {
        self.info.unshift(DimensionInfo {
            len: 1,
            lower_bound: lower_bound
        })
    }

    /// Takes ownership of another array, appending it to the top-level
    /// dimension of this array.
    ///
    /// The dimensions of the other array must have an identical shape to the
    /// dimensions of a slice of this array. This includes both the sizes of
    /// the dimensions as well as their lower bounds.
    ///
    /// For example, if `[3,4]` is pushed onto `[[1,2]]`, the result is
    /// `[[1,2],[3,4]]`.
    ///
    /// # Failure
    ///
    /// Fails if the other array does not have dimensions identical to the
    /// dimensions of a slice of this array.
    pub fn push_move(&mut self, other: ArrayBase<T>) {
        assert!(self.info.len() - 1 == other.info.len(),
                "Cannot append differently shaped arrays");
        for (info1, info2) in self.info.iter().skip(1).zip(other.info.iter()) {
            assert!(info1 == info2, "Cannot join differently shaped arrays");
        }
        self.info[0].len += 1;
        self.data.push_all_move(other.data);
    }

    /// Returns an iterator over the values in this array, in the
    /// higher-dimensional equivalent of row-major order.
    pub fn values<'a>(&'a self) -> VecIterator<'a, T> {
        self.data.iter()
    }
}

impl<T> Array<T> for ArrayBase<T> {
    fn get_dimension_info<'a>(&'a self) -> &'a [DimensionInfo] {
        self.info.as_slice()
    }

    fn slice<'a>(&'a self, idx: int) -> ArraySlice<'a, T> {
        assert!(self.info.len() != 1,
                "Attempted to slice a one-dimensional array");
        ArraySlice {
            parent: BaseParent(self),
            idx: self.shift_idx(idx)
        }
    }

    fn get<'a>(&'a self, idx: int) -> &'a T {
        assert!(self.info.len() == 1,
                "Attempted to get from a multi-dimensional array");
        self.raw_get(self.shift_idx(idx), 1)
    }
}

impl<T> MutableArray<T> for ArrayBase<T> {}

impl<T> InternalArray<T> for ArrayBase<T> {
    fn raw_get<'a>(&'a self, idx: uint, _size: uint) -> &'a T {
        &self.data[idx]
    }
}

enum ArrayParent<'parent, T> {
    SliceParent(&'parent ArraySlice<'parent, T>),
    BaseParent(&'parent ArrayBase<T>),
}

/// An immutable slice of a multi-dimensional array
pub struct ArraySlice<'parent, T> {
    priv parent: ArrayParent<'parent, T>,
    priv idx: uint,
}

impl<'parent, T> Array<T> for ArraySlice<'parent, T> {
    fn get_dimension_info<'a>(&'a self) -> &'a [DimensionInfo] {
        let info = match self.parent {
            SliceParent(p) => p.get_dimension_info(),
            BaseParent(p) => p.get_dimension_info()
        };
        info.slice_from(1)
    }

    fn slice<'a>(&'a self, idx: int) -> ArraySlice<'a, T> {
        assert!(self.get_dimension_info().len() != 1,
                "Attempted to slice a one-dimensional array");
        ArraySlice {
            parent: SliceParent(self),
            idx: self.shift_idx(idx)
        }
    }

    fn get<'a>(&'a self, idx: int) -> &'a T {
        assert!(self.get_dimension_info().len() == 1,
                "Attempted to get from a multi-dimensional array");
        self.raw_get(self.shift_idx(idx), 1)
    }
}

impl<'parent, T> InternalArray<T> for ArraySlice<'parent, T> {
    fn raw_get<'a>(&'a self, idx: uint, size: uint) -> &'a T {
        let size = size * self.get_dimension_info()[0].len;
        let idx = size * self.idx + idx;
        match self.parent {
            SliceParent(p) => p.raw_get(idx, size),
            BaseParent(p) => p.raw_get(idx, size)
        }
    }
}

/// A mutable slice of a multi-dimensional array
pub struct MutArraySlice<'parent, T> {
    priv slice: ArraySlice<'parent, T>
}

impl<'parent, T> Array<T> for MutArraySlice<'parent, T> {
    fn get_dimension_info<'a>(&'a self) -> &'a [DimensionInfo] {
        self.slice.get_dimension_info()
    }

    fn slice<'a>(&'a self, idx: int) -> ArraySlice<'a, T> {
        self.slice.slice(idx)
    }

    fn get<'a>(&'a self, idx: int) -> &'a T {
        self.slice.get(idx)
    }
}

impl<'parent, T> MutableArray<T> for MutArraySlice<'parent, T> {}

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

    #[test]
    fn test_from_vec() {
        let a = ArrayBase::from_vec(~[0, 1, 2], -1);
        assert_eq!([DimensionInfo { len: 3, lower_bound: -1 }],
                   a.get_dimension_info());
        assert_eq!(&0, a.get(-1));
        assert_eq!(&1, a.get(0));
        assert_eq!(&2, a.get(1));
    }

    #[test]
    #[should_fail]
    fn test_get_2d_fail() {
        let mut a = ArrayBase::from_vec(~[0, 1, 2], -1);
        a.wrap(1);
        a.get(1);
    }

    #[test]
    #[should_fail]
    fn test_2d_slice_range_fail_low() {
        let mut a = ArrayBase::from_vec(~[0, 1, 2], -1);
        a.wrap(1);
        a.slice(0);
    }

    #[test]
    #[should_fail]
    fn test_2d_slice_range_fail_high() {
        let mut a = ArrayBase::from_vec(~[0, 1, 2], -1);
        a.wrap(1);
        a.slice(2);
    }

    #[test]
    fn test_2d_slice_get() {
        let mut a = ArrayBase::from_vec(~[0, 1, 2], -1);
        a.wrap(1);
        let s = a.slice(1);
        assert_eq!(&0, s.get(-1));
        assert_eq!(&1, s.get(0));
        assert_eq!(&2, s.get(1));
    }

    #[test]
    #[should_fail]
    fn test_push_move_wrong_lower_bound() {
        let mut a = ArrayBase::from_vec(~[1], -1);
        a.push_move(ArrayBase::from_vec(~[2], 0));
    }

    #[test]
    #[should_fail]
    fn test_push_move_wrong_dims() {
        let mut a = ArrayBase::from_vec(~[1], -1);
        a.wrap(1);
        a.push_move(ArrayBase::from_vec(~[1, 2], -1));
    }

    #[test]
    #[should_fail]
    fn test_push_move_wrong_dim_count() {
        let mut a = ArrayBase::from_vec(~[1], -1);
        a.wrap(1);
        let mut b = ArrayBase::from_vec(~[2], -1);
        b.wrap(1);
        a.push_move(b);
    }

    #[test]
    fn test_push_move_ok() {
        let mut a = ArrayBase::from_vec(~[1, 2], 0);
        a.wrap(0);
        a.push_move(ArrayBase::from_vec(~[3, 4], 0));
        let s = a.slice(0);
        assert_eq!(&1, s.get(0));
        assert_eq!(&2, s.get(1));
        let s = a.slice(1);
        assert_eq!(&3, s.get(0));
        assert_eq!(&4, s.get(1));
    }

    #[test]
    fn test_3d() {
        let mut a = ArrayBase::from_vec(~[0, 1], 0);
        a.wrap(0);
        a.push_move(ArrayBase::from_vec(~[2, 3], 0));
        a.wrap(0);
        let mut b = ArrayBase::from_vec(~[4, 5], 0);
        b.wrap(0);
        b.push_move(ArrayBase::from_vec(~[6, 7], 0));
        a.push_move(b);
        let s1 = a.slice(0);
        let s2 = s1.slice(0);
        assert_eq!(&0, s2.get(0));
        assert_eq!(&1, s2.get(1));
        let s2 = s1.slice(1);
        assert_eq!(&2, s2.get(0));
        assert_eq!(&3, s2.get(1));
        let s1 = a.slice(1);
        let s2 = s1.slice(0);
        assert_eq!(&4, s2.get(0));
        assert_eq!(&5, s2.get(1));
        let s2 = s1.slice(1);
        assert_eq!(&6, s2.get(0));
        assert_eq!(&7, s2.get(1));
    }

    #[test]
    fn test_mut() {
        let mut a = ArrayBase::from_vec(~[1, 2], 0);
        a.wrap(0);
        {
            let mut s = a.slice_mut(0);
            *s.get_mut(0) = 3;
        }
        let s = a.slice(0);
        assert_eq!(&3, s.get(0));
    }

    #[test]
    #[should_fail]
    fn test_base_overslice() {
        let a = ArrayBase::from_vec(~[1], 0);
        a.slice(0);
    }

    #[test]
    #[should_fail]
    fn test_slice_overslice() {
        let mut a = ArrayBase::from_vec(~[1], 0);
        a.wrap(0);
        let s = a.slice(0);
        s.slice(0);
    }
}
<|endoftext|>


<commit_before>#![feature(custom_derive, plugin)]
#![plugin(serde_macros)]

#[macro_use]
extern crate log;
extern crate env_logger;
extern crate iron;
extern crate mount;
extern crate staticfile;
extern crate bodyparser;
extern crate serde;
extern crate serde_json;
extern crate mktemp;
#[macro_use]
extern crate quick_error;

use std::any::Any;
use std::env;
use std::path::PathBuf;

use iron::prelude::*;
use iron::status;
use mount::Mount;
use serde::{Serialize, Deserialize};
use staticfile::Static;

use sandbox::Sandbox;

const DEFAULT_ADDRESS: &'static str = "127.0.0.1";
const DEFAULT_PORT: u16 = 5000;

mod sandbox;

fn main() {
    env_logger::init().expect("Unable to initialize logger");

    let root: PathBuf = env::var_os("PLAYGROUND_UI_ROOT").expect("Must specify PLAYGROUND_UI_ROOT").into();
    let address = env::var("PLAYGROUND_UI_ADDRESS").unwrap_or(DEFAULT_ADDRESS.to_string());
    let port = env::var("PLAYGROUND_UI_PORT").ok().and_then(|p| p.parse().ok()).unwrap_or(DEFAULT_PORT);

    let mut mount = Mount::new();
    mount.mount("/", Static::new(&root));
    mount.mount("/compile", compile);
    mount.mount("/execute", execute);
    mount.mount("/format", format);

    info!("Starting the server on {}:{}", address, port);
    Iron::new(mount).http((&*address, port)).expect("Unable to start server");
}

fn compile(req: &mut Request) -> IronResult<Response> {
    with_sandbox(req, |sandbox, req: CompileRequest| {
        sandbox.compile(&req.into()).map(CompileResponse::from)
    })
}

fn execute(req: &mut Request) -> IronResult<Response> {
    with_sandbox(req, |sandbox, req: ExecuteRequest| {
        sandbox.execute(&req.into()).map(ExecuteResponse::from)
    })
}

fn format(req: &mut Request) -> IronResult<Response> {
    with_sandbox(req, |sandbox, req: FormatRequest| {
        sandbox.format(&req.into()).map(FormatResponse::from)
    })
}

fn with_sandbox<Req, Resp, F>(req: &mut Request, f: F) -> IronResult<Response>
    where F: FnOnce(Sandbox, Req) -> sandbox::Result<Resp>,
          Req: Deserialize + Clone + Any + 'static,
          Resp: Serialize,
{
    let response = req.get::<bodyparser::Struct<Req>>()
        .map_err(Error::Deserialization)
        .and_then(|r| r.ok_or(Error::RequestMissing))
        .and_then(|req| {
            let sandbox = try!(Sandbox::new());
            let resp = try!(f(sandbox, req));
            let body = try!(serde_json::ser::to_string(&resp));
            Ok(body)
        });

    match response {
        Ok(body) => Ok(Response::with((status::Ok, body))),
        Err(err) => {
            let err = ErrorJson { error: err.to_string() };
            match serde_json::ser::to_string(&err) {
                Ok(error_str) => Ok(Response::with((status::InternalServerError, error_str))),
                Err(_) => Ok(Response::with((status::InternalServerError, FATAL_ERROR_JSON))),
            }
        },
    }
}

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        Sandbox(err: sandbox::Error) {
            description("sandbox operation failed")
            display("Sandbox operation failed: {}", err)
            cause(err)
            from()
        }
        Serialization(err: serde_json::Error) {
            description("unable to serialize response")
            display("Unable to serialize response: {}", err)
            cause(err)
            from()
        }
        Deserialization(err: bodyparser::BodyError) {
            description("unable to deserialize request")
            display("Unable to deserialize request: {}", err)
            cause(err)
            from()
        }
        RequestMissing {
            description("no request was provided")
            display("No request was provided")
        }
    }
}

const FATAL_ERROR_JSON: &'static str =
    r#"{"error": "Multiple cascading errors occurred, abandon all hope"}"#;

#[derive(Debug, Clone, Serialize)]
struct ErrorJson {
    error: String,
}

#[derive(Debug, Clone, Deserialize)]
struct CompileRequest {
    target: String,
    channel: String,
    mode: String,
    tests: bool,
    code: String,
}

impl From<CompileRequest> for sandbox::CompileRequest {
    fn from(me: CompileRequest) -> Self {
        sandbox::CompileRequest {
            target: parse_target(&me.target),
            channel: parse_channel(&me.channel),
            mode: parse_mode(&me.mode),
            tests: me.tests,
            code: me.code,
        }
    }
}

#[derive(Debug, Clone, Serialize)]
struct CompileResponse {
    success: bool,
    code: String,
    stdout: String,
    stderr: String,
}

impl From<sandbox::CompileResponse> for CompileResponse {
    fn from(me: sandbox::CompileResponse) -> Self {
        CompileResponse {
            success: me.success,
            code: me.code,
            stdout: me.stdout,
            stderr: me.stderr,
        }
    }
}

#[derive(Debug, Clone, Deserialize)]
struct ExecuteRequest {
    channel: String,
    mode: String,
    tests: bool,
    code: String,
}

impl From<ExecuteRequest> for sandbox::ExecuteRequest {
    fn from(me: ExecuteRequest) -> Self {
        sandbox::ExecuteRequest {
            channel: parse_channel(&me.channel),
            mode: parse_mode(&me.mode),
            tests: me.tests,
            code: me.code,
        }
    }
}

#[derive(Debug, Clone, Serialize)]
struct ExecuteResponse {
    success: bool,
    stdout: String,
    stderr: String,
}

impl From<sandbox::ExecuteResponse> for ExecuteResponse {
    fn from(me: sandbox::ExecuteResponse) -> Self {
        ExecuteResponse {
            success: me.success,
            stdout: me.stdout,
            stderr: me.stderr,
        }
    }
}

#[derive(Debug, Clone, Deserialize)]
struct FormatRequest {
    code: String,
}

impl From<FormatRequest> for sandbox::FormatRequest {
    fn from(me: FormatRequest) -> Self {
        sandbox::FormatRequest {
            code: me.code,
        }
    }
}

#[derive(Debug, Clone, Serialize)]
struct FormatResponse {
    success: bool,
    code: String,
    stdout: String,
    stderr: String,
}

impl From<sandbox::FormatResponse> for FormatResponse {
    fn from(me: sandbox::FormatResponse) -> Self {
        FormatResponse {
            success: me.success,
            code: me.code,
            stdout: me.stdout,
            stderr: me.stderr,
        }
    }
}

fn parse_target(s: &str) -> sandbox::CompileTarget {
    match s {
        "asm" => sandbox::CompileTarget::Assembly,
        "llvm-ir" => sandbox::CompileTarget::LlvmIr,
        _ => panic!("Unknown compilation target {}", s),
    }
}

fn parse_channel(s: &str) -> sandbox::Channel {
    match s {
        "stable" => sandbox::Channel::Stable,
        "beta" => sandbox::Channel::Beta,
        "nightly" => sandbox::Channel::Nightly,
        _ => panic!("Unknown channel {}", s),
    }
}

fn parse_mode(s: &str) -> sandbox::Mode {
    match s {
        "debug" => sandbox::Mode::Debug,
        "release" => sandbox::Mode::Release,
        _ => panic!("Unknown mode {}", s),
    }
}
<commit_msg>Don't panic when invalid enum strings are passed in<commit_after>#![feature(try_from)]
#![feature(custom_derive, plugin)]
#![plugin(serde_macros)]

#[macro_use]
extern crate log;
extern crate env_logger;
extern crate iron;
extern crate mount;
extern crate staticfile;
extern crate bodyparser;
extern crate serde;
extern crate serde_json;
extern crate mktemp;
#[macro_use]
extern crate quick_error;

use std::any::Any;
use std::convert::{TryFrom, TryInto};
use std::env;
use std::path::PathBuf;

use iron::prelude::*;
use iron::status;
use mount::Mount;
use serde::{Serialize, Deserialize};
use staticfile::Static;

use sandbox::Sandbox;

const DEFAULT_ADDRESS: &'static str = "127.0.0.1";
const DEFAULT_PORT: u16 = 5000;

mod sandbox;

fn main() {
    env_logger::init().expect("Unable to initialize logger");

    let root: PathBuf = env::var_os("PLAYGROUND_UI_ROOT").expect("Must specify PLAYGROUND_UI_ROOT").into();
    let address = env::var("PLAYGROUND_UI_ADDRESS").unwrap_or(DEFAULT_ADDRESS.to_string());
    let port = env::var("PLAYGROUND_UI_PORT").ok().and_then(|p| p.parse().ok()).unwrap_or(DEFAULT_PORT);

    let mut mount = Mount::new();
    mount.mount("/", Static::new(&root));
    mount.mount("/compile", compile);
    mount.mount("/execute", execute);
    mount.mount("/format", format);

    info!("Starting the server on {}:{}", address, port);
    Iron::new(mount).http((&*address, port)).expect("Unable to start server");
}

fn compile(req: &mut Request) -> IronResult<Response> {
    with_sandbox(req, |sandbox, req: CompileRequest| {
        let req = try!(req.try_into());
        sandbox
            .compile(&req)
            .map(CompileResponse::from)
            .map_err(Error::Sandbox)
    })
}

fn execute(req: &mut Request) -> IronResult<Response> {
    with_sandbox(req, |sandbox, req: ExecuteRequest| {
        let req = try!(req.try_into());
        sandbox
            .execute(&req)
            .map(ExecuteResponse::from)
            .map_err(Error::Sandbox)
    })
}

fn format(req: &mut Request) -> IronResult<Response> {
    with_sandbox(req, |sandbox, req: FormatRequest| {
        sandbox
            .format(&req.into())
            .map(FormatResponse::from)
            .map_err(Error::Sandbox)
    })
}

fn with_sandbox<Req, Resp, F>(req: &mut Request, f: F) -> IronResult<Response>
    where F: FnOnce(Sandbox, Req) -> Result<Resp>,
          Req: Deserialize + Clone + Any + 'static,
          Resp: Serialize,
{
    let response = req.get::<bodyparser::Struct<Req>>()
        .map_err(Error::Deserialization)
        .and_then(|r| r.ok_or(Error::RequestMissing))
        .and_then(|req| {
            let sandbox = try!(Sandbox::new());
            let resp = try!(f(sandbox, req));
            let body = try!(serde_json::ser::to_string(&resp));
            Ok(body)
        });

    match response {
        Ok(body) => Ok(Response::with((status::Ok, body))),
        Err(err) => {
            let err = ErrorJson { error: err.to_string() };
            match serde_json::ser::to_string(&err) {
                Ok(error_str) => Ok(Response::with((status::InternalServerError, error_str))),
                Err(_) => Ok(Response::with((status::InternalServerError, FATAL_ERROR_JSON))),
            }
        },
    }
}

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        Sandbox(err: sandbox::Error) {
            description("sandbox operation failed")
            display("Sandbox operation failed: {}", err)
            cause(err)
            from()
        }
        Serialization(err: serde_json::Error) {
            description("unable to serialize response")
            display("Unable to serialize response: {}", err)
            cause(err)
            from()
        }
        Deserialization(err: bodyparser::BodyError) {
            description("unable to deserialize request")
            display("Unable to deserialize request: {}", err)
            cause(err)
            from()
        }
        InvalidTarget(value: String) {
            description("an invalid target was passed")
            display("The value {:?} is not a valid target", value)
        }
        InvalidChannel(value: String) {
            description("an invalid channel was passed")
            display("The value {:?} is not a valid channel", value,)
        }
        InvalidMode(value: String) {
            description("an invalid mode was passed")
            display("The value {:?} is not a valid mode", value)
        }
        RequestMissing {
            description("no request was provided")
            display("No request was provided")
        }
    }
}

type Result<T> = ::std::result::Result<T, Error>;

const FATAL_ERROR_JSON: &'static str =
    r#"{"error": "Multiple cascading errors occurred, abandon all hope"}"#;

#[derive(Debug, Clone, Serialize)]
struct ErrorJson {
    error: String,
}

#[derive(Debug, Clone, Deserialize)]
struct CompileRequest {
    target: String,
    channel: String,
    mode: String,
    tests: bool,
    code: String,
}

impl TryFrom<CompileRequest> for sandbox::CompileRequest {
    type Err = Error;

    fn try_from(me: CompileRequest) -> Result<Self> {
        Ok(sandbox::CompileRequest {
            target: try!(parse_target(&me.target)),
            channel: try!(parse_channel(&me.channel)),
            mode: try!(parse_mode(&me.mode)),
            tests: me.tests,
            code: me.code,
        })
    }
}

#[derive(Debug, Clone, Serialize)]
struct CompileResponse {
    success: bool,
    code: String,
    stdout: String,
    stderr: String,
}

impl From<sandbox::CompileResponse> for CompileResponse {
    fn from(me: sandbox::CompileResponse) -> Self {
        CompileResponse {
            success: me.success,
            code: me.code,
            stdout: me.stdout,
            stderr: me.stderr,
        }
    }
}

#[derive(Debug, Clone, Deserialize)]
struct ExecuteRequest {
    channel: String,
    mode: String,
    tests: bool,
    code: String,
}

impl TryFrom<ExecuteRequest> for sandbox::ExecuteRequest {
    type Err = Error;

    fn try_from(me: ExecuteRequest) -> Result<Self> {
        Ok(sandbox::ExecuteRequest {
            channel: try!(parse_channel(&me.channel)),
            mode: try!(parse_mode(&me.mode)),
            tests: me.tests,
            code: me.code,
        })
    }
}

#[derive(Debug, Clone, Serialize)]
struct ExecuteResponse {
    success: bool,
    stdout: String,
    stderr: String,
}

impl From<sandbox::ExecuteResponse> for ExecuteResponse {
    fn from(me: sandbox::ExecuteResponse) -> Self {
        ExecuteResponse {
            success: me.success,
            stdout: me.stdout,
            stderr: me.stderr,
        }
    }
}

#[derive(Debug, Clone, Deserialize)]
struct FormatRequest {
    code: String,
}

impl From<FormatRequest> for sandbox::FormatRequest {
    fn from(me: FormatRequest) -> Self {
        sandbox::FormatRequest {
            code: me.code,
        }
    }
}

#[derive(Debug, Clone, Serialize)]
struct FormatResponse {
    success: bool,
    code: String,
    stdout: String,
    stderr: String,
}

impl From<sandbox::FormatResponse> for FormatResponse {
    fn from(me: sandbox::FormatResponse) -> Self {
        FormatResponse {
            success: me.success,
            code: me.code,
            stdout: me.stdout,
            stderr: me.stderr,
        }
    }
}

fn parse_target(s: &str) -> Result<sandbox::CompileTarget> {
    Ok(match s {
        "asm" => sandbox::CompileTarget::Assembly,
        "llvm-ir" => sandbox::CompileTarget::LlvmIr,
        _ => return Err(Error::InvalidTarget(s.into()))
    })
}

fn parse_channel(s: &str) -> Result<sandbox::Channel> {
    Ok(match s {
        "stable" => sandbox::Channel::Stable,
        "beta" => sandbox::Channel::Beta,
        "nightly" => sandbox::Channel::Nightly,
        _ => return Err(Error::InvalidChannel(s.into()))
    })
}

fn parse_mode(s: &str) -> Result<sandbox::Mode> {
    Ok(match s {
        "debug" => sandbox::Mode::Debug,
        "release" => sandbox::Mode::Release,
        _ => return Err(Error::InvalidMode(s.into()))
    })
}
<|endoftext|>


<commit_before>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    borrow_analysis_v2::{BorrowAnnotation, EdgeDomain},
    function_target::{FunctionData, FunctionTarget},
    function_target_pipeline::{FunctionTargetProcessor, FunctionTargetsHolder},
    stackless_bytecode::{
        AttrId, BorrowEdge, BorrowNode,
        Bytecode::{self, *},
        Operation,
    },
};
use move_model::{
    ast::{ConditionKind, TempIndex},
    model::{FunctionEnv, Loc, StructEnv},
    ty::Type,
};
use std::collections::BTreeMap;
use vm::file_format::CodeOffset;

pub struct MemoryInstrumentationProcessor {}

impl MemoryInstrumentationProcessor {
    pub fn new() -> Box<Self> {
        Box::new(MemoryInstrumentationProcessor {})
    }
}

impl FunctionTargetProcessor for MemoryInstrumentationProcessor {
    fn process(
        &self,
        _targets: &mut FunctionTargetsHolder,
        func_env: &FunctionEnv<'_>,
        mut data: FunctionData,
    ) -> FunctionData {
        if func_env.is_native() {
            return data;
        }
        let borrow_annotation = data
            .annotations
            .remove::<BorrowAnnotation>()
            .expect("borrow annotation");
        let next_attr_id = data.next_free_attr_index();
        let code = std::mem::take(&mut data.code);
        let func_target = FunctionTarget::new(func_env, &data);
        let mut instrumenter = Instrumenter::new(&func_target, &borrow_annotation, next_attr_id);
        let mut new_code = vec![];
        for (code_offset, bytecode) in code.into_iter().enumerate() {
            let (before, after) =
                instrumenter.compute_instrumentation(code_offset as CodeOffset, &bytecode);
            new_code.extend(before);
            new_code.push(bytecode);
            new_code.extend(after);
        }
        let new_locations = std::mem::take(&mut instrumenter.new_locations);
        data.code = new_code;
        data.locations.extend(new_locations.into_iter());
        data
    }

    fn name(&self) -> String {
        "memory_instr".to_string()
    }
}

struct Instrumenter<'a> {
    func_target: &'a FunctionTarget<'a>,
    borrow_annotation: &'a BorrowAnnotation,
    next_attr_id: usize,
    new_locations: BTreeMap<AttrId, Loc>,
}

impl<'a> Instrumenter<'a> {
    fn new(
        func_target: &'a FunctionTarget<'a>,
        borrow_annotation: &'a BorrowAnnotation,
        next_attr_id: usize,
    ) -> Self {
        Self {
            func_target,
            borrow_annotation,
            next_attr_id,
            new_locations: BTreeMap::new(),
        }
    }

    fn compute_instrumentation(
        &mut self,
        code_offset: CodeOffset,
        bytecode: &Bytecode,
    ) -> (Vec<Bytecode>, Vec<Bytecode>) {
        let (mut before, mut after) = self.public_function_instrumentation(code_offset, bytecode);
        let destroy_instr = self.ref_create_destroy_instrumentation(code_offset, bytecode);
        if matches!(
            bytecode,
            Bytecode::Ret(..) | Bytecode::Branch(..) | Bytecode::Jump(..) | Bytecode::Abort(..)
        ) {
            // Add this to before instrumentation.
            before.extend(destroy_instr);
        } else {
            after.extend(destroy_instr);
        }
        (before, after)
    }

    fn public_function_instrumentation(
        &mut self,
        _code_offset: CodeOffset,
        bytecode: &Bytecode,
    ) -> (Vec<Bytecode>, Vec<Bytecode>) {
        let mut before = vec![];
        let mut after = vec![];
        if let Call(attr_id, _, Operation::Function(mid, fid, _), srcs, _) = bytecode {
            let callee_env = self
                .func_target
                .module_env()
                .env
                .get_module(*mid)
                .into_function(*fid);
            if callee_env.is_public() {
                let pack_refs: Vec<&TempIndex> = srcs
                    .iter()
                    .filter(|idx| self.is_pack_ref_ty(self.func_target.get_local_type(**idx)))
                    .collect();
                before.append(
                    &mut pack_refs
                        .iter()
                        .map(|idx| {
                            Bytecode::Call(
                                self.clone_attr(*attr_id),
                                vec![],
                                Operation::PackRef,
                                vec![**idx],
                                None,
                            )
                        })
                        .collect(),
                );
                after.append(
                    &mut pack_refs
                        .into_iter()
                        .map(|idx| {
                            Bytecode::Call(
                                self.clone_attr(*attr_id),
                                vec![],
                                Operation::UnpackRef,
                                vec![*idx],
                                None,
                            )
                        })
                        .collect(),
                );
            }
        }
        (before, after)
    }

    /// Determines whether the type needs a pack ref.
    fn is_pack_ref_ty(&self, ty: &Type) -> bool {
        let env = self.func_target.global_env();
        if let Some((struct_env, _)) = ty.skip_reference().get_struct(env) {
            self.is_pack_ref_struct(&struct_env)
        } else {
            // TODO: vectors
            false
        }
    }

    /// Determines whether the struct needs a pack ref.
    fn is_pack_ref_struct(&self, struct_env: &StructEnv<'_>) -> bool {
        use ConditionKind::*;
        struct_env.get_spec().any(|c| matches!(c.kind, VarUpdate(..)|VarPack(..)|Invariant))
        // If any of the fields has it, it inherits to the struct.
        ||  struct_env
            .get_fields()
            .any(|fe| self.is_pack_ref_ty(&fe.get_type()))
    }

    fn new_attr_id(&mut self, loc: Loc) -> AttrId {
        let attr_id = AttrId::new(self.next_attr_id);
        self.next_attr_id += 1;
        self.new_locations.insert(attr_id, loc);
        attr_id
    }

    fn clone_attr(&mut self, id: AttrId) -> AttrId {
        let loc = self.func_target.get_bytecode_loc(id);
        self.new_attr_id(loc)
    }

    fn ref_create_destroy_instrumentation(
        &mut self,
        code_offset: CodeOffset,
        bytecode: &Bytecode,
    ) -> Vec<Bytecode> {
        let borrow_annotation_at = self
            .borrow_annotation
            .get_borrow_info_at(code_offset)
            .unwrap();
        let before = &borrow_annotation_at.before;
        let after = &borrow_annotation_at.after;

        let mut instrumented_bytecodes = vec![];

        // Generate UnpackRef from Borrow instructions.
        if let Call(attr_id, dests, op, _, _) = bytecode {
            use Operation::*;
            match op {
                BorrowLoc | BorrowField(..) | BorrowGlobal(..) => {
                    let ty = self.func_target.get_local_type(dests[0]);
                    let node = BorrowNode::Reference(dests[0]);
                    if self.is_pack_ref_ty(ty)
                        && after.is_in_use(&node)
                        && !after.is_unchecked(&node)
                    {
                        instrumented_bytecodes.push(Bytecode::Call(
                            self.clone_attr(*attr_id),
                            vec![],
                            if after.is_spliced(&node) {
                                Operation::UnpackRefDeep
                            } else {
                                Operation::UnpackRef
                            },
                            vec![dests[0]],
                            None,
                        ));
                    }
                }
                _ => {}
            }
        }

        // Generate PackRef for nodes which go out of scope, as well as generate WriteBack.
        let attr_id = bytecode.get_attr_id();
        for node in before.dying_nodes(after) {
            if let BorrowNode::Reference(idx) = &node {
                let ty = self.func_target.get_local_type(*idx);
                if self.is_pack_ref_ty(ty) {
                    // Generate a pack_ref for this reference, unless: (a) the node is marked
                    // as unchecked (b) the node is marked as having been moved to somewhere else.
                    if !before.is_unchecked(&node) && !before.is_moved(&node) {
                        instrumented_bytecodes.push(Bytecode::Call(
                            self.clone_attr(attr_id),
                            vec![],
                            if before.is_spliced(&node) {
                                // If this node has been spliced, we need to perform a deep pack.
                                // A spliced node is one which has a child at some unknown,
                                // dynamically defined path, derived by some function from the parent.
                                // The nodes on this path have not been packed yet, and we therefore
                                // need to do a deep pack.
                                Operation::PackRefDeep
                            } else {
                                Operation::PackRef
                            },
                            vec![*idx],
                            None,
                        ));
                    }
                }
                // Generate write_back for this reference.
                for (parent, edge_dom_ele) in before.get_incoming(&node) {
                    match edge_dom_ele {
                        EdgeDomain::Top => instrumented_bytecodes.push(Bytecode::Call(
                            self.clone_attr(attr_id),
                            vec![],
                            Operation::WriteBack(parent.clone(), BorrowEdge::Weak),
                            vec![*idx],
                            None,
                        )),
                        EdgeDomain::EdgeSet(edges) => {
                            for edge in edges {
                                instrumented_bytecodes.push(Bytecode::Call(
                                    self.clone_attr(attr_id),
                                    vec![],
                                    Operation::WriteBack(parent.clone(), BorrowEdge::Strong(edge)),
                                    vec![*idx],
                                    None,
                                ))
                            }
                        }
                    }
                }
            }
        }
        instrumented_bytecodes
    }
}
<commit_msg>[move-prover] replacing plus func to avoid overflow<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    borrow_analysis_v2::{BorrowAnnotation, EdgeDomain},
    function_target::{FunctionData, FunctionTarget},
    function_target_pipeline::{FunctionTargetProcessor, FunctionTargetsHolder},
    stackless_bytecode::{
        AttrId, BorrowEdge, BorrowNode,
        Bytecode::{self, *},
        Operation,
    },
};
use move_model::{
    ast::{ConditionKind, TempIndex},
    model::{FunctionEnv, Loc, StructEnv},
    ty::Type,
};
use std::collections::BTreeMap;
use vm::file_format::CodeOffset;

pub struct MemoryInstrumentationProcessor {}

impl MemoryInstrumentationProcessor {
    pub fn new() -> Box<Self> {
        Box::new(MemoryInstrumentationProcessor {})
    }
}

impl FunctionTargetProcessor for MemoryInstrumentationProcessor {
    fn process(
        &self,
        _targets: &mut FunctionTargetsHolder,
        func_env: &FunctionEnv<'_>,
        mut data: FunctionData,
    ) -> FunctionData {
        if func_env.is_native() {
            return data;
        }
        let borrow_annotation = data
            .annotations
            .remove::<BorrowAnnotation>()
            .expect("borrow annotation");
        let next_attr_id = data.next_free_attr_index();
        let code = std::mem::take(&mut data.code);
        let func_target = FunctionTarget::new(func_env, &data);
        let mut instrumenter = Instrumenter::new(&func_target, &borrow_annotation, next_attr_id);
        let mut new_code = vec![];
        for (code_offset, bytecode) in code.into_iter().enumerate() {
            let (before, after) =
                instrumenter.compute_instrumentation(code_offset as CodeOffset, &bytecode);
            new_code.extend(before);
            new_code.push(bytecode);
            new_code.extend(after);
        }
        let new_locations = std::mem::take(&mut instrumenter.new_locations);
        data.code = new_code;
        data.locations.extend(new_locations.into_iter());
        data
    }

    fn name(&self) -> String {
        "memory_instr".to_string()
    }
}

struct Instrumenter<'a> {
    func_target: &'a FunctionTarget<'a>,
    borrow_annotation: &'a BorrowAnnotation,
    next_attr_id: usize,
    new_locations: BTreeMap<AttrId, Loc>,
}

impl<'a> Instrumenter<'a> {
    fn new(
        func_target: &'a FunctionTarget<'a>,
        borrow_annotation: &'a BorrowAnnotation,
        next_attr_id: usize,
    ) -> Self {
        Self {
            func_target,
            borrow_annotation,
            next_attr_id,
            new_locations: BTreeMap::new(),
        }
    }

    fn compute_instrumentation(
        &mut self,
        code_offset: CodeOffset,
        bytecode: &Bytecode,
    ) -> (Vec<Bytecode>, Vec<Bytecode>) {
        let (mut before, mut after) = self.public_function_instrumentation(code_offset, bytecode);
        let destroy_instr = self.ref_create_destroy_instrumentation(code_offset, bytecode);
        if matches!(
            bytecode,
            Bytecode::Ret(..) | Bytecode::Branch(..) | Bytecode::Jump(..) | Bytecode::Abort(..)
        ) {
            // Add this to before instrumentation.
            before.extend(destroy_instr);
        } else {
            after.extend(destroy_instr);
        }
        (before, after)
    }

    fn public_function_instrumentation(
        &mut self,
        _code_offset: CodeOffset,
        bytecode: &Bytecode,
    ) -> (Vec<Bytecode>, Vec<Bytecode>) {
        let mut before = vec![];
        let mut after = vec![];
        if let Call(attr_id, _, Operation::Function(mid, fid, _), srcs, _) = bytecode {
            let callee_env = self
                .func_target
                .module_env()
                .env
                .get_module(*mid)
                .into_function(*fid);
            if callee_env.is_public() {
                let pack_refs: Vec<&TempIndex> = srcs
                    .iter()
                    .filter(|idx| self.is_pack_ref_ty(self.func_target.get_local_type(**idx)))
                    .collect();
                before.append(
                    &mut pack_refs
                        .iter()
                        .map(|idx| {
                            Bytecode::Call(
                                self.clone_attr(*attr_id),
                                vec![],
                                Operation::PackRef,
                                vec![**idx],
                                None,
                            )
                        })
                        .collect(),
                );
                after.append(
                    &mut pack_refs
                        .into_iter()
                        .map(|idx| {
                            Bytecode::Call(
                                self.clone_attr(*attr_id),
                                vec![],
                                Operation::UnpackRef,
                                vec![*idx],
                                None,
                            )
                        })
                        .collect(),
                );
            }
        }
        (before, after)
    }

    /// Determines whether the type needs a pack ref.
    fn is_pack_ref_ty(&self, ty: &Type) -> bool {
        let env = self.func_target.global_env();
        if let Some((struct_env, _)) = ty.skip_reference().get_struct(env) {
            self.is_pack_ref_struct(&struct_env)
        } else {
            // TODO: vectors
            false
        }
    }

    /// Determines whether the struct needs a pack ref.
    fn is_pack_ref_struct(&self, struct_env: &StructEnv<'_>) -> bool {
        use ConditionKind::*;
        struct_env.get_spec().any(|c| matches!(c.kind, VarUpdate(..)|VarPack(..)|Invariant))
        // If any of the fields has it, it inherits to the struct.
        ||  struct_env
            .get_fields()
            .any(|fe| self.is_pack_ref_ty(&fe.get_type()))
    }

    fn new_attr_id(&mut self, loc: Loc) -> AttrId {
        let attr_id = AttrId::new(self.next_attr_id);
        self.next_attr_id = usize::saturating_add(self.next_attr_id, 1);
        self.new_locations.insert(attr_id, loc);
        attr_id
    }

    fn clone_attr(&mut self, id: AttrId) -> AttrId {
        let loc = self.func_target.get_bytecode_loc(id);
        self.new_attr_id(loc)
    }

    fn ref_create_destroy_instrumentation(
        &mut self,
        code_offset: CodeOffset,
        bytecode: &Bytecode,
    ) -> Vec<Bytecode> {
        let borrow_annotation_at = self
            .borrow_annotation
            .get_borrow_info_at(code_offset)
            .unwrap();
        let before = &borrow_annotation_at.before;
        let after = &borrow_annotation_at.after;

        let mut instrumented_bytecodes = vec![];

        // Generate UnpackRef from Borrow instructions.
        if let Call(attr_id, dests, op, _, _) = bytecode {
            use Operation::*;
            match op {
                BorrowLoc | BorrowField(..) | BorrowGlobal(..) => {
                    let ty = self.func_target.get_local_type(dests[0]);
                    let node = BorrowNode::Reference(dests[0]);
                    if self.is_pack_ref_ty(ty)
                        && after.is_in_use(&node)
                        && !after.is_unchecked(&node)
                    {
                        instrumented_bytecodes.push(Bytecode::Call(
                            self.clone_attr(*attr_id),
                            vec![],
                            if after.is_spliced(&node) {
                                Operation::UnpackRefDeep
                            } else {
                                Operation::UnpackRef
                            },
                            vec![dests[0]],
                            None,
                        ));
                    }
                }
                _ => {}
            }
        }

        // Generate PackRef for nodes which go out of scope, as well as generate WriteBack.
        let attr_id = bytecode.get_attr_id();
        for node in before.dying_nodes(after) {
            if let BorrowNode::Reference(idx) = &node {
                let ty = self.func_target.get_local_type(*idx);
                if self.is_pack_ref_ty(ty) {
                    // Generate a pack_ref for this reference, unless: (a) the node is marked
                    // as unchecked (b) the node is marked as having been moved to somewhere else.
                    if !before.is_unchecked(&node) && !before.is_moved(&node) {
                        instrumented_bytecodes.push(Bytecode::Call(
                            self.clone_attr(attr_id),
                            vec![],
                            if before.is_spliced(&node) {
                                // If this node has been spliced, we need to perform a deep pack.
                                // A spliced node is one which has a child at some unknown,
                                // dynamically defined path, derived by some function from the parent.
                                // The nodes on this path have not been packed yet, and we therefore
                                // need to do a deep pack.
                                Operation::PackRefDeep
                            } else {
                                Operation::PackRef
                            },
                            vec![*idx],
                            None,
                        ));
                    }
                }
                // Generate write_back for this reference.
                for (parent, edge_dom_ele) in before.get_incoming(&node) {
                    match edge_dom_ele {
                        EdgeDomain::Top => instrumented_bytecodes.push(Bytecode::Call(
                            self.clone_attr(attr_id),
                            vec![],
                            Operation::WriteBack(parent.clone(), BorrowEdge::Weak),
                            vec![*idx],
                            None,
                        )),
                        EdgeDomain::EdgeSet(edges) => {
                            for edge in edges {
                                instrumented_bytecodes.push(Bytecode::Call(
                                    self.clone_attr(attr_id),
                                    vec![],
                                    Operation::WriteBack(parent.clone(), BorrowEdge::Strong(edge)),
                                    vec![*idx],
                                    None,
                                ))
                            }
                        }
                    }
                }
            }
        }
        instrumented_bytecodes
    }
}
<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (eliza@elizas.website)
//
//  Copyright (c) 2015-2017 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! # SOS VGA
//! Code for interacting with the system's VGA buffer.
//!
//! # Features
//! This crate exposes the following feature flags:
//! + `system_term`: Use the VGA buffer as the system terminal. This provides
//!   implementations of the `print!` and `println!` macros.
//! + `log`: provides a `log!` macro for kernel log messages.
#![crate_name = "vga"]
#![crate_type = "lib"]
#![feature( slice_patterns
          , unique )]
#![feature( const_fn
          , const_unique_new )]
#![cfg_attr(feature = "system_term", feature(lang_items))]
#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]
#![no_std]

#[cfg(feature = "system_term")]
extern crate spin;

use core::{mem, ptr};
use core::fmt::{Write, Result};
// use core::ptr::Unique;

#[cfg(feature = "system_term")]
use spin::Mutex;
#[cfg(feature = "kinfo")]
#[macro_use] extern crate log;

#[cfg(all( feature = "system_term"
          , not(test)))]
pub mod panic;

/// Macro for printing to the standard output.
///
/// Equivalent to the `println!` macro except that a newline is not printed at
/// the end of the message.
///
/// # Panics
///
/// Panics if writing to the VGA console fails.
///
#[cfg(feature = "system_term")]
#[macro_export]
macro_rules! println {
    ($fmt:expr) => (print!(concat!($fmt, "\n")));
    ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*));
}

/// Macro for printing to the standard output.
///
/// Equivalent to the `println!` macro except that a newline is not printed at
/// the end of the message.
///
/// # Panics
///
/// Panics if writing to the VGA console fails.
#[cfg(feature = "system_term")]
#[macro_export]
macro_rules! print {
    ($($arg:tt)*) => ({
            use core::fmt::Write;
            $crate::CONSOLE.lock()
                           .write_fmt(format_args!($($arg)*))
                           .unwrap();
    });
}

#[cfg(feature = "kinfo")]
#[macro_use] pub mod kinfo;
pub mod status;

/// The system's global VGA terminal
/// TODO: should this live in the kernel instead?
#[cfg(feature = "system_term")]
pub static CONSOLE: Mutex<Terminal>
    = Mutex::new(unsafe { Terminal::new(
         Palette::new(Color::LightGrey, Color::Black )
       , 0xB8000
    )});

// TODO: support varying VGA screen sizes?
pub const X_MAX: usize = 80;
pub const Y_MAX: usize = 25;

/// The type signature fot the actual VGA buffer
pub type Buffer = [[Char; X_MAX]; Y_MAX];

const ANSI_ESCAPE: &'static str = "\x1b";
const FG_MASK: u8 = 0b0000_1111;
const BG_MASK: u8 = 0b1111_0000;

/// VGA color codes
#[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone)]
#[repr(u8)]
pub enum Color { Black = 0
               , Blue = 1
               , Green = 2
               , Cyan = 3
               , Red = 4
               , Magenta = 5
               , Brown = 6
               , LightGrey = 7
               , DarkGrey = 8
               , LightBlue = 9
               , LightGreen = 10
               , LightCyan = 11
               , LightRed = 12
               , LightMagenta = 13
               , Yellow = 14
               , White = 15
               }

#[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone)]
pub struct Palette(u8);

impl Palette {
    /// Returns a `Palette` with the given foreground and background color.
    pub const fn new(fg: Color, bg: Color) -> Self {
        Palette( (bg as u8) << 4 | (fg as u8) )
    }

    /// Returns a new `Palette` with this palette's background color, and
    /// the specified foreground color.
    pub fn set_foreground(&self, fg: Color) -> Self {
        Palette( ( self.0 & BG_MASK) | (fg as u8 & FG_MASK) )
    }

    /// Returns a new `Palette` with this palette's foreground color, and
    /// the specified background color.
    pub fn set_background(&self, bg: Color) -> Self {
        Palette( ( (bg as u8) << 4 & BG_MASK) | (self.0 & FG_MASK) )
    }

    /// Returns this `Palette`'s foreground color.
    pub fn foreground(&self) -> Color {
        unsafe { mem::transmute(self.0 & FG_MASK) }
    }

    /// Returns this `Palette`'s background color.
    pub fn background(&self) -> Color {
        unsafe { mem::transmute((self.0 & BG_MASK) >> 4) }
    }

}
/// A colored VGA character.
#[derive(Copy, Clone)]
#[repr(C)]
pub struct Char { pub ascii: u8
                , pub colors: Palette
                }

impl Char {
    #[inline(always)]
    pub const fn empty() -> Self {
        Char { ascii: 0, colors: Palette(0) }
    }
}

pub struct Terminal { buffer: ptr::Unique<Buffer>
                    , x: usize
                    , y: usize
                    , colors: Palette
                    }
impl Terminal {

    #[inline]
    pub fn x_position(&self) -> usize {
        self.x
    }

    /// Constructs a new `Terminal` for abuffer starting at the given address.
    ///
    /// # Arguments
    /// + `colors`: the default color palette for the terminal
    /// + `buffer_start`: the address of the to the memory location where
    ///                   the terminal's VGA buffer begins
    ///
    /// # Unsafe due to:
    /// + Casting a raw address to an array
    /// + Constructing a `ptr::Unique` from an unchecked mut pointer.
    pub const unsafe fn new( colors: Palette
                           , buffer_start: usize)
                            -> Terminal {
        Terminal { x: 0, y: 0
                 , colors
                    // TODO: this probably shouldn't be unchecked, but this
                    //  can't be a const fn otherwise...
                 , buffer: ptr::Unique::new_unchecked(buffer_start as *mut _)
                 }
    }

    #[inline]
    fn buffer(&mut self) -> &mut  Buffer {
        unsafe { self.buffer.as_mut() }
    }

    /// Set the color palette used for writing subsequent characters.
    pub fn set_colors(&mut self, bg: Color, fg: Color) -> &mut Self {
        self.colors = Palette::new(bg,fg);
        self
    }

    /// Scrolls the terminal one row.
    fn scroll(&mut self) {
        // // construct an iterator over the whole buffer
        // let mut rows = self.buffer()
        //                    .iter_mut();
        //
        // // the current row in the buffer
        // let mut current = rows.next()
        //                    .unwrap();
        //
        // while let Some(next) = rows.next() {
        //     // while there are rows remaining in the iterator, swap the
        //     // next row with the current one (moving it back by one)
        //     mem::swap(current, next);
        //     // and advance our pointer to the current row.
        //     current = next;
        // }
        let buffer: &mut _ = self.buffer();
        for row in 1..Y_MAX {
            for col in 0 .. X_MAX {
                unsafe {
                    let last = ptr::read_volatile(&buffer[row][col]);
                    ptr::write_volatile( &mut buffer[row - 1][col], last);
                }
            }
        }
        // empty the last line in the buffer
        unsafe {
            for col in 0..X_MAX {
                ptr::write_volatile(&mut buffer[Y_MAX - 1][col], Char::empty());
            }
        }
    }

    /// Clear the terminal
    #[inline]
    pub fn clear(&mut self) -> &mut Self {
        // to clear the terminal, we just zero out the whole buffer.
        {
            let buffer: &mut _ =self.buffer();
            for row in 0..Y_MAX {
                for col in 0 .. X_MAX {
                    unsafe {
                        ptr::write_volatile(
                            &mut buffer[row][col], Char::empty()
                        );
                    }
                }
            }
        }

        self.x = 0;
        self.y = 0;
        self
    }

    /// Write the given byte to the terminal, and advance the cursor position.
    pub fn write_byte(&mut self, byte: u8) -> &mut Self {
        if byte == b'\n' {
            // if the byte is a newline, we just advance to the next line
            // and reset the column position.
            self.x = 0;
            self.y += 1;
        } else {
            // otherwise, it's a regular character, so we just set the
            // byte at the current position in the buffer to that
            // character (with the current color palette)
            //
            let y = self.y;
            let x = self.x;
            unsafe {
                ptr::write_volatile( &mut (self.buffer()[y][x])
                                   , Char { ascii: byte, colors: self.colors }
                                   );
            }
            // and advance our column position by one
            self.x += 1;

            if self.x >= X_MAX {
                // if we've reached the end of the line, advance to the next
                self.x = 0;
                self.y += 1;
            }
        }
        if self.y >= Y_MAX {
            // if we've reached the bottom of the terminal, scroll.
            self.scroll();
            self.y -= 1;
        }
        self
    }

    fn handle_ansi_escape(&self, escape_code: &str) -> Result {
        match escape_code.as_bytes() {
            // `\x1b[3Nm` sets the foreground color to N.
            &[0x1b, b'[', b'3', n, b'm'] => {
                unsafe { self.colors
                             .set_foreground(mem::transmute(n - 48)); }
                Ok(())
            }
            // `\x1b[4Nm` sets the background color to N
          , &[0x1b, b'[', b'4', n, b'm'] => {
                unsafe { self.colors
                             .set_background(mem::transmute(n - 48)); }
                Ok(())
            }
          , _ => unimplemented!()
        }
        // let escape_seq: &str = bytes.take_while(|b| b != b'm')
        //                       .collect::<&str>();
        // match escape_seq {
        //     [b'3', n] => unsafe {
        //         self.colors.set_foreground(mem::transmute(n - 48))
        //     }
        // }
        // while let Some(byte) = bytes.next() {
        //     match *byte {
        //         // we've recieved an ANSI escape sequence.
        //         // this basically enters a mediocre FSM for matching ANSI
        //         // control codes.
        //         0x1b => match *next_ansi_byte!(bytes) {
        //             // handle multi-char ANSI escapes
        //             b'[' => match *next_ansi_byte!(bytes) {
        //                 // foreground color code
        //                 fg @ 30 ... 37 => {
        //                     if !(*next_ansi_byte!(bytes) == b'm') {
        //                         unsafe {
        //                             let color: vga::Color
        //                                 = mem::transmute(fg - 30);
        //                             self.colors
        //                                 .set_foreground(color);
        //                         }
        //
        //                     }
        //                 }
        //                 // background color code
        //               , 40 ... 47 => {
        //
        //                 }
        //               , _ => unimplemented!()
        //             }
        //           , _    => unimplemented!()
        //         }
        //         // otherwise, treat the byte as a normal ASCII char
        //       , b => { self.write_byte(b); }
        //     }
        // }

    }

}

struct AnsiEscapeIter<'a> { curr_slice: &'a str
                          , in_escape: bool
                          }

impl<'a> AnsiEscapeIter<'a> {

    pub fn new(s: &'a str) -> Self {
        AnsiEscapeIter { curr_slice: s
                       , in_escape: false
                       }
    }
}

impl<'a> Iterator for AnsiEscapeIter<'a> {
    type Item = &'a str;

    fn next(&mut self) -> Option<Self::Item> {
        if self.curr_slice.len() == 0 {
            // if the remaining string is empty, we just return `None`
            None
        } else {
            // otherwise, find the next index to chunk on.
            let maybe_idx
                = if self.in_escape {
                     // if we're in an escape code, we split the chunk at the
                     // index of the next 'm' character, adding 1 so that the
                     // 'm' is in the escape code chunk.
                    self.curr_slice.find('m')
                        .map(|idx| idx + 1)
                } else {
                    // otherwise, split at the next ANSI escape sequence
                    self.curr_slice.find(ANSI_ESCAPE)
                };

            // if we found another index to chunk on, map over that index;
            // otherwise, we just yield the rest of the string
            maybe_idx.map_or(
                Some(self.curr_slice) // remainder (if no index to chunk on)
              , |idx| { // otherwise, chunk along that index...
                    let (chunk, next_slice) = self.curr_slice
                                                  .split_at(idx);
                    self.curr_slice = next_slice; // update current chunk
                    Some(chunk)                   // return the chunk
                })
        }

    }
}

impl Write for Terminal {

    fn write_str(&mut self, s: &str) -> Result {

        if s.contains(ANSI_ESCAPE) {
            // if the segment contains an ANSI escape, construct an iterator
            // over each chunk containing either an escape sequence or text
            for segment in AnsiEscapeIter::new(s) {
                if segment.starts_with(ANSI_ESCAPE) {
                    // if the current segment is an ANSI escape code,
                    // try to handle the escape and fail if it is malformed
                    self.handle_ansi_escape(segment)?
                } else {
                    // otherwise, just write each chunk in the string.
                    for byte in segment.as_bytes() {
                        self.write_byte(*byte);
                    }
                }
            }
        } else {
            // otherwise, if there are no ANSI escape codes,
            // we can just write each byte in the string.
            for byte in s.as_bytes() {
                self.write_byte(*byte);
            }
        }
        Ok(())
    }

}
<commit_msg>fix(vga): temporary fix for #111<commit_after>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (eliza@elizas.website)
//
//  Copyright (c) 2015-2017 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! # SOS VGA
//! Code for interacting with the system's VGA buffer.
//!
//! # Features
//! This crate exposes the following feature flags:
//! + `system_term`: Use the VGA buffer as the system terminal. This provides
//!   implementations of the `print!` and `println!` macros.
//! + `log`: provides a `log!` macro for kernel log messages.
#![crate_name = "vga"]
#![crate_type = "lib"]
#![feature( slice_patterns
          , unique )]
#![feature(ptr_internals)]
#![feature( const_fn
          , const_unique_new )]
#![cfg_attr(feature = "system_term", feature(lang_items))]
#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]
#![no_std]

#[cfg(feature = "system_term")]
extern crate spin;

use core::{mem, ptr};
use core::fmt::{Write, Result};
// use core::ptr::Unique;

#[cfg(feature = "system_term")]
use spin::Mutex;
#[cfg(feature = "kinfo")]
#[macro_use] extern crate log;

#[cfg(all( feature = "system_term"
          , not(test)))]
pub mod panic;

/// Macro for printing to the standard output.
///
/// Equivalent to the `println!` macro except that a newline is not printed at
/// the end of the message.
///
/// # Panics
///
/// Panics if writing to the VGA console fails.
///
#[cfg(feature = "system_term")]
#[macro_export]
macro_rules! println {
    ($fmt:expr) => (print!(concat!($fmt, "\n")));
    ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*));
}

/// Macro for printing to the standard output.
///
/// Equivalent to the `println!` macro except that a newline is not printed at
/// the end of the message.
///
/// # Panics
///
/// Panics if writing to the VGA console fails.
#[cfg(feature = "system_term")]
#[macro_export]
macro_rules! print {
    ($($arg:tt)*) => ({
            use core::fmt::Write;
            $crate::CONSOLE.lock()
                           .write_fmt(format_args!($($arg)*))
                           .unwrap();
    });
}

#[cfg(feature = "kinfo")]
#[macro_use] pub mod kinfo;
pub mod status;

/// The system's global VGA terminal
/// TODO: should this live in the kernel instead?
#[cfg(feature = "system_term")]
pub static CONSOLE: Mutex<Terminal>
    = Mutex::new(unsafe { Terminal::new(
         Palette::new(Color::LightGrey, Color::Black )
       , 0xB8000
    )});

// TODO: support varying VGA screen sizes?
pub const X_MAX: usize = 80;
pub const Y_MAX: usize = 25;

/// The type signature fot the actual VGA buffer
pub type Buffer = [[Char; X_MAX]; Y_MAX];

const ANSI_ESCAPE: &'static str = "\x1b";
const FG_MASK: u8 = 0b0000_1111;
const BG_MASK: u8 = 0b1111_0000;

/// VGA color codes
#[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone)]
#[repr(u8)]
pub enum Color { Black = 0
               , Blue = 1
               , Green = 2
               , Cyan = 3
               , Red = 4
               , Magenta = 5
               , Brown = 6
               , LightGrey = 7
               , DarkGrey = 8
               , LightBlue = 9
               , LightGreen = 10
               , LightCyan = 11
               , LightRed = 12
               , LightMagenta = 13
               , Yellow = 14
               , White = 15
               }

#[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone)]
pub struct Palette(u8);

impl Palette {
    /// Returns a `Palette` with the given foreground and background color.
    pub const fn new(fg: Color, bg: Color) -> Self {
        Palette( (bg as u8) << 4 | (fg as u8) )
    }

    /// Returns a new `Palette` with this palette's background color, and
    /// the specified foreground color.
    pub fn set_foreground(&self, fg: Color) -> Self {
        Palette( ( self.0 & BG_MASK) | (fg as u8 & FG_MASK) )
    }

    /// Returns a new `Palette` with this palette's foreground color, and
    /// the specified background color.
    pub fn set_background(&self, bg: Color) -> Self {
        Palette( ( (bg as u8) << 4 & BG_MASK) | (self.0 & FG_MASK) )
    }

    /// Returns this `Palette`'s foreground color.
    pub fn foreground(&self) -> Color {
        unsafe { mem::transmute(self.0 & FG_MASK) }
    }

    /// Returns this `Palette`'s background color.
    pub fn background(&self) -> Color {
        unsafe { mem::transmute((self.0 & BG_MASK) >> 4) }
    }

}
/// A colored VGA character.
#[derive(Copy, Clone)]
#[repr(C)]
pub struct Char { pub ascii: u8
                , pub colors: Palette
                }

impl Char {
    #[inline(always)]
    pub const fn empty() -> Self {
        Char { ascii: 0, colors: Palette(0) }
    }
}

pub struct Terminal { buffer: ptr::Unique<Buffer>
                    , x: usize
                    , y: usize
                    , colors: Palette
                    }
impl Terminal {

    #[inline]
    pub fn x_position(&self) -> usize {
        self.x
    }

    /// Constructs a new `Terminal` for abuffer starting at the given address.
    ///
    /// # Arguments
    /// + `colors`: the default color palette for the terminal
    /// + `buffer_start`: the address of the to the memory location where
    ///                   the terminal's VGA buffer begins
    ///
    /// # Unsafe due to:
    /// + Casting a raw address to an array
    /// + Constructing a `ptr::Unique` from an unchecked mut pointer.
    pub const unsafe fn new( colors: Palette
                           , buffer_start: usize)
                            -> Terminal {
        Terminal { x: 0, y: 0
                 , colors
                    // TODO: this probably shouldn't be unchecked, but this
                    //  can't be a const fn otherwise...
                 , buffer: ptr::Unique::new_unchecked(buffer_start as *mut _)
                 }
    }

    #[inline]
    fn buffer(&mut self) -> &mut  Buffer {
        unsafe { self.buffer.as_mut() }
    }

    /// Set the color palette used for writing subsequent characters.
    pub fn set_colors(&mut self, bg: Color, fg: Color) -> &mut Self {
        self.colors = Palette::new(bg,fg);
        self
    }

    /// Scrolls the terminal one row.
    fn scroll(&mut self) {
        // // construct an iterator over the whole buffer
        // let mut rows = self.buffer()
        //                    .iter_mut();
        //
        // // the current row in the buffer
        // let mut current = rows.next()
        //                    .unwrap();
        //
        // while let Some(next) = rows.next() {
        //     // while there are rows remaining in the iterator, swap the
        //     // next row with the current one (moving it back by one)
        //     mem::swap(current, next);
        //     // and advance our pointer to the current row.
        //     current = next;
        // }
        let buffer: &mut _ = self.buffer();
        for row in 1..Y_MAX {
            for col in 0 .. X_MAX {
                unsafe {
                    let last = ptr::read_volatile(&buffer[row][col]);
                    ptr::write_volatile( &mut buffer[row - 1][col], last);
                }
            }
        }
        // empty the last line in the buffer
        unsafe {
            for col in 0..X_MAX {
                ptr::write_volatile(&mut buffer[Y_MAX - 1][col], Char::empty());
            }
        }
    }

    /// Clear the terminal
    #[inline]
    pub fn clear(&mut self) -> &mut Self {
        // to clear the terminal, we just zero out the whole buffer.
        {
            let buffer: &mut _ =self.buffer();
            for row in 0..Y_MAX {
                for col in 0 .. X_MAX {
                    unsafe {
                        ptr::write_volatile(
                            &mut buffer[row][col], Char::empty()
                        );
                    }
                }
            }
        }

        self.x = 0;
        self.y = 0;
        self
    }

    /// Write the given byte to the terminal, and advance the cursor position.
    pub fn write_byte(&mut self, byte: u8) -> &mut Self {
        if byte == b'\n' {
            // if the byte is a newline, we just advance to the next line
            // and reset the column position.
            self.x = 0;
            self.y += 1;
        } else {
            // otherwise, it's a regular character, so we just set the
            // byte at the current position in the buffer to that
            // character (with the current color palette)
            //
            let y = self.y;
            let x = self.x;
            unsafe {
                ptr::write_volatile( &mut (self.buffer()[y][x])
                                   , Char { ascii: byte, colors: self.colors }
                                   );
            }
            // and advance our column position by one
            self.x += 1;

            if self.x >= X_MAX {
                // if we've reached the end of the line, advance to the next
                self.x = 0;
                self.y += 1;
            }
        }
        if self.y >= Y_MAX {
            // if we've reached the bottom of the terminal, scroll.
            self.scroll();
            self.y -= 1;
        }
        self
    }

    fn handle_ansi_escape(&self, escape_code: &str) -> Result {
        match escape_code.as_bytes() {
            // `\x1b[3Nm` sets the foreground color to N.
            &[0x1b, b'[', b'3', n, b'm'] => {
                unsafe { self.colors
                             .set_foreground(mem::transmute(n - 48)); }
                Ok(())
            }
            // `\x1b[4Nm` sets the background color to N
          , &[0x1b, b'[', b'4', n, b'm'] => {
                unsafe { self.colors
                             .set_background(mem::transmute(n - 48)); }
                Ok(())
            }
          , _ => unimplemented!()
        }
        // let escape_seq: &str = bytes.take_while(|b| b != b'm')
        //                       .collect::<&str>();
        // match escape_seq {
        //     [b'3', n] => unsafe {
        //         self.colors.set_foreground(mem::transmute(n - 48))
        //     }
        // }
        // while let Some(byte) = bytes.next() {
        //     match *byte {
        //         // we've recieved an ANSI escape sequence.
        //         // this basically enters a mediocre FSM for matching ANSI
        //         // control codes.
        //         0x1b => match *next_ansi_byte!(bytes) {
        //             // handle multi-char ANSI escapes
        //             b'[' => match *next_ansi_byte!(bytes) {
        //                 // foreground color code
        //                 fg @ 30 ... 37 => {
        //                     if !(*next_ansi_byte!(bytes) == b'm') {
        //                         unsafe {
        //                             let color: vga::Color
        //                                 = mem::transmute(fg - 30);
        //                             self.colors
        //                                 .set_foreground(color);
        //                         }
        //
        //                     }
        //                 }
        //                 // background color code
        //               , 40 ... 47 => {
        //
        //                 }
        //               , _ => unimplemented!()
        //             }
        //           , _    => unimplemented!()
        //         }
        //         // otherwise, treat the byte as a normal ASCII char
        //       , b => { self.write_byte(b); }
        //     }
        // }

    }

}

struct AnsiEscapeIter<'a> { curr_slice: &'a str
                          , in_escape: bool
                          }

impl<'a> AnsiEscapeIter<'a> {

    pub fn new(s: &'a str) -> Self {
        AnsiEscapeIter { curr_slice: s
                       , in_escape: false
                       }
    }
}

impl<'a> Iterator for AnsiEscapeIter<'a> {
    type Item = &'a str;

    fn next(&mut self) -> Option<Self::Item> {
        if self.curr_slice.len() == 0 {
            // if the remaining string is empty, we just return `None`
            None
        } else {
            // otherwise, find the next index to chunk on.
            let maybe_idx
                = if self.in_escape {
                     // if we're in an escape code, we split the chunk at the
                     // index of the next 'm' character, adding 1 so that the
                     // 'm' is in the escape code chunk.
                    self.curr_slice.find('m')
                        .map(|idx| idx + 1)
                } else {
                    // otherwise, split at the next ANSI escape sequence
                    self.curr_slice.find(ANSI_ESCAPE)
                };

            // if we found another index to chunk on, map over that index;
            // otherwise, we just yield the rest of the string
            maybe_idx.map_or(
                Some(self.curr_slice) // remainder (if no index to chunk on)
              , |idx| { // otherwise, chunk along that index...
                    let (chunk, next_slice) = self.curr_slice
                                                  .split_at(idx);
                    self.curr_slice = next_slice; // update current chunk
                    Some(chunk)                   // return the chunk
                })
        }

    }
}

impl Write for Terminal {

    fn write_str(&mut self, s: &str) -> Result {

        if s.contains(ANSI_ESCAPE) {
            // if the segment contains an ANSI escape, construct an iterator
            // over each chunk containing either an escape sequence or text
            for segment in AnsiEscapeIter::new(s) {
                if segment.starts_with(ANSI_ESCAPE) {
                    // if the current segment is an ANSI escape code,
                    // try to handle the escape and fail if it is malformed
                    self.handle_ansi_escape(segment)?
                } else {
                    // otherwise, just write each chunk in the string.
                    for byte in segment.as_bytes() {
                        self.write_byte(*byte);
                    }
                }
            }
        } else {
            // otherwise, if there are no ANSI escape codes,
            // we can just write each byte in the string.
            for byte in s.as_bytes() {
                self.write_byte(*byte);
            }
        }
        Ok(())
    }

}
<|endoftext|>