<commit_before>use std::cmp::Ordering::{self, Greater, Less};

#[allow(unsafe_code)]
pub(crate) fn fastcmp(l: &[u8], r: &[u8]) -> Ordering {
    let len = std::cmp::min(l.len(), r.len());
    let cmp = unsafe { libc::memcmp(l.as_ptr() as _, r.as_ptr() as _, len) };
    match cmp {
        a if a > 0 => Greater,
        a if a < 0 => Less,
        _ => l.len().cmp(&r.len()),
    }
}

#[cfg(test)]
mod qc {
    use super::fastcmp;

    fn prop_cmp_matches(l: &[u8], r: &[u8]) -> bool {
        assert_eq!(fastcmp(l, r), l.cmp(r));
        assert_eq!(fastcmp(r, l), r.cmp(l));
        assert_eq!(fastcmp(l, l), l.cmp(l));
        assert_eq!(fastcmp(r, r), r.cmp(r));
        true
    }

    #[test]
    fn test_fastcmp() {
        let cases: [&[u8]; 8] = [
            &[],
            &[0],
            &[1],
            &[1],
            &[255],
            &[1, 2, 3],
            &[1, 2, 3, 0],
            &[1, 2, 3, 55],
        ];
        for pair in cases.windows(2) {
            prop_cmp_matches(pair[0], pair[1]);
        }
    }
    quickcheck::quickcheck! {
        fn qc_fastcmp(l: Vec<u8>, r: Vec<u8>) -> bool {
            println!("{:?}", l);
            prop_cmp_matches(&l, &r)
        }
    }
}
<commit_msg>remove print statement in qc test<commit_after>use std::cmp::Ordering::{self, Greater, Less};

#[allow(unsafe_code)]
pub(crate) fn fastcmp(l: &[u8], r: &[u8]) -> Ordering {
    let len = std::cmp::min(l.len(), r.len());
    let cmp = unsafe { libc::memcmp(l.as_ptr() as _, r.as_ptr() as _, len) };
    match cmp {
        a if a > 0 => Greater,
        a if a < 0 => Less,
        _ => l.len().cmp(&r.len()),
    }
}

#[cfg(test)]
mod qc {
    use super::fastcmp;

    fn prop_cmp_matches(l: &[u8], r: &[u8]) -> bool {
        assert_eq!(fastcmp(l, r), l.cmp(r));
        assert_eq!(fastcmp(r, l), r.cmp(l));
        assert_eq!(fastcmp(l, l), l.cmp(l));
        assert_eq!(fastcmp(r, r), r.cmp(r));
        true
    }

    #[test]
    fn test_fastcmp() {
        let cases: [&[u8]; 8] = [
            &[],
            &[0],
            &[1],
            &[1],
            &[255],
            &[1, 2, 3],
            &[1, 2, 3, 0],
            &[1, 2, 3, 55],
        ];
        for pair in cases.windows(2) {
            prop_cmp_matches(pair[0], pair[1]);
        }
    }
    quickcheck::quickcheck! {
        fn qc_fastcmp(l: Vec<u8>, r: Vec<u8>) -> bool {
            prop_cmp_matches(&l, &r)
        }
    }
}
<|endoftext|>


<commit_before>use super::palette::PaletteColor;

/// The GameBoyColor-specific GPU register addresses.
pub mod regs {
    pub const VRAM_BANK : usize = 0xFF4F;
    /// Register defining the index of the palette to read/write from 'BGP_DATA'.
    pub const BGP_INDEX : usize = 0xFF68;
    /// Adress from where the background palette of index defined at 'BGP_INDEX'
    /// can be read/modified.
    pub const BGP_DATA  : usize = 0xFF69;
    pub const OBP_INDEX : usize = 0xFF6A;
    pub const OBP_DATA  : usize = 0xFF6B;
}

/// Defines a palette register index (or specification) as following:
/// bit 0   : if 1, read/modify the high byte of the palette color
/// bit 1-2 : number of the color to modify in the palette (0-3)
/// bit 3-5 : index (00-3F)
/// bit 7   : auto increment enabled if 1, else disabled
pub struct PaletteIndexRegister {
    /// The raw value of the index register.
    raw_value: u8,
    /// The index of the palette to read/modify (0-7).
    palette_index: usize,
    /// The number of the color to modify (0-3).
    palette_color_number: usize,
    /// If true, read/write the high byte of a 'PaletteColorValue',
    /// otherwise read/write the low byte.
    high_byte: bool,
    /// If true, automatically increment the palette index after each write
    /// to the 'BGP_DATA' address. Reading has no effect
    auto_increment: bool,
}

impl PaletteIndexRegister {
    pub fn new(raw_value: u8) -> PaletteIndexRegister {
        let mut new_index = PaletteIndexRegister {
            raw_value: 0x00,
            palette_index: 0,
            palette_color_number: 0,
            high_byte: false,
            auto_increment: false,
        };
        new_index.update_with(raw_value);
        new_index
    }

    pub fn raw_value(&self) -> u8 { return self.raw_value }
    pub fn high_byte(&self) -> bool { return self.high_byte }
    pub fn index(&self) -> usize { return self.palette_index }
    pub fn color_index(&self) -> usize { return self.palette_color_number }

    /// Set the register new raw value and update its state to match it.
    pub fn update_with(&mut self, value: u8) {
        self.raw_value = value;
        self.high_byte = (value & 0x01) == 0x01;
        self.palette_color_number = ((value & 0x06) >> 1) as usize;
        self.palette_index = ((value & 0x38) >> 3) as usize;
        self.auto_increment = (value & 0x80) == 0x80;
    }

    /// Must be called every time the associated palette data register is written
    /// to. If auto-increment is set to true (bit 7 = 1), increment the index.
    pub fn auto_increment(&mut self) {
        if self.auto_increment {
            let new_value = self.raw_value+1;
            self.update_with(new_value);
        }
    }
}

/// GameBoyColor-specific GPU data. This allows to eventually save on memory
/// when in classic mode (using an 'Option' typically).
pub struct GpuData {
    /// The background palette index register.
    pub bg_palette_index: PaletteIndexRegister,
    /// The 8 background palettes.
    pub bg_palettes: [PaletteColor; 8],
    /// The object palette index register.
    pub ob_palette_index: PaletteIndexRegister,
    /// The 8 object palettes.
    pub ob_palettes: [PaletteColor; 8],
}

impl GpuData {
    pub fn new() -> GpuData {
        GpuData {
            bg_palette_index: PaletteIndexRegister::new(0x00),
            bg_palettes: [PaletteColor::new(); 8],
            ob_palette_index: PaletteIndexRegister::new(0x00),
            ob_palettes: [PaletteColor::new(); 8],
        }
    }

    /// Get the byte value in the background palette according to the
    /// specifications of the background palette index.
    pub fn get_bg_color(&self) -> u8 {
        let palette = self.bg_palettes[self.bg_palette_index.index()].data();
        if self.bg_palette_index.high_byte() {
            palette[self.bg_palette_index.color_index()].raw_high()
        } else {
            palette[self.bg_palette_index.color_index()].raw_low()
        }
    }
    /// Set the byte value in the background palette according to the
    /// specifications of the background palette index.
    pub fn set_bg_color(&mut self, byte: u8) {
        let palette = self.bg_palettes[self.bg_palette_index.index()].data_mut();
        if self.bg_palette_index.high_byte() {
            palette[self.bg_palette_index.color_index()].set_high(byte);
        } else {
            palette[self.bg_palette_index.color_index()].set_low(byte);
        }
        self.bg_palette_index.auto_increment();
    }

    /// Get the byte value in the object palette according to the
    /// specifications of the object palette index.
    pub fn get_ob_color(&self) -> u8 {
        let palette = self.bg_palettes[self.bg_palette_index.index()].data();
        if self.bg_palette_index.high_byte() {
            palette[self.bg_palette_index.color_index()].raw_high()
        } else {
            palette[self.bg_palette_index.color_index()].raw_low()
        }
    }
    /// Set the byte value in the object palette according to the
    /// specifications of the object palette index.
    pub fn set_ob_color(&mut self, byte: u8) {
        let palette = self.ob_palettes[self.ob_palette_index.index()].data_mut();
        if self.ob_palette_index.high_byte() {
            palette[self.ob_palette_index.color_index()].set_high(byte);
        } else {
            palette[self.ob_palette_index.color_index()].set_low(byte);
        }
        self.ob_palette_index.auto_increment();
    }
}
<commit_msg>Added simple unit test for 'PaletteIndexRegister'<commit_after>use super::palette::PaletteColor;

/// The GameBoyColor-specific GPU register addresses.
pub mod regs {
    pub const VRAM_BANK : usize = 0xFF4F;
    /// Register defining the index of the palette to read/write from 'BGP_DATA'.
    pub const BGP_INDEX : usize = 0xFF68;
    /// Adress from where the background palette of index defined at 'BGP_INDEX'
    /// can be read/modified.
    pub const BGP_DATA  : usize = 0xFF69;
    pub const OBP_INDEX : usize = 0xFF6A;
    pub const OBP_DATA  : usize = 0xFF6B;
}

/// Defines a palette register index (or specification) as following:
/// bit 0   : if 1, read/modify the high byte of the palette color
/// bit 1-2 : number of the color to modify in the palette (0-3)
/// bit 3-5 : index (00-3F)
/// bit 7   : auto increment enabled if 1, else disabled
pub struct PaletteIndexRegister {
    /// The raw value of the index register.
    raw_value: u8,
    /// The index of the palette to read/modify (0-7).
    palette_index: usize,
    /// The number of the color to modify (0-3).
    palette_color_number: usize,
    /// If true, read/write the high byte of a 'PaletteColorValue',
    /// otherwise read/write the low byte.
    high_byte: bool,
    /// If true, automatically increment the palette index after each write
    /// to the 'BGP_DATA' address. Reading has no effect
    auto_increment: bool,
}

impl PaletteIndexRegister {
    pub fn new(raw_value: u8) -> PaletteIndexRegister {
        let mut new_index = PaletteIndexRegister {
            raw_value: 0x00,
            palette_index: 0,
            palette_color_number: 0,
            high_byte: false,
            auto_increment: false,
        };
        new_index.update_with(raw_value);
        new_index
    }

    pub fn raw_value(&self) -> u8 { return self.raw_value }
    pub fn high_byte(&self) -> bool { return self.high_byte }
    pub fn index(&self) -> usize { return self.palette_index }
    pub fn color_index(&self) -> usize { return self.palette_color_number }

    /// Set the register new raw value and update its state to match it.
    pub fn update_with(&mut self, value: u8) {
        self.raw_value = value;
        self.high_byte = (value & 0x01) == 0x01;
        self.palette_color_number = ((value & 0x06) >> 1) as usize;
        self.palette_index = ((value & 0x38) >> 3) as usize;
        self.auto_increment = (value & 0x80) == 0x80;
    }

    /// Must be called every time the associated palette data register is written
    /// to. If auto-increment is set to true (bit 7 = 1), increment the index.
    pub fn auto_increment(&mut self) {
        if self.auto_increment {
            let new_value = self.raw_value+1;
            self.update_with(new_value);
        }
    }
}

/// GameBoyColor-specific GPU data. This allows to eventually save on memory
/// when in classic mode (using an 'Option' typically).
pub struct GpuData {
    /// The background palette index register.
    pub bg_palette_index: PaletteIndexRegister,
    /// The 8 background palettes.
    pub bg_palettes: [PaletteColor; 8],
    /// The object palette index register.
    pub ob_palette_index: PaletteIndexRegister,
    /// The 8 object palettes.
    pub ob_palettes: [PaletteColor; 8],
}

impl GpuData {
    pub fn new() -> GpuData {
        GpuData {
            bg_palette_index: PaletteIndexRegister::new(0x00),
            bg_palettes: [PaletteColor::new(); 8],
            ob_palette_index: PaletteIndexRegister::new(0x00),
            ob_palettes: [PaletteColor::new(); 8],
        }
    }

    /// Get the byte value in the background palette according to the
    /// specifications of the background palette index.
    pub fn get_bg_color(&self) -> u8 {
        let palette = self.bg_palettes[self.bg_palette_index.index()].data();
        if self.bg_palette_index.high_byte() {
            palette[self.bg_palette_index.color_index()].raw_high()
        } else {
            palette[self.bg_palette_index.color_index()].raw_low()
        }
    }
    /// Set the byte value in the background palette according to the
    /// specifications of the background palette index.
    pub fn set_bg_color(&mut self, byte: u8) {
        let palette = self.bg_palettes[self.bg_palette_index.index()].data_mut();
        if self.bg_palette_index.high_byte() {
            palette[self.bg_palette_index.color_index()].set_high(byte);
        } else {
            palette[self.bg_palette_index.color_index()].set_low(byte);
        }
        self.bg_palette_index.auto_increment();
    }

    /// Get the byte value in the object palette according to the
    /// specifications of the object palette index.
    pub fn get_ob_color(&self) -> u8 {
        let palette = self.bg_palettes[self.bg_palette_index.index()].data();
        if self.bg_palette_index.high_byte() {
            palette[self.bg_palette_index.color_index()].raw_high()
        } else {
            palette[self.bg_palette_index.color_index()].raw_low()
        }
    }
    /// Set the byte value in the object palette according to the
    /// specifications of the object palette index.
    pub fn set_ob_color(&mut self, byte: u8) {
        let palette = self.ob_palettes[self.ob_palette_index.index()].data_mut();
        if self.ob_palette_index.high_byte() {
            palette[self.ob_palette_index.color_index()].set_high(byte);
        } else {
            palette[self.ob_palette_index.color_index()].set_low(byte);
        }
        self.ob_palette_index.auto_increment();
    }
}

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

    #[test]
    fn test_PaletteIndexRegister_decoding() {
        let index = PaletteIndexRegister::new(0xAD);
        assert_eq!(index.raw_value(), 0xAD);
        assert_eq!(index.high_byte(), true);
        assert_eq!(index.color_index(), 2);
        assert_eq!(index.index(), 5);
    }
}
<|endoftext|>


<commit_before>// Copyright 2018, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use std::borrow::Borrow;
use std::cmp::Ordering;
use std::ffi::{CStr, CString, OsStr};
use std::fmt;
use std::ops::Deref;
use std::os::raw::c_char;
use std::ptr;
use std::slice;
use std::string::String;
use translate::*;
use types::{StaticType, Type};
use libc;

use gobject_ffi;
use ffi as glib_ffi;
use value::{FromValueOptional, Value, SetValueOptional, SetValue};

#[derive(Debug)]
pub enum GString {
    ForeignOwned(CString),
    Borrowed(*const c_char, usize),
    Owned(*mut c_char, usize)
}

impl GString {
    pub unsafe fn new(ptr: *mut c_char) -> Self {
        assert!(!ptr.is_null());
        GString::Owned(ptr, libc::strlen(ptr))
    }

    pub unsafe fn new_borrowed(ptr: *const c_char) -> Self {
        assert!(!ptr.is_null());
        GString::Borrowed(ptr, libc::strlen(ptr))
    }

    pub fn as_str(&self) -> &str {
        let cstr = match self {
            GString::Borrowed(ptr, length) => unsafe {
                let bytes = slice::from_raw_parts(*ptr as *const u8, length + 1);
                CStr::from_bytes_with_nul_unchecked(bytes)
            }
            GString::Owned(ptr, length) => unsafe {
                let bytes = slice::from_raw_parts(*ptr as *const u8, length + 1);
                CStr::from_bytes_with_nul_unchecked(bytes)
            }
            GString::ForeignOwned(cstring) => {
                cstring.as_c_str()
            }
        };
        cstr.to_str().unwrap()
    }
}

impl Drop for GString {
    fn drop(&mut self) {
        if let GString::Owned(ptr, _len) = self {
            unsafe {
                glib_ffi::g_free(*ptr as *mut _);
            }
        }
    }
}

impl fmt::Display for GString {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.as_str())
    }
}

impl Borrow<str> for GString {
    fn borrow(&self) -> &str {
        self.as_str()
    }
}

impl Ord for GString {
    fn cmp(&self, other: &GString) -> Ordering {
        self.as_str().cmp(other.as_str())
    }
}

impl PartialOrd for GString {
    fn partial_cmp(&self, other: &GString) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl PartialEq for GString {
    fn eq(&self, other: &GString) -> bool {
        self.as_str() == other.as_str()
    }
}

impl PartialEq<GString> for String {
    fn eq(&self, other: &GString) -> bool {
        self.as_str() == other.as_str()
    }
}

impl PartialEq<str> for GString {
    fn eq(&self, other: &str) -> bool {
        self.as_str() == other
    }
}

impl<'a> PartialEq<&'a str> for GString {
    fn eq(&self, other: &&'a str) -> bool {
        self.as_str() == *other
    }
}

impl<'a> PartialEq<GString> for &'a str {
    fn eq(&self, other: &GString) -> bool {
        *self == other.as_str()
    }
}

impl PartialEq<String> for GString {
    fn eq(&self, other: &String) -> bool {
        self.as_str() == other.as_str()
    }
}

impl PartialEq<GString> for str {
    fn eq(&self, other: &GString) -> bool {
        self == other.as_str()
    }
}

impl PartialOrd<GString> for String {
    fn partial_cmp(&self, other: &GString) -> Option<Ordering> {
        Some(self.cmp(&String::from(other.as_str())))
    }
}

impl PartialOrd<String> for GString {
    fn partial_cmp(&self, other: &String) -> Option<Ordering> {
        Some(self.as_str().cmp(other.as_str()))
    }
}

impl PartialOrd<GString> for str {
    fn partial_cmp(&self, other: &GString) -> Option<Ordering> {
        Some(self.cmp(&other))
    }
}

impl PartialOrd<str> for GString {
    fn partial_cmp(&self, other: &str) -> Option<Ordering> {
        Some(self.as_str().cmp(other))
    }
}

impl Eq for GString {}

impl AsRef<str> for GString {
    fn as_ref(&self) -> &str {
        self.as_str()
    }
}

impl AsRef<OsStr> for GString {
    fn as_ref(&self) -> &OsStr {
        OsStr::new(self.as_str())
    }
}

impl Deref for GString {
    type Target = str;

    fn deref(&self) -> &str {
        self.as_str()
    }
}

impl From<GString> for String {
    #[inline]
    fn from(s: GString) -> Self {
        String::from(s.as_str())
    }
}

impl From<GString> for Box<str> {
    #[inline]
    fn from(s: GString) -> Self {
        let st: String = s.into();
        st.into_boxed_str()
    }
}

impl From<String> for GString {
    #[inline]
    fn from(s: String) -> Self {
        s.as_bytes().to_vec().into()
    }
}

impl From<Box<str>> for GString {
    #[inline]
    fn from(s: Box<str>) -> Self {
        s.as_bytes().to_vec().into()
    }
}

impl From<&'static str> for GString {
    #[inline]
    fn from(s: &'static str) -> Self {
        GString::Borrowed(s.as_ptr() as *const c_char, s.len())
    }
}

impl From<Vec<u8>> for GString {
    #[inline]
    fn from(s: Vec<u8>) -> Self {
        let cstring = CString::new(s).expect("CString::new failed");
        cstring.into()
    }
}

impl From<CString> for GString {
    #[inline]
    fn from(s: CString) -> Self {
        GString::ForeignOwned(s)
    }
}

impl<'a> From<&'a CStr> for GString {
    #[inline]
    fn from(c: &'a CStr) -> Self {
        CString::from(c).into()
    }
}

impl FromGlibPtrFull<*const c_char> for GString {
    #[inline]
    unsafe fn from_glib_full(ptr: *const c_char) -> Self {
        GString::new(ptr as *mut _)
    }
}

impl FromGlibPtrFull<*mut u8> for GString {
    #[inline]
    unsafe fn from_glib_full(ptr: *mut u8) -> Self {
        GString::new(ptr as *mut _)
    }
}

impl FromGlibPtrFull<*mut i8> for GString {
    #[inline]
    unsafe fn from_glib_full(ptr: *mut i8) -> Self {
        GString::new(ptr)
    }
}

impl FromGlibPtrNone<*const c_char> for GString {
    #[inline]
    unsafe fn from_glib_none(ptr: *const c_char) -> Self {
        let cstr = CStr::from_ptr(ptr);
        cstr.into()
    }
}

impl FromGlibPtrNone<*mut u8> for GString {
    #[inline]
    unsafe fn from_glib_none(ptr: *mut u8) -> Self {
        let cstr = CStr::from_ptr(ptr as *mut i8);
        cstr.into()
    }
}

impl FromGlibPtrNone<*mut i8> for GString {
    #[inline]
    unsafe fn from_glib_none(ptr: *mut i8) -> Self {
        let cstr = CStr::from_ptr(ptr);
        cstr.into()
    }
}

impl FromGlibPtrBorrow<*const c_char> for GString {
    #[inline]
    unsafe fn from_glib_borrow(ptr: *const c_char) -> Self {
        GString::new_borrowed(ptr)
    }
}

impl FromGlibPtrBorrow<*mut u8> for GString {
    #[inline]
    unsafe fn from_glib_borrow(ptr: *mut u8) -> Self {
        GString::new_borrowed(ptr as *const c_char)
    }
}

impl FromGlibPtrBorrow<*mut i8> for GString {
    #[inline]
    unsafe fn from_glib_borrow(ptr: *mut i8) -> Self {
        GString::new_borrowed(ptr as *const c_char)
    }
}

impl<'a> ToGlibPtr<'a, *const c_char> for GString {
    type Storage = &'a Self;

    #[inline]
    fn to_glib_none(&'a self) -> Stash<'a, *const c_char, Self> {
        Stash(self.as_ptr() as *const _, self)
    }

    #[inline]
    fn to_glib_full(&self) -> *const c_char {
        unsafe {
            glib_ffi::g_strndup(self.as_ptr() as *const c_char, self.len() as libc::size_t)
                as *const c_char
        }
    }
}

impl<'a> ToGlibPtr<'a, *mut c_char> for GString {
    type Storage = &'a Self;

    #[inline]
    fn to_glib_none(&'a self) -> Stash<'a, *mut c_char, Self> {
        Stash(self.as_ptr() as *mut _, self)
    }

    #[inline]
    fn to_glib_full(&self) -> *mut c_char {
        unsafe {
            glib_ffi::g_strndup(self.as_ptr() as *const c_char, self.len() as libc::size_t)
                as *mut c_char
        }
    }
}

impl GlibPtrDefault for GString {
    type GlibType = *const c_char;
}

impl StaticType for GString {
    fn static_type() -> Type {
        String::static_type()
    }
}

impl StaticType for Vec<GString> {
    fn static_type() -> Type {
        unsafe {
            from_glib(glib_ffi::g_strv_get_type())
        }
    }
}

impl<'a> FromValueOptional<'a> for GString {
    unsafe fn from_value_optional(value: &'a Value) -> Option<Self> {
        let val = value.to_glib_none().0;
        if val.is_null() {
            None
        } else {
            let ptr = gobject_ffi::g_value_dup_string(val);
            Some(GString::new(ptr))
        }
    }
}

impl SetValue for GString {
    unsafe fn set_value(value: &mut Value, this: &Self) {
        gobject_ffi::g_value_take_string(value.to_glib_none_mut().0, this.to_glib_full())
    }
}

impl SetValueOptional for GString {
    unsafe fn set_value_optional(value: &mut Value, this: Option<&Self>) {
        gobject_ffi::g_value_take_string(value.to_glib_none_mut().0, this.to_glib_full())
    }
}

impl_from_glib_container_as_vec_string!(GString, *const c_char);
impl_from_glib_container_as_vec_string!(GString, *mut c_char);

#[cfg(test)]
mod tests {
    use gstring::GString;
    use std::ffi::CString;
    use ffi as glib_ffi;

    #[test]
    fn test_gstring() {
        let data = CString::new("foo").unwrap();
        let ptr = data.into_raw();

        unsafe {
            let ptr_copy = glib_ffi::g_strdup(ptr);
            let gstring = GString::new(ptr_copy);
            assert_eq!(gstring.as_str(), "foo");
            let foo: Box<str> = gstring.into();
            assert_eq!(foo.as_ref(), "foo");
        }
    }

    #[test]
    fn test_owned_glib_string() {
        let data = CString::new("foo").unwrap();
        let ptr = data.into_raw();
        unsafe {
            let ptr_copy = glib_ffi::g_strdup(ptr);
            let gstr = GString::new(ptr_copy);
            assert_eq!(gstr, "foo");
        }
    }

    #[test]
    fn test_gstring_from_str() {
        let gstring: GString = "foo".into();
        assert_eq!(gstring.as_str(), "foo");
        let foo: Box<str> = gstring.into();
        assert_eq!(foo.as_ref(), "foo");
    }

    #[test]
    fn test_gstring_from_cstring() {
        let cstr = CString::new("foo").unwrap();
        let gstring = GString::from(cstr);
        assert_eq!(gstring.as_str(), "foo");
        let foo: Box<str> = gstring.into();
        assert_eq!(foo.as_ref(), "foo");
    }

    #[test]
    fn test_string_from_gstring() {
        let cstr = CString::new("foo").unwrap();
        let gstring = GString::from(cstr);
        assert_eq!(gstring.as_str(), "foo");
        let s = String::from(gstring);
        assert_eq!(s, "foo");
    }

    #[test]
    fn test_vec_u8_to_gstring() {
        let v = "foo".as_bytes();
        let s: GString = Vec::from(v).into();
        assert_eq!(s.as_str(), "foo");
    }

}
<commit_msg>gstring: Specify a lifetime for the From<str> impl<commit_after>// Copyright 2018, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use std::borrow::Borrow;
use std::cmp::Ordering;
use std::ffi::{CStr, CString, OsStr};
use std::fmt;
use std::ops::Deref;
use std::os::raw::c_char;
use std::ptr;
use std::slice;
use std::string::String;
use translate::*;
use types::{StaticType, Type};
use libc;

use gobject_ffi;
use ffi as glib_ffi;
use value::{FromValueOptional, Value, SetValueOptional, SetValue};

#[derive(Debug)]
pub enum GString {
    ForeignOwned(CString),
    Borrowed(*const c_char, usize),
    Owned(*mut c_char, usize)
}

impl GString {
    pub unsafe fn new(ptr: *mut c_char) -> Self {
        assert!(!ptr.is_null());
        GString::Owned(ptr, libc::strlen(ptr))
    }

    pub unsafe fn new_borrowed(ptr: *const c_char) -> Self {
        assert!(!ptr.is_null());
        GString::Borrowed(ptr, libc::strlen(ptr))
    }

    pub fn as_str(&self) -> &str {
        let cstr = match self {
            GString::Borrowed(ptr, length) => unsafe {
                let bytes = slice::from_raw_parts(*ptr as *const u8, length + 1);
                CStr::from_bytes_with_nul_unchecked(bytes)
            }
            GString::Owned(ptr, length) => unsafe {
                let bytes = slice::from_raw_parts(*ptr as *const u8, length + 1);
                CStr::from_bytes_with_nul_unchecked(bytes)
            }
            GString::ForeignOwned(cstring) => {
                cstring.as_c_str()
            }
        };
        cstr.to_str().unwrap()
    }
}

impl Drop for GString {
    fn drop(&mut self) {
        if let GString::Owned(ptr, _len) = self {
            unsafe {
                glib_ffi::g_free(*ptr as *mut _);
            }
        }
    }
}

impl fmt::Display for GString {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.as_str())
    }
}

impl Borrow<str> for GString {
    fn borrow(&self) -> &str {
        self.as_str()
    }
}

impl Ord for GString {
    fn cmp(&self, other: &GString) -> Ordering {
        self.as_str().cmp(other.as_str())
    }
}

impl PartialOrd for GString {
    fn partial_cmp(&self, other: &GString) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl PartialEq for GString {
    fn eq(&self, other: &GString) -> bool {
        self.as_str() == other.as_str()
    }
}

impl PartialEq<GString> for String {
    fn eq(&self, other: &GString) -> bool {
        self.as_str() == other.as_str()
    }
}

impl PartialEq<str> for GString {
    fn eq(&self, other: &str) -> bool {
        self.as_str() == other
    }
}

impl<'a> PartialEq<&'a str> for GString {
    fn eq(&self, other: &&'a str) -> bool {
        self.as_str() == *other
    }
}

impl<'a> PartialEq<GString> for &'a str {
    fn eq(&self, other: &GString) -> bool {
        *self == other.as_str()
    }
}

impl PartialEq<String> for GString {
    fn eq(&self, other: &String) -> bool {
        self.as_str() == other.as_str()
    }
}

impl PartialEq<GString> for str {
    fn eq(&self, other: &GString) -> bool {
        self == other.as_str()
    }
}

impl PartialOrd<GString> for String {
    fn partial_cmp(&self, other: &GString) -> Option<Ordering> {
        Some(self.cmp(&String::from(other.as_str())))
    }
}

impl PartialOrd<String> for GString {
    fn partial_cmp(&self, other: &String) -> Option<Ordering> {
        Some(self.as_str().cmp(other.as_str()))
    }
}

impl PartialOrd<GString> for str {
    fn partial_cmp(&self, other: &GString) -> Option<Ordering> {
        Some(self.cmp(&other))
    }
}

impl PartialOrd<str> for GString {
    fn partial_cmp(&self, other: &str) -> Option<Ordering> {
        Some(self.as_str().cmp(other))
    }
}

impl Eq for GString {}

impl AsRef<str> for GString {
    fn as_ref(&self) -> &str {
        self.as_str()
    }
}

impl AsRef<OsStr> for GString {
    fn as_ref(&self) -> &OsStr {
        OsStr::new(self.as_str())
    }
}

impl Deref for GString {
    type Target = str;

    fn deref(&self) -> &str {
        self.as_str()
    }
}

impl From<GString> for String {
    #[inline]
    fn from(s: GString) -> Self {
        String::from(s.as_str())
    }
}

impl From<GString> for Box<str> {
    #[inline]
    fn from(s: GString) -> Self {
        let st: String = s.into();
        st.into_boxed_str()
    }
}

impl From<String> for GString {
    #[inline]
    fn from(s: String) -> Self {
        s.as_bytes().to_vec().into()
    }
}

impl From<Box<str>> for GString {
    #[inline]
    fn from(s: Box<str>) -> Self {
        s.as_bytes().to_vec().into()
    }
}

impl<'a> From<&'a str> for GString {
    #[inline]
    fn from(s: &'a str) -> Self {
        s.as_bytes().to_vec().into()
    }
}

impl From<Vec<u8>> for GString {
    #[inline]
    fn from(s: Vec<u8>) -> Self {
        let cstring = CString::new(s).expect("CString::new failed");
        cstring.into()
    }
}

impl From<CString> for GString {
    #[inline]
    fn from(s: CString) -> Self {
        GString::ForeignOwned(s)
    }
}

impl<'a> From<&'a CStr> for GString {
    #[inline]
    fn from(c: &'a CStr) -> Self {
        CString::from(c).into()
    }
}

impl FromGlibPtrFull<*const c_char> for GString {
    #[inline]
    unsafe fn from_glib_full(ptr: *const c_char) -> Self {
        GString::new(ptr as *mut _)
    }
}

impl FromGlibPtrFull<*mut u8> for GString {
    #[inline]
    unsafe fn from_glib_full(ptr: *mut u8) -> Self {
        GString::new(ptr as *mut _)
    }
}

impl FromGlibPtrFull<*mut i8> for GString {
    #[inline]
    unsafe fn from_glib_full(ptr: *mut i8) -> Self {
        GString::new(ptr)
    }
}

impl FromGlibPtrNone<*const c_char> for GString {
    #[inline]
    unsafe fn from_glib_none(ptr: *const c_char) -> Self {
        let cstr = CStr::from_ptr(ptr);
        cstr.into()
    }
}

impl FromGlibPtrNone<*mut u8> for GString {
    #[inline]
    unsafe fn from_glib_none(ptr: *mut u8) -> Self {
        let cstr = CStr::from_ptr(ptr as *mut i8);
        cstr.into()
    }
}

impl FromGlibPtrNone<*mut i8> for GString {
    #[inline]
    unsafe fn from_glib_none(ptr: *mut i8) -> Self {
        let cstr = CStr::from_ptr(ptr);
        cstr.into()
    }
}

impl FromGlibPtrBorrow<*const c_char> for GString {
    #[inline]
    unsafe fn from_glib_borrow(ptr: *const c_char) -> Self {
        GString::new_borrowed(ptr)
    }
}

impl FromGlibPtrBorrow<*mut u8> for GString {
    #[inline]
    unsafe fn from_glib_borrow(ptr: *mut u8) -> Self {
        GString::new_borrowed(ptr as *const c_char)
    }
}

impl FromGlibPtrBorrow<*mut i8> for GString {
    #[inline]
    unsafe fn from_glib_borrow(ptr: *mut i8) -> Self {
        GString::new_borrowed(ptr as *const c_char)
    }
}

impl<'a> ToGlibPtr<'a, *const c_char> for GString {
    type Storage = &'a Self;

    #[inline]
    fn to_glib_none(&'a self) -> Stash<'a, *const c_char, Self> {
        Stash(self.as_ptr() as *const _, self)
    }

    #[inline]
    fn to_glib_full(&self) -> *const c_char {
        unsafe {
            glib_ffi::g_strndup(self.as_ptr() as *const c_char, self.len() as libc::size_t)
                as *const c_char
        }
    }
}

impl<'a> ToGlibPtr<'a, *mut c_char> for GString {
    type Storage = &'a Self;

    #[inline]
    fn to_glib_none(&'a self) -> Stash<'a, *mut c_char, Self> {
        Stash(self.as_ptr() as *mut _, self)
    }

    #[inline]
    fn to_glib_full(&self) -> *mut c_char {
        unsafe {
            glib_ffi::g_strndup(self.as_ptr() as *const c_char, self.len() as libc::size_t)
                as *mut c_char
        }
    }
}

impl GlibPtrDefault for GString {
    type GlibType = *const c_char;
}

impl StaticType for GString {
    fn static_type() -> Type {
        String::static_type()
    }
}

impl StaticType for Vec<GString> {
    fn static_type() -> Type {
        unsafe {
            from_glib(glib_ffi::g_strv_get_type())
        }
    }
}

impl<'a> FromValueOptional<'a> for GString {
    unsafe fn from_value_optional(value: &'a Value) -> Option<Self> {
        let val = value.to_glib_none().0;
        if val.is_null() {
            None
        } else {
            let ptr = gobject_ffi::g_value_dup_string(val);
            Some(GString::new(ptr))
        }
    }
}

impl SetValue for GString {
    unsafe fn set_value(value: &mut Value, this: &Self) {
        gobject_ffi::g_value_take_string(value.to_glib_none_mut().0, this.to_glib_full())
    }
}

impl SetValueOptional for GString {
    unsafe fn set_value_optional(value: &mut Value, this: Option<&Self>) {
        gobject_ffi::g_value_take_string(value.to_glib_none_mut().0, this.to_glib_full())
    }
}

impl_from_glib_container_as_vec_string!(GString, *const c_char);
impl_from_glib_container_as_vec_string!(GString, *mut c_char);

#[cfg(test)]
mod tests {
    use gstring::GString;
    use std::ffi::CString;
    use ffi as glib_ffi;

    #[test]
    fn test_gstring() {
        let data = CString::new("foo").unwrap();
        let ptr = data.into_raw();

        unsafe {
            let ptr_copy = glib_ffi::g_strdup(ptr);
            let gstring = GString::new(ptr_copy);
            assert_eq!(gstring.as_str(), "foo");
            let foo: Box<str> = gstring.into();
            assert_eq!(foo.as_ref(), "foo");
        }
    }

    #[test]
    fn test_owned_glib_string() {
        let data = CString::new("foo").unwrap();
        let ptr = data.into_raw();
        unsafe {
            let ptr_copy = glib_ffi::g_strdup(ptr);
            let gstr = GString::new(ptr_copy);
            assert_eq!(gstr, "foo");
        }
    }

    #[test]
    fn test_gstring_from_str() {
        let gstring: GString = "foo".into();
        assert_eq!(gstring.as_str(), "foo");
        let foo: Box<str> = gstring.into();
        assert_eq!(foo.as_ref(), "foo");
    }

    #[test]
    fn test_gstring_from_cstring() {
        let cstr = CString::new("foo").unwrap();
        let gstring = GString::from(cstr);
        assert_eq!(gstring.as_str(), "foo");
        let foo: Box<str> = gstring.into();
        assert_eq!(foo.as_ref(), "foo");
    }

    #[test]
    fn test_string_from_gstring() {
        let cstr = CString::new("foo").unwrap();
        let gstring = GString::from(cstr);
        assert_eq!(gstring.as_str(), "foo");
        let s = String::from(gstring);
        assert_eq!(s, "foo");
    }

    #[test]
    fn test_vec_u8_to_gstring() {
        let v = "foo".as_bytes();
        let s: GString = Vec::from(v).into();
        assert_eq!(s.as_str(), "foo");
    }

}
<|endoftext|>


<commit_before>use std::io::Error;

use mio::{self, EventLoop, Token, EventSet};
use mio::util::Slab;

pub enum Notify<T:EventMachine> {
    NewMachine(T),
}

pub trait EventMachine: Send + Sized {

    /// Socket readiness notification
    fn ready(self, events: EventSet) -> Option<Self>;

    /// Gives socket a chance to register in event loop
    ///
    /// Keep in mind that there are no reregister or any other kind of modify
    /// operation. So it's mostly useful for registering all events in
    /// edge-triggered mode
    fn register<H: mio::Handler>(&mut self,
        tok: Token, eloop: &mut EventLoop<H>)
        -> Result<(), Error>;

    /// Abnormal termination of event machine
    ///
    /// Currently happens when no slab space available or when register
    /// fails (which presumably means can't add socket to epoll)
    fn abort(self) {}
}

pub struct Handler<T:EventMachine> {
    slab: Slab<T>,
}

impl<T:EventMachine> mio::Handler for Handler<T> {
    type Message = Notify<T>;
    type Timeout = ();
    fn ready(&mut self, _eloop: &mut EventLoop<Self>,
        token: Token, events: EventSet)
    {
        self.slab.replace_with(token, |fsm| {
            fsm.ready(events)
        }).ok();  // Spurious events are ok in mio
    }

    fn notify(&mut self, eloop: &mut EventLoop<Self>, msg: Notify<T>) {
        use self::Notify::*;
        match msg {
            NewMachine(fsm) => {
                // This is so complex because of limitations of Slab
                match self.slab.insert(fsm) {
                    Ok(tok) => {
                        self.slab.replace_with(tok, |mut fsm| {
                            match fsm.register(tok, eloop) {
                                Ok(()) => Some(fsm),
                                Err(_) => {
                                    fsm.abort();
                                    None
                                }
                            }
                        }).unwrap();
                    }
                    Err(fsm) => {
                        fsm.abort();
                    }
                }
            }
        }
    }
}

<commit_msg>Add `new()` method for Handler<commit_after>use std::io::Error;

use mio::{self, EventLoop, Token, EventSet};
use mio::util::Slab;

pub enum Notify<T:EventMachine> {
    NewMachine(T),
}

pub trait EventMachine: Send + Sized {

    /// Socket readiness notification
    fn ready(self, events: EventSet) -> Option<Self>;

    /// Gives socket a chance to register in event loop
    ///
    /// Keep in mind that there are no reregister or any other kind of modify
    /// operation. So it's mostly useful for registering all events in
    /// edge-triggered mode
    fn register<H: mio::Handler>(&mut self,
        tok: Token, eloop: &mut EventLoop<H>)
        -> Result<(), Error>;

    /// Abnormal termination of event machine
    ///
    /// Currently happens when no slab space available or when register
    /// fails (which presumably means can't add socket to epoll)
    fn abort(self) {}
}

pub struct Handler<T:EventMachine> {
    slab: Slab<T>,
}

impl<T:EventMachine> Handler<T> {
    pub fn new() -> Handler<T> {
        // TODO(tailhook) create default config from the ulimit data instead
        // of using real defaults
        Handler {
            slab: Slab::new(4096),
        }
    }
}

impl<T:EventMachine> mio::Handler for Handler<T> {
    type Message = Notify<T>;
    type Timeout = ();
    fn ready(&mut self, _eloop: &mut EventLoop<Self>,
        token: Token, events: EventSet)
    {
        self.slab.replace_with(token, |fsm| {
            fsm.ready(events)
        }).ok();  // Spurious events are ok in mio
    }

    fn notify(&mut self, eloop: &mut EventLoop<Self>, msg: Notify<T>) {
        use self::Notify::*;
        match msg {
            NewMachine(fsm) => {
                // This is so complex because of limitations of Slab
                match self.slab.insert(fsm) {
                    Ok(tok) => {
                        self.slab.replace_with(tok, |mut fsm| {
                            match fsm.register(tok, eloop) {
                                Ok(()) => Some(fsm),
                                Err(_) => {
                                    fsm.abort();
                                    None
                                }
                            }
                        }).unwrap();
                    }
                    Err(fsm) => {
                        fsm.abort();
                    }
                }
            }
        }
    }
}

<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::fmt::{self, Debug, Formatter};
use std::marker::PhantomData;
use std::ops::RangeFrom;
use {Command, Error, Record};

const ORIGIN: usize = 0;

/// A history of commands.
#[derive(Debug)]
pub struct History<R> {
    id: usize,
    parent: usize,
    next: RangeFrom<usize>,
    record: Record<R>,
    branches: HashMap<usize, Branch<R>>,
}

impl<R> History<R> {
    /// Returns a new history.
    #[inline]
    pub fn new(receiver: impl Into<R>) -> History<R> {
        History {
            id: ORIGIN,
            parent: ORIGIN,
            next: 1..,
            record: Record::new(receiver),
            branches: HashMap::new(),
        }
    }

    /// Pushes the command to the top of the history and executes its [`apply`] method.
    /// The command is merged with the previous top command if they have the same [`id`].
    ///
    /// # Errors
    /// If an error occur when executing [`apply`] the error is returned together with the command.
    ///
    /// [`apply`]: trait.Command.html#tymethod.apply
    /// [`id`]: trait.Command.html#method.id
    #[inline]
    pub fn apply(&mut self, cmd: impl Command<R> + 'static) -> Result<Option<usize>, Error<R>>
    where
        R: 'static,
    {
        let cursor = self.record.cursor();
        let commands = self.record.apply(cmd)?;
        let commands: Vec<_> = commands.collect();
        if !commands.is_empty() {
            let id = self.next.next().unwrap();
            self.branches.insert(
                id,
                Branch {
                    parent: self.id,
                    cursor,
                    commands,
                },
            );
            Ok(Some(id))
        } else {
            Ok(None)
        }
    }

    /// Calls the [`undo`] method for the active command and sets the previous one as the new active one.
    ///
    /// # Errors
    /// If an error occur when executing [`undo`] the error is returned together with the command.
    ///
    /// [`undo`]: trait.Command.html#tymethod.undo
    #[inline]
    #[must_use]
    pub fn undo(&mut self) -> Option<Result<(), Error<R>>> {
        self.record.undo()
    }

    /// Calls the [`redo`] method for the active command and sets the next one as the
    /// new active one.
    ///
    /// # Errors
    /// If an error occur when executing [`redo`] the error is returned together with the command.
    ///
    /// [`redo`]: trait.Command.html#method.redo
    #[inline]
    #[must_use]
    pub fn redo(&mut self) -> Option<Result<(), Error<R>>> {
        self.record.redo()
    }

    /// Jumps to the command in `branch` at `cursor`.
    #[inline]
    #[must_use]
    pub fn jump_to(&mut self, mut branch: usize, cursor: usize) -> Option<Result<(), Error<R>>>
    where
        R: 'static,
    {
        if self.id == branch {
            return self.record.jump_to(cursor);
        }

        // Find the path from `dest` to `ORIGIN`.
        let mut dest = self.branches.remove(&branch)?;
        branch = dest.parent;
        let mut path = vec![dest];
        while branch != ORIGIN {
            dest = self.branches.remove(&branch).unwrap();
            path.push(dest);
        }

        // Find the path from `start` to `ORIGIN`.
        if self.id != ORIGIN {
            let mut start = self.branches.remove(&self.parent).unwrap();
            branch = start.parent;
            let mut tmp = vec![start];
            while branch != ORIGIN {
                start = self.branches.remove(&branch).unwrap();
                tmp.push(start);
            }
            tmp.reverse();
            path.append(&mut tmp);
        }

        // Walk the path from `start` to `dest`.
        while let Some(dest) = path.pop() {
            // Move to `dest.cursor` either by undoing or redoing.
            if let Err(err) = self.record.jump_to(dest.cursor).unwrap() {
                return Some(Err(err));
            }
            // Apply the commands in the branch and move older commands into their own branch.
            for cmd in dest.commands {
                if let Err(err) = self.apply(cmd) {
                    return Some(Err(err));
                }
            }
        }

        Some(Ok(()))
    }
}

impl<R: Default> Default for History<R> {
    #[inline]
    fn default() -> History<R> {
        History::new(R::default())
    }
}

impl<R> From<R> for History<R> {
    #[inline]
    fn from(receiver: R) -> Self {
        History::new(receiver)
    }
}

struct Branch<R> {
    parent: usize,
    cursor: usize,
    commands: Vec<Box<dyn Command<R> + 'static>>,
}

impl<R> Debug for Branch<R> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.debug_struct("Branch")
            .field("parent", &self.parent)
            .field("cursor", &self.cursor)
            .field("commands", &self.commands)
            .finish()
    }
}

/// Builder for a history.
#[derive(Debug)]
pub struct HistoryBuilder<R> {
    receiver: PhantomData<R>,
}

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

    #[derive(Debug)]
    struct Add(char);

    impl Command<String> for Add {
        fn apply(&mut self, receiver: &mut String) -> Result<(), Box<dyn Error>> {
            receiver.push(self.0);
            Ok(())
        }

        fn undo(&mut self, receiver: &mut String) -> Result<(), Box<dyn Error>> {
            self.0 = receiver.pop().ok_or("`receiver` is empty")?;
            Ok(())
        }
    }

    #[test]
    fn jump_to() {
        let mut history = History::default();
        history.apply(Add('a')).unwrap();
        history.apply(Add('b')).unwrap();
        history.apply(Add('c')).unwrap();
        history.apply(Add('d')).unwrap();
        history.apply(Add('e')).unwrap();

        history.undo().unwrap().unwrap();
        history.undo().unwrap().unwrap();

        let b = history.apply(Add('f')).unwrap().unwrap();
        history.apply(Add('g')).unwrap();

        history.jump_to(b, 5).unwrap().unwrap();
    }
}
<commit_msg>Update branch id when walking path<commit_after>use std::collections::HashMap;
use std::fmt::{self, Debug, Formatter};
use std::marker::PhantomData;
use std::ops::RangeFrom;
use {Command, Error, Record};

const ORIGIN: usize = 0;

/// A history of commands.
#[derive(Debug)]
pub struct History<R> {
    id: usize,
    parent: usize,
    next: RangeFrom<usize>,
    record: Record<R>,
    branches: HashMap<usize, Branch<R>>,
}

impl<R> History<R> {
    /// Returns a new history.
    #[inline]
    pub fn new(receiver: impl Into<R>) -> History<R> {
        History {
            id: ORIGIN,
            parent: ORIGIN,
            next: 1..,
            record: Record::new(receiver),
            branches: HashMap::new(),
        }
    }

    /// Pushes the command to the top of the history and executes its [`apply`] method.
    /// The command is merged with the previous top command if they have the same [`id`].
    ///
    /// # Errors
    /// If an error occur when executing [`apply`] the error is returned together with the command.
    ///
    /// [`apply`]: trait.Command.html#tymethod.apply
    /// [`id`]: trait.Command.html#method.id
    #[inline]
    pub fn apply(&mut self, cmd: impl Command<R> + 'static) -> Result<Option<usize>, Error<R>>
    where
        R: 'static,
    {
        let cursor = self.record.cursor();
        let commands = self.record.apply(cmd)?;
        let commands: Vec<_> = commands.collect();
        if !commands.is_empty() {
            let id = self.next.next().unwrap();
            self.branches.insert(
                id,
                Branch {
                    parent: self.id,
                    cursor,
                    commands,
                },
            );
            Ok(Some(id))
        } else {
            Ok(None)
        }
    }

    /// Calls the [`undo`] method for the active command and sets the previous one as the new active one.
    ///
    /// # Errors
    /// If an error occur when executing [`undo`] the error is returned together with the command.
    ///
    /// [`undo`]: trait.Command.html#tymethod.undo
    #[inline]
    #[must_use]
    pub fn undo(&mut self) -> Option<Result<(), Error<R>>> {
        self.record.undo()
    }

    /// Calls the [`redo`] method for the active command and sets the next one as the
    /// new active one.
    ///
    /// # Errors
    /// If an error occur when executing [`redo`] the error is returned together with the command.
    ///
    /// [`redo`]: trait.Command.html#method.redo
    #[inline]
    #[must_use]
    pub fn redo(&mut self) -> Option<Result<(), Error<R>>> {
        self.record.redo()
    }

    /// Jumps to the command in `branch` at `cursor`.
    #[inline]
    #[must_use]
    pub fn jump_to(&mut self, mut branch: usize, cursor: usize) -> Option<Result<(), Error<R>>>
    where
        R: 'static,
    {
        if self.id == branch {
            return self.record.jump_to(cursor);
        }

        // Find the path from `dest` to `ORIGIN`.
        let mut dest = self.branches.remove(&branch)?;
        branch = dest.parent;
        let mut path = vec![dest];
        while branch != ORIGIN {
            dest = self.branches.remove(&branch).unwrap();
            branch = dest.parent;
            path.push(dest);
        }

        // Find the path from `start` to `ORIGIN`.
        if self.id != ORIGIN {
            let mut start = self.branches.remove(&self.parent).unwrap();
            branch = start.parent;
            let mut tmp = vec![start];
            while branch != ORIGIN {
                start = self.branches.remove(&branch).unwrap();
                branch = start.parent;
                tmp.push(start);
            }
            tmp.reverse();
            path.append(&mut tmp);
        }

        // Walk the path from `start` to `dest`.
        while let Some(dest) = path.pop() {
            // Move to `dest.cursor` either by undoing or redoing.
            if let Err(err) = self.record.jump_to(dest.cursor).unwrap() {
                return Some(Err(err));
            }
            // Apply the commands in the branch and move older commands into their own branch.
            for cmd in dest.commands {
                let cursor = self.record.cursor();
                let commands = match self.record.apply(cmd) {
                    Ok(commands) => commands,
                    Err(err) => return Some(Err(err)),
                };
                let commands: Vec<_> = commands.collect();
                if !commands.is_empty() {
                    self.branches.insert(
                        self.id,
                        Branch {
                            parent: dest.parent,
                            cursor,
                            commands,
                        },
                    );
                    self.id = dest.parent;
                }
            }
        }

        Some(Ok(()))
    }
}

impl<R: Default> Default for History<R> {
    #[inline]
    fn default() -> History<R> {
        History::new(R::default())
    }
}

impl<R> From<R> for History<R> {
    #[inline]
    fn from(receiver: R) -> Self {
        History::new(receiver)
    }
}

struct Branch<R> {
    parent: usize,
    cursor: usize,
    commands: Vec<Box<dyn Command<R> + 'static>>,
}

impl<R> Debug for Branch<R> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.debug_struct("Branch")
            .field("parent", &self.parent)
            .field("cursor", &self.cursor)
            .field("commands", &self.commands)
            .finish()
    }
}

/// Builder for a history.
#[derive(Debug)]
pub struct HistoryBuilder<R> {
    receiver: PhantomData<R>,
}

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

    #[derive(Debug)]
    struct Add(char);

    impl Command<String> for Add {
        fn apply(&mut self, receiver: &mut String) -> Result<(), Box<dyn Error>> {
            receiver.push(self.0);
            Ok(())
        }

        fn undo(&mut self, receiver: &mut String) -> Result<(), Box<dyn Error>> {
            self.0 = receiver.pop().ok_or("`receiver` is empty")?;
            Ok(())
        }
    }

    #[test]
    fn jump_to() {
        let mut history = History::default();
        history.apply(Add('a')).unwrap();
        history.apply(Add('b')).unwrap();
        history.apply(Add('c')).unwrap();
        history.apply(Add('d')).unwrap();
        history.apply(Add('e')).unwrap();

        history.undo().unwrap().unwrap();
        history.undo().unwrap().unwrap();

        let b = history.apply(Add('f')).unwrap().unwrap();
        history.apply(Add('g')).unwrap();

        history.jump_to(b, 5).unwrap().unwrap();
    }
}
<|endoftext|>


<commit_before>
use libc;
use libc::{
    c_void,
    c_long,
    size_t,
};
use std::ffi::CString;
use std;
use std::num::FromPrimitive;
use ffi;
use {
    Face,
    FtResult,
};

extern "C" fn alloc_library(_memory: ffi::FT_Memory, size: c_long) -> *mut c_void {
    unsafe {
        libc::malloc(size as size_t)
    }
}

extern "C" fn free_library(_memory: ffi::FT_Memory, block: *mut c_void) {
    unsafe {
        libc::free(block)
    }
}

extern "C" fn realloc_library(_memory: ffi::FT_Memory,
                              _cur_size: c_long,
                              new_size: c_long,
                              block: *mut c_void) -> *mut c_void {
    unsafe {
        libc::realloc(block, new_size as size_t)
    }
}

static MEMORY: ffi::FT_MemoryRec = ffi::FT_MemoryRec {
    user: 0 as *mut c_void,
    alloc: alloc_library,
    free: free_library,
    realloc: realloc_library,
};

pub struct Library {
    raw: ffi::FT_Library,
}

impl Library {
    pub fn init() -> FtResult<Library> {
        unsafe {
            let mut raw = std::ptr::null_mut();

            let err = ffi::FT_New_Library(&MEMORY, &mut raw);
            if err == ffi::FT_Err_Ok {
                ffi::FT_Add_Default_Modules(raw);
                Ok(Library {
                    raw: raw,
                })
            } else {
                Err(FromPrimitive::from_i32(err).unwrap())
            }
        }
    }

    pub fn new_face(&self, filepathname: &str, face_index: ffi::FT_Long) -> FtResult<Face> {
        unsafe {
            let mut face = std::ptr::null_mut();

            let path_str = CString::from_slice(filepathname.as_bytes());

            let err = ffi::FT_New_Face(self.raw, path_str.as_ptr(), face_index, &mut face);
            if err == ffi::FT_Err_Ok {
                Ok(Face::from_raw(self.raw, face))
            } else {
                Err(FromPrimitive::from_i32(err).unwrap())
            }
        }
    }

    pub fn new_memory_face(&self, buffer: &[u8], face_index: ffi::FT_Long) -> FtResult<Face> {
        unsafe {
            let mut face = std::ptr::null_mut();
            let err = ffi::FT_New_Memory_Face(self.raw, buffer.as_ptr(), buffer.len() as ffi::FT_Long, face_index, &mut face);
            if err == ffi::FT_Err_Ok {
                Ok(Face::from_raw(self.raw, face))
            } else {
                Err(FromPrimitive::from_i32(err).unwrap())
            }
        }
    }

    pub fn raw(&self) -> ffi::FT_Library {
        self.raw
    }
}

impl Drop for Library {
    fn drop(&mut self) {
        unsafe {
            let err = ffi::FT_Done_Library(self.raw);
            if err != ffi::FT_Err_Ok {
                std::io::println(format!("Failed to drop Library. Error Code: {}", err).as_slice());
            }
        }
    }
}

<commit_msg>&Path instead of &str<commit_after>
use libc;
use libc::{
    c_void,
    c_long,
    size_t,
};
use std::ffi::CString;
use std;
use std::num::FromPrimitive;
use ffi;
use {
    Face,
    FtResult,
};

extern "C" fn alloc_library(_memory: ffi::FT_Memory, size: c_long) -> *mut c_void {
    unsafe {
        libc::malloc(size as size_t)
    }
}

extern "C" fn free_library(_memory: ffi::FT_Memory, block: *mut c_void) {
    unsafe {
        libc::free(block)
    }
}

extern "C" fn realloc_library(_memory: ffi::FT_Memory,
                              _cur_size: c_long,
                              new_size: c_long,
                              block: *mut c_void) -> *mut c_void {
    unsafe {
        libc::realloc(block, new_size as size_t)
    }
}

static MEMORY: ffi::FT_MemoryRec = ffi::FT_MemoryRec {
    user: 0 as *mut c_void,
    alloc: alloc_library,
    free: free_library,
    realloc: realloc_library,
};

pub struct Library {
    raw: ffi::FT_Library,
}

impl Library {
    pub fn init() -> FtResult<Library> {
        unsafe {
            let mut raw = std::ptr::null_mut();

            let err = ffi::FT_New_Library(&MEMORY, &mut raw);
            if err == ffi::FT_Err_Ok {
                ffi::FT_Add_Default_Modules(raw);
                Ok(Library {
                    raw: raw,
                })
            } else {
                Err(FromPrimitive::from_i32(err).unwrap())
            }
        }
    }

    pub fn new_face(&self, filepath: &Path, face_index: ffi::FT_Long) -> FtResult<Face> {
        unsafe {
            let mut face = std::ptr::null_mut();

            let path_str = CString::from_slice(filepath.as_vec());

            let err = ffi::FT_New_Face(self.raw, path_str.as_ptr(), face_index, &mut face);
            if err == ffi::FT_Err_Ok {
                Ok(Face::from_raw(self.raw, face))
            } else {
                Err(FromPrimitive::from_i32(err).unwrap())
            }
        }
    }

    pub fn new_memory_face(&self, buffer: &[u8], face_index: ffi::FT_Long) -> FtResult<Face> {
        unsafe {
            let mut face = std::ptr::null_mut();
            let err = ffi::FT_New_Memory_Face(self.raw, buffer.as_ptr(), buffer.len() as ffi::FT_Long, face_index, &mut face);
            if err == ffi::FT_Err_Ok {
                Ok(Face::from_raw(self.raw, face))
            } else {
                Err(FromPrimitive::from_i32(err).unwrap())
            }
        }
    }

    pub fn raw(&self) -> ffi::FT_Library {
        self.raw
    }
}

impl Drop for Library {
    fn drop(&mut self) {
        unsafe {
            let err = ffi::FT_Done_Library(self.raw);
            if err != ffi::FT_Err_Ok {
                std::io::println(format!("Failed to drop Library. Error Code: {}", err).as_slice());
            }
        }
    }
}

<|endoftext|>


<commit_before>use std::vec::Vec;
use std::thread;
use std::sync::mpsc;

pub enum Message {
    Pause,
    Resume,
    Step,
    Inspect,
}

pub fn spawn() -> (mpsc::Sender<Message>, mpsc::Receiver<String>) {
    let (tx_message, rx_message) = mpsc::channel();
    let (tx_data, rx_data) = mpsc::channel();

    thread::spawn(move || {
        let mut computer = Machine::new();
        let mut paused = false;

        loop {
            let message = rx_message.try_recv();
            if message.is_ok() {
                match message.unwrap() {
                    Message::Pause => {
                        paused = true;
                    },

                    Message::Resume => {
                        paused = false;
                    },

                    Message::Step => {
                        paused = true;
                        computer.step();
                    },

                    Message::Inspect => {
                        let data = format!("PAUSED {}\nPC {}", paused, computer.loc());
                        tx_data.send(data).unwrap();
                    }
                }
            }

            thread::yield_now();

            if !paused {
                computer.step();
            }

        }
    });

    return (tx_message, rx_data);
}

pub struct Machine {
    memory: Vec<u32>,
    counter: u32,
}

impl Machine {
    pub fn new() -> Machine {
        Machine {
            memory: vec![0; 2097152],
            counter: 0,
        }
    }

    pub fn with_data(data: Vec<u32>) -> Machine {
        Machine {
            memory: data,
            counter: 0,
        }
    }

    pub fn loc(&self) -> u32 {
        self.counter
    }

    pub fn dump(&self) -> &Vec<u32> {
        &self.memory
    }

    pub fn load(&mut self, data: Vec<u32>) {
        self.memory = data;
    }

    pub fn step(&mut self) {
        let counter = self.counter as usize;
        let opcode = self.memory[counter];
        let a = self.memory[counter + 1];
        let b = self.memory[counter + 2];
        let c = self.memory[counter + 3];
        self.exec(opcode, a, b, c);
    }

    fn exec(&mut self, opcode: u32, a: u32, b: u32, c: u32) {
        match opcode {
            // PC <- M[A]
            1 => {
                self.counter = self.memory[a as usize];
            },

            // If M[B] = 0, then PC <- M[A]
            2 => {
                if 0 == self.memory[b as usize] {
                  self.counter = self.memory[a as usize];
                }
            },

            // M[A] <- PC
            3 => {
                self.memory[a as usize] = self.counter;
                self.counter += 4;
            },

            // M[A] <- M[B]
            4 => {
                self.memory[a as usize] = self.memory[b as usize];
                self.counter += 4;
            },

            // M[A] <- M[M[B]]
            5 => {
                let b = self.memory[b as usize];
                self.memory[a as usize] = self.memory[b as usize];
                self.counter += 4;
            },

            // M[M[B]] <- M[A]
            6 => {
                let b = self.memory[b as usize];
                self.memory[b as usize] = self.memory[a as usize];
                self.counter += 4;
            },

            // M[A] <- M[B] + M[C]
            7 => {
                let b = self.memory[b as usize];
                let c = self.memory[c as usize];
                self.memory[a as usize] = b + c;
                self.counter += 4;
            },

            // M[A] <- M[B] - M[C]
            8 => {
                let b = self.memory[b as usize];
                let c = self.memory[c as usize];
                self.memory[a as usize] = b - c;
                self.counter += 4;
            },

            // M[A] <- M[B] * M[C]
            9 => {
                let b = self.memory[b as usize];
                let c = self.memory[c as usize];
                self.memory[a as usize] = b * c;
                self.counter += 4;
            },

            // M[A] <- M[B] / M[C]
            10 => {
                let b = self.memory[b as usize];
                let c = self.memory[c as usize];
                self.memory[a as usize] = b / c;
                self.counter += 4;
            },

            // M[A] <- M[B] % M[C]
            11 => {
                let b = self.memory[b as usize];
                let c = self.memory[c as usize];
                self.memory[a as usize] = b % c;
                self.counter += 4;
            },

            // If M[B] < M[C], then M[A] <- 1, else M[A] <- 0
            12 => {
                let b = self.memory[b as usize];
                let c = self.memory[c as usize];
                if b < c {
                  self.memory[a as usize] = 1;
                } else {
                  self.memory[a as usize] = 0;
                }
                self.counter += 4;
            },

            // MA[A] <- NOT(M[B] AND M[C])
            13 => {
                let b = self.memory[b as usize];
                let c = self.memory[c as usize];
                if b > 0 && c > 0 {
                  self.memory[a as usize] = 0;
                } else {
                  self.memory[a as usize] = 1;
                }
                self.counter += 4;
            },

            // Unknown opcode
            _ => {
            },
        }
    }
}

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

    #[test]
    fn it_loads_data() {
        let mut m = Machine::new();
        assert_eq!(Some(&0), m.dump().first());

        m.load(vec![1]);
        assert_eq!(Some(&1), m.dump().first());
    }

    #[test]
    fn it_runs_opcode_1() {
        // PC <- M[A]
        let mut m = Machine::with_data(vec![1, 4, 0, 0, 2]);

        assert_eq!(0, m.loc());
        m.step();
        assert_eq!(2, m.loc());
    }

    #[test]
    fn it_runs_opcode_2_then_branch() {
        // If M[B] = 0, then PC <- M[A]
        let mut m = Machine::with_data(vec![2, 4, 5, 0, 2, 0]);

        assert_eq!(0, m.loc());
        m.step();
        assert_eq!(2, m.loc());
    }

    #[test]
    fn it_runs_opcode_2_else_branch() {
        // If M[B] = 0, then PC <- M[A]
        let mut m = Machine::with_data(vec![2, 4, 5, 0, 2, 1]);

        assert_eq!(0, m.loc());
        m.step();
        assert_eq!(0, m.loc());
    }

    #[test]
    fn it_runs_opcode_3() {
        // M[A] <- PC
        let mut m = Machine::with_data(vec![3, 4, 0, 0, 1]);

        assert_eq!(0, m.loc());
        m.step();
        assert_eq!(&vec![3, 4, 0, 0, 0], m.dump());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_4() {
        // M[A] <- M[B]
        let mut m = Machine::with_data(vec![4, 4, 5, 0, 6, 7]);

        assert_eq!(0, m.loc());
        m.step();
        assert_eq!(&vec![4, 4, 5, 0, 7, 7], m.dump());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_5() {
        // M[A] <- M[M[B]]
        let mut m = Machine::with_data(vec![5, 4, 5, 0, 6, 7, 0, 8]);

        assert_eq!(0, m.loc());
        m.step();
        assert_eq!(&vec![5, 4, 5, 0, 8, 7, 0, 8], m.dump());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_6() {
        // M[M[B]] <- M[A]
        let mut m = Machine::with_data(vec![6, 4, 5, 0, 8, 6, 7]);

        assert_eq!(0, m.loc());
        m.step();
        assert_eq!(&vec![6, 4, 5, 0, 8, 6, 8], m.dump());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_7() {
        // M[A] <- M[B] + M[C]
        let mut m = Machine::with_data(vec![7, 4, 5, 6, 0, 11, 2]);

        assert_eq!(0, m.loc());
        m.step();
        assert_eq!(&vec![7, 4, 5, 6, 13, 11, 2], m.dump());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_8() {
        // M[A] <- M[B] - M[C]
        let mut m = Machine::with_data(vec![8, 4, 5, 6, 0, 11, 2]);

        assert_eq!(0, m.loc());
        m.step();
        assert_eq!(&vec![8, 4, 5, 6, 9, 11, 2], m.dump());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_9() {
        // M[A] <- M[B] * M[C]
        let mut m = Machine::with_data(vec![9, 4, 5, 6, 0, 11, 2]);

        assert_eq!(0, m.loc());
        m.step();
        assert_eq!(&vec![9, 4, 5, 6, 22, 11, 2], m.dump());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_10() {
        // M[A] <- M[B] / M[C]
        let mut m = Machine::with_data(vec![10, 4, 5, 6, 0, 11, 2]);

        assert_eq!(0, m.loc());
        m.step();
        assert_eq!(&vec![10, 4, 5, 6, 5, 11, 2], m.dump());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_11() {
        // M[A] <- M[B] % M[C]
        let mut m = Machine::with_data(vec![11, 4, 5, 6, 0, 11, 2]);

        assert_eq!(0, m.loc());
        m.step();
        assert_eq!(&vec![11, 4, 5, 6, 1, 11, 2], m.dump());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_12_then_branch() {
        // If M[B] < M[C], then M[A] <- 1, else M[A] <- 0
        let mut m = Machine::with_data(vec![12, 4, 5, 6, 2, 8, 9]);

        assert_eq!(0, m.loc());
        m.step();
        assert_eq!(&vec![12, 4, 5, 6, 1, 8, 9], m.dump());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_12_else_branch() {
        // If M[B] < M[C], then M[A] <- 1, else M[A] <- 0
        let mut m = Machine::with_data(vec![12, 4, 5, 6, 2, 9, 8]);

        assert_eq!(0, m.loc());
        m.step();
        assert_eq!(&vec![12, 4, 5, 6, 0, 9, 8], m.dump());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_13_false_false_branch() {
        // M[A] <- NOT(M[B] AND M[C])
        let mut m = Machine::with_data(vec![13, 4, 5, 6, 2, 0, 0]);

        assert_eq!(0, m.loc());
        m.step();
        assert_eq!(&vec![13, 4, 5, 6, 1, 0, 0], m.dump());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_13_false_true_branch() {
        // M[A] <- NOT(M[B] AND M[C])
        let mut m = Machine::with_data(vec![13, 4, 5, 6, 2, 0, 1]);

        assert_eq!(0, m.loc());
        m.step();
        assert_eq!(&vec![13, 4, 5, 6, 1, 0, 1], m.dump());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_13_true_false_branch() {
        // M[A] <- NOT(M[B] AND M[C])
        let mut m = Machine::with_data(vec![13, 4, 5, 6, 2, 1, 0]);

        assert_eq!(0, m.loc());
        m.step();
        assert_eq!(&vec![13, 4, 5, 6, 1, 1, 0], m.dump());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_13_true_true_branch() {
        // M[A] <- NOT(M[B] AND M[C])
        let mut m = Machine::with_data(vec![13, 4, 5, 6, 2, 1, 1]);

        assert_eq!(0, m.loc());
        m.step();
        assert_eq!(&vec![13, 4, 5, 6, 0, 1, 1], m.dump());
        assert_eq!(4, m.loc());
    }
}
<commit_msg>Replace with_data() with struct update syntax.<commit_after>use std::vec::Vec;
use std::thread;
use std::sync::mpsc;

pub enum Message {
    Pause,
    Resume,
    Step,
    Inspect,
}

pub fn spawn() -> (mpsc::Sender<Message>, mpsc::Receiver<String>) {
    let (tx_message, rx_message) = mpsc::channel();
    let (tx_data, rx_data) = mpsc::channel();

    thread::spawn(move || {
        let mut computer = Machine::new();
        let mut paused = false;

        loop {
            let message = rx_message.try_recv();
            if message.is_ok() {
                match message.unwrap() {
                    Message::Pause => {
                        paused = true;
                    },

                    Message::Resume => {
                        paused = false;
                    },

                    Message::Step => {
                        paused = true;
                        computer.step();
                    },

                    Message::Inspect => {
                        let data = format!("PAUSED {}\nPC {}", paused, computer.loc());
                        tx_data.send(data).unwrap();
                    }
                }
            }

            thread::yield_now();

            if !paused {
                computer.step();
            }

        }
    });

    return (tx_message, rx_data);
}

pub struct Machine {
    memory: Vec<u32>,
    counter: u32,
}

impl Machine {
    pub fn new() -> Machine {
        Machine {
            memory: vec![0; 2097152],
            counter: 0,
        }
    }

    pub fn loc(&self) -> u32 {
        self.counter
    }

    pub fn dump(&self) -> &Vec<u32> {
        &self.memory
    }

    pub fn load(&mut self, data: Vec<u32>) {
        self.memory = data;
    }

    pub fn step(&mut self) {
        let counter = self.counter as usize;
        let opcode = self.memory[counter];
        let a = self.memory[counter + 1];
        let b = self.memory[counter + 2];
        let c = self.memory[counter + 3];
        self.exec(opcode, a, b, c);
    }

    fn exec(&mut self, opcode: u32, a: u32, b: u32, c: u32) {
        match opcode {
            // PC <- M[A]
            1 => {
                self.counter = self.memory[a as usize];
            },

            // If M[B] = 0, then PC <- M[A]
            2 => {
                if 0 == self.memory[b as usize] {
                  self.counter = self.memory[a as usize];
                }
            },

            // M[A] <- PC
            3 => {
                self.memory[a as usize] = self.counter;
                self.counter += 4;
            },

            // M[A] <- M[B]
            4 => {
                self.memory[a as usize] = self.memory[b as usize];
                self.counter += 4;
            },

            // M[A] <- M[M[B]]
            5 => {
                let b = self.memory[b as usize];
                self.memory[a as usize] = self.memory[b as usize];
                self.counter += 4;
            },

            // M[M[B]] <- M[A]
            6 => {
                let b = self.memory[b as usize];
                self.memory[b as usize] = self.memory[a as usize];
                self.counter += 4;
            },

            // M[A] <- M[B] + M[C]
            7 => {
                let b = self.memory[b as usize];
                let c = self.memory[c as usize];
                self.memory[a as usize] = b + c;
                self.counter += 4;
            },

            // M[A] <- M[B] - M[C]
            8 => {
                let b = self.memory[b as usize];
                let c = self.memory[c as usize];
                self.memory[a as usize] = b - c;
                self.counter += 4;
            },

            // M[A] <- M[B] * M[C]
            9 => {
                let b = self.memory[b as usize];
                let c = self.memory[c as usize];
                self.memory[a as usize] = b * c;
                self.counter += 4;
            },

            // M[A] <- M[B] / M[C]
            10 => {
                let b = self.memory[b as usize];
                let c = self.memory[c as usize];
                self.memory[a as usize] = b / c;
                self.counter += 4;
            },

            // M[A] <- M[B] % M[C]
            11 => {
                let b = self.memory[b as usize];
                let c = self.memory[c as usize];
                self.memory[a as usize] = b % c;
                self.counter += 4;
            },

            // If M[B] < M[C], then M[A] <- 1, else M[A] <- 0
            12 => {
                let b = self.memory[b as usize];
                let c = self.memory[c as usize];
                if b < c {
                  self.memory[a as usize] = 1;
                } else {
                  self.memory[a as usize] = 0;
                }
                self.counter += 4;
            },

            // MA[A] <- NOT(M[B] AND M[C])
            13 => {
                let b = self.memory[b as usize];
                let c = self.memory[c as usize];
                if b > 0 && c > 0 {
                  self.memory[a as usize] = 0;
                } else {
                  self.memory[a as usize] = 1;
                }
                self.counter += 4;
            },

            // Unknown opcode
            _ => {
            },
        }
    }
}

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

    #[test]
    fn it_loads_data() {
        let mut m = Machine::new();
        assert_eq!(Some(&0), m.dump().first());

        m.load(vec![1]);
        assert_eq!(Some(&1), m.dump().first());
    }

    #[test]
    fn it_runs_opcode_1() {
        // PC <- M[A]
        let mut m = Machine { memory: vec![1, 4, 0, 0, 2], .. Machine::new() };

        assert_eq!(0, m.loc());
        m.step();
        assert_eq!(2, m.loc());
    }

    #[test]
    fn it_runs_opcode_2_then_branch() {
        // If M[B] = 0, then PC <- M[A]
        let mut m = Machine { memory: vec![2, 4, 5, 0, 2, 0], .. Machine::new() };

        assert_eq!(0, m.loc());
        m.step();
        assert_eq!(2, m.loc());
    }

    #[test]
    fn it_runs_opcode_2_else_branch() {
        // If M[B] = 0, then PC <- M[A]
        let mut m = Machine { memory: vec![2, 4, 5, 0, 2, 1], .. Machine::new() };

        assert_eq!(0, m.loc());
        m.step();
        assert_eq!(0, m.loc());
    }

    #[test]
    fn it_runs_opcode_3() {
        // M[A] <- PC
        let mut m = Machine { memory: vec![3, 4, 0, 0, 1], .. Machine::new() };

        assert_eq!(0, m.loc());
        m.step();
        assert_eq!(&vec![3, 4, 0, 0, 0], m.dump());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_4() {
        // M[A] <- M[B]
        let mut m = Machine { memory: vec![4, 4, 5, 0, 6, 7], .. Machine::new() };

        assert_eq!(0, m.loc());
        m.step();
        assert_eq!(&vec![4, 4, 5, 0, 7, 7], m.dump());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_5() {
        // M[A] <- M[M[B]]
        let mut m = Machine { memory: vec![5, 4, 5, 0, 6, 7, 0, 8], .. Machine::new() };

        assert_eq!(0, m.loc());
        m.step();
        assert_eq!(&vec![5, 4, 5, 0, 8, 7, 0, 8], m.dump());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_6() {
        // M[M[B]] <- M[A]
        let mut m = Machine { memory: vec![6, 4, 5, 0, 8, 6, 7], .. Machine::new() };

        assert_eq!(0, m.loc());
        m.step();
        assert_eq!(&vec![6, 4, 5, 0, 8, 6, 8], m.dump());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_7() {
        // M[A] <- M[B] + M[C]
        let mut m = Machine { memory: vec![7, 4, 5, 6, 0, 11, 2], .. Machine::new() };

        assert_eq!(0, m.loc());
        m.step();
        assert_eq!(&vec![7, 4, 5, 6, 13, 11, 2], m.dump());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_8() {
        // M[A] <- M[B] - M[C]
        let mut m = Machine { memory: vec![8, 4, 5, 6, 0, 11, 2], .. Machine::new() };

        assert_eq!(0, m.loc());
        m.step();
        assert_eq!(&vec![8, 4, 5, 6, 9, 11, 2], m.dump());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_9() {
        // M[A] <- M[B] * M[C]
        let mut m = Machine { memory: vec![9, 4, 5, 6, 0, 11, 2], .. Machine::new() };

        assert_eq!(0, m.loc());
        m.step();
        assert_eq!(&vec![9, 4, 5, 6, 22, 11, 2], m.dump());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_10() {
        // M[A] <- M[B] / M[C]
        let mut m = Machine { memory: vec![10, 4, 5, 6, 0, 11, 2], .. Machine::new() };

        assert_eq!(0, m.loc());
        m.step();
        assert_eq!(&vec![10, 4, 5, 6, 5, 11, 2], m.dump());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_11() {
        // M[A] <- M[B] % M[C]
        let mut m = Machine { memory: vec![11, 4, 5, 6, 0, 11, 2], .. Machine::new() };

        assert_eq!(0, m.loc());
        m.step();
        assert_eq!(&vec![11, 4, 5, 6, 1, 11, 2], m.dump());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_12_then_branch() {
        // If M[B] < M[C], then M[A] <- 1, else M[A] <- 0
        let mut m = Machine { memory: vec![12, 4, 5, 6, 2, 8, 9], .. Machine::new() };

        assert_eq!(0, m.loc());
        m.step();
        assert_eq!(&vec![12, 4, 5, 6, 1, 8, 9], m.dump());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_12_else_branch() {
        // If M[B] < M[C], then M[A] <- 1, else M[A] <- 0
        let mut m = Machine { memory: vec![12, 4, 5, 6, 2, 9, 8], .. Machine::new() };

        assert_eq!(0, m.loc());
        m.step();
        assert_eq!(&vec![12, 4, 5, 6, 0, 9, 8], m.dump());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_13_false_false_branch() {
        // M[A] <- NOT(M[B] AND M[C])
        let mut m = Machine { memory: vec![13, 4, 5, 6, 2, 0, 0], .. Machine::new() };

        assert_eq!(0, m.loc());
        m.step();
        assert_eq!(&vec![13, 4, 5, 6, 1, 0, 0], m.dump());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_13_false_true_branch() {
        // M[A] <- NOT(M[B] AND M[C])
        let mut m = Machine { memory: vec![13, 4, 5, 6, 2, 0, 1], .. Machine::new() };

        assert_eq!(0, m.loc());
        m.step();
        assert_eq!(&vec![13, 4, 5, 6, 1, 0, 1], m.dump());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_13_true_false_branch() {
        // M[A] <- NOT(M[B] AND M[C])
        let mut m = Machine { memory: vec![13, 4, 5, 6, 2, 1, 0], .. Machine::new() };

        assert_eq!(0, m.loc());
        m.step();
        assert_eq!(&vec![13, 4, 5, 6, 1, 1, 0], m.dump());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_13_true_true_branch() {
        // M[A] <- NOT(M[B] AND M[C])
        let mut m = Machine { memory: vec![13, 4, 5, 6, 2, 1, 1], .. Machine::new() };

        assert_eq!(0, m.loc());
        m.step();
        assert_eq!(&vec![13, 4, 5, 6, 0, 1, 1], m.dump());
        assert_eq!(4, m.loc());
    }
}
<|endoftext|>