<commit_before>extern crate atoi;
extern crate bit_vec;
#[macro_use]
extern crate bitflags;
extern crate byteorder;
extern crate chrono;
#[macro_use]
extern crate lazy_static;
extern crate regex;
#[cfg(feature = "rustc_serialize")]
pub extern crate rustc_serialize;
pub extern crate serde;
pub extern crate serde_json;
extern crate smallvec;
extern crate time;
extern crate twox_hash;
pub extern crate uuid;

/// Macro to conveniently generate named parameters for a statement.
/// Parameter name is `T` where `String: From<T>`, and
///
/// ```ignore
/// params! {
///     "param_name_1" => param_value_1,
///     "param_name_2" => param_value_2,
/// }
/// ```
#[macro_export]
macro_rules! params {
    ($($name:expr => $value:expr),*) => (
        vec![
            $((::std::string::String::from($name), $crate::value::Value::from($value))),*
        ]
    );
    ($($name:expr => $value:expr),*,) => (
        params!($($name => $value),*)
    );
}

/// Non panicking Slice::split_at
macro_rules! split_at_or_err {
    ($reader:expr, $at:expr, $msg:expr) => {
        if $reader.len() >= $at {
            Ok($reader.split_at($at))
        } else {
            Err(io::Error::new(io::ErrorKind::UnexpectedEof, $msg))
        }
    };
}

/// Reads MySql's length-encoded string
#[macro_export]
macro_rules! read_lenenc_str {
    ($reader:expr) => {
        $reader.read_lenenc_int().and_then(|len| {
            let (value, rest) = split_at_or_err!($reader,
                                                 len as usize,
                                                 "EOF while reading length-encoded string")?;
            *$reader = rest;
            Ok(value)
        })
    };
}

pub mod constants;
pub mod io;
pub mod named_params;
#[macro_use]
pub mod packets;
pub mod params;
pub mod row;
pub mod value;
<commit_msg>Reexport chrono and time<commit_after>extern crate atoi;
extern crate bit_vec;
#[macro_use]
extern crate bitflags;
extern crate byteorder;
pub extern crate chrono;
#[macro_use]
extern crate lazy_static;
extern crate regex;
#[cfg(feature = "rustc_serialize")]
pub extern crate rustc_serialize;
pub extern crate serde;
pub extern crate serde_json;
extern crate smallvec;
pub extern crate time;
extern crate twox_hash;
pub extern crate uuid;

/// Macro to conveniently generate named parameters for a statement.
/// Parameter name is `T` where `String: From<T>`, and
///
/// ```ignore
/// params! {
///     "param_name_1" => param_value_1,
///     "param_name_2" => param_value_2,
/// }
/// ```
#[macro_export]
macro_rules! params {
    ($($name:expr => $value:expr),*) => (
        vec![
            $((::std::string::String::from($name), $crate::value::Value::from($value))),*
        ]
    );
    ($($name:expr => $value:expr),*,) => (
        params!($($name => $value),*)
    );
}

/// Non panicking Slice::split_at
macro_rules! split_at_or_err {
    ($reader:expr, $at:expr, $msg:expr) => {
        if $reader.len() >= $at {
            Ok($reader.split_at($at))
        } else {
            Err(io::Error::new(io::ErrorKind::UnexpectedEof, $msg))
        }
    };
}

/// Reads MySql's length-encoded string
#[macro_export]
macro_rules! read_lenenc_str {
    ($reader:expr) => {
        $reader.read_lenenc_int().and_then(|len| {
            let (value, rest) = split_at_or_err!($reader,
                                                 len as usize,
                                                 "EOF while reading length-encoded string")?;
            *$reader = rest;
            Ok(value)
        })
    };
}

pub mod constants;
pub mod io;
pub mod named_params;
#[macro_use]
pub mod packets;
pub mod params;
pub mod row;
pub mod value;
<|endoftext|>


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

// What does this do? You'll never guess!
type HeapId<'a> = PhantomData<std::cell::Cell<&'a mut ()>>;

// The heap is (for now) just a big Vec of Pairs
pub struct Heap<'a> {
    id: HeapId<'a>,
    storage: Vec<PairStorage<'a>>,
    freelist: *mut PairStorage<'a>,
    pins: RefCell<HashMap<*mut PairStorage<'a>, usize>>
}

pub const HEAP_SIZE: usize = 10000;

/// Create a heap, pass it to a callback, then destroy the heap.
///
/// The heap's lifetime is directly tied to this function call, for safety. (So
/// the API is a little wonky --- but how many heaps were you planning on
/// creating?)
pub fn with_heap<F, O>(f: F) -> O
    where F: for<'a> FnOnce(&mut Heap<'a>) -> O
{
    f(&mut Heap::new())
}

/// Trait implemented by all types that can be stored directly in the GC heap:
/// the `Storage` types associated with any `HeapInline` or `HeapRef` type.
///
/// XXX maybe this should not be its own trait - fold into HeapInline?
///
unsafe trait Mark {
    unsafe fn mark(ptr: *mut Self);
}

/// Trait implemented by all types that can be stored in fields of structs (or,
/// eventually, elements of GCVecs) that are stored in the GC heap.
unsafe trait HeapInline<'a> {
    /// The type of the value when it is physically stored in the heap.
    type Storage: Mark;

    /// Extract the value from the heap. Do not under any circumstances call
    /// this.  It is for macro-generated code to call; it is impossible for
    /// ordinary users to call this safely, because `ptr` must be a direct,
    /// unwrapped reference to a value stored in the GC heap, which ordinary
    /// users cannot obtain.
    ///
    /// This turns any raw pointers in the `Storage` value into safe
    /// references, so while it's a dangerous function, the result of a correct
    /// call can be safely handed out to user code.
    ///
    unsafe fn from_heap(heap: &Heap<'a>, ptr: &Self::Storage) -> Self;

    /// Convert the value to the form it should have in the heap.
    /// This is for macro-generated code to call.
    fn to_heap(self) -> Self::Storage;
}

impl<'a> Heap<'a> {
    fn new() -> Heap<'a> {
        // Allocate with the full capacity so that allocated Pairs never move
        let mut h = Heap {
            id: PhantomData,
            storage: Vec::with_capacity(HEAP_SIZE),
            freelist: std::ptr::null_mut(),
            pins: RefCell::new(HashMap::new())
        };
        for i in 0 .. HEAP_SIZE {
            h.storage.push(PairStorage {
                marked: false,
                head: ValueStorage::Null,
                tail: ValueStorage::Null
            });
            let p = &mut h.storage[i] as *mut PairStorage<'a>;
            unsafe {
                h.add_to_free_list(p);
            }
        }
        h
    }

    fn pin(&self, p: *mut PairStorage<'a>) {
        let mut pins = self.pins.borrow_mut();
        let entry = pins.entry(p).or_insert(0);
        *entry += 1;
    }

    fn unpin(&self, p: *mut PairStorage<'a>) {
        let mut pins = self.pins.borrow_mut();
        if {
            let entry = pins.entry(p).or_insert(0);
            assert!(*entry != 0);
            *entry -= 1;
            *entry == 0
        } {
            pins.remove(&p);
        }
    }

    unsafe fn add_to_free_list(&mut self, p: *mut PairStorage<'a>) {
        let listp: *mut *mut PairStorage<'a> = std::mem::transmute(p);
        *listp = self.freelist;
        assert_eq!(*listp, self.freelist);
        self.freelist = p;
    }

    pub fn try_alloc(&mut self, pair: (Value<'a>, Value<'a>)) -> Option<Pair<'a>> {
        if self.freelist.is_null() {
            unsafe {
                self.gc();
            }
            if self.freelist.is_null() {
                return None;
            }
        }

        let p = self.freelist;
        unsafe {
            let listp: *mut *mut PairStorage<'a> = std::mem::transmute(p);
            self.freelist = *listp;

            let (h, t) = pair;
            *p = PairStorage {
                marked: false,
                head: h.to_heap(),
                tail: t.to_heap()
            };
            Some(Pair::new(self, p))
        }
    }

    pub fn alloc(&mut self, pair: (Value<'a>, Value<'a>)) -> Pair<'a> {
        self.try_alloc(pair).expect("out of memory (gc did not collect anything)")
    }

    pub fn alloc_null(&mut self) -> Pair<'a> {
        self.alloc((Value::Null, Value::Null))
    }

    unsafe fn gc(&mut self) {
        // clear mark bits
        for p in &mut self.storage {
            p.marked = false;
        }

        // mark phase
        for (&p, _) in self.pins.borrow().iter() {
            Mark::mark(p);
        }

        // sweep phase
        self.freelist = std::ptr::null_mut();
        for i in 0 .. HEAP_SIZE {
            let p = &mut self.storage[i] as *mut PairStorage<'a>;
            if !(*p).marked {
                self.add_to_free_list(p);
            }
        }
    }

    #[cfg(test)]
    pub fn force_gc(&mut self) {
        unsafe { self.gc(); }
    }
}

// === Pair, the reference type

// PairStorage is the only type that is actually allocated inside the heap (private)
struct PairStorage<'a> {
    marked: bool,
    head: ValueStorage<'a>,
    tail: ValueStorage<'a>
}

unsafe impl<'a> Mark for PairStorage<'a> {
    unsafe fn mark(ptr: *mut PairStorage<'a>) {
        if !ptr.is_null() && !(*ptr).marked {
            (*ptr).marked = true;
            Mark::mark(&mut (*ptr).head as *mut ValueStorage<'a>);
            Mark::mark(&mut (*ptr).tail as *mut ValueStorage<'a>);
        }
    }
}

// Handle to a PairStorage that lives in the heap.
#[allow(raw_pointer_derive)]
#[derive(Debug, PartialEq)]
pub struct Pair<'a> {
    ptr: *mut PairStorage<'a>,
    heap: *const Heap<'a>,
    heap_id: HeapId<'a>
}

impl<'a> Drop for Pair<'a> {
    fn drop(&mut self) {
        unsafe {
            (*self.heap).unpin(self.ptr);
        }
    }
}

impl<'a> Clone for Pair<'a> {
    fn clone(&self) -> Pair<'a> {
        let &Pair { ptr, heap, heap_id } = self;
        unsafe {
            (*heap).pin(ptr);
        }
        Pair {
            ptr: ptr,
            heap: heap,
            heap_id: heap_id
        }
    }
}

impl<'a> Pair<'a> {
    unsafe fn new(heap: &Heap<'a>, p: *mut PairStorage<'a>) -> Pair<'a> {
        heap.pin(p);
        Pair {
            ptr: p,
            heap: heap as *const Heap<'a>,
            heap_id: heap.id
        }
    }

    pub fn head(&self) -> Value<'a> {
        let ptr = self.ptr;
        unsafe { Value::from_heap(&*self.heap, &(*ptr).head) }
    }

    pub fn tail(&self) -> Value<'a> {
        let ptr = self.ptr;
        unsafe { Value::from_heap(&*self.heap, &(*ptr).tail) }
    }

    pub fn set_head(&self, v: Value<'a>) {
        let ptr = self.ptr;
        unsafe { (*ptr).head = v.to_heap(); }
    }

    pub fn set_tail(&self, v: Value<'a>) {
        let ptr = self.ptr;
        unsafe { (*ptr).tail = v.to_heap(); }
    }

    #[cfg(test)]
    pub fn address(&self) -> usize {
        unsafe { std::mem::transmute(self.ptr) }
    }
}

// === Values (a heap-inline enum)

// Values inside the heap (GC heap-to-heap cross-references) (private)
enum ValueStorage<'a> {
    Null,
    Int(i32),
    Str(Rc<String>),
    Pair(*mut PairStorage<'a>, HeapId<'a>)
}

unsafe impl<'a> Mark for ValueStorage<'a> {
    unsafe fn mark(ptr: *mut ValueStorage<'a>) {
        match *ptr {
            ValueStorage::Pair(p, _) => Mark::mark(p),
            _ => {}
        }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub enum Value<'a> {
    Null,
    Int(i32),
    Str(Rc<String>),  // <-- equality is by value
    Pair(Pair<'a>)  // <-- equality is by pointer
}

unsafe impl<'a> HeapInline<'a> for Value<'a> {
    type Storage = ValueStorage<'a>;

    fn to_heap(self) -> ValueStorage<'a> {
        match self {
            Value::Null => ValueStorage::Null,
            Value::Int(n) => ValueStorage::Int(n),
            Value::Str(rcstr) => ValueStorage::Str(rcstr),
            Value::Pair(Pair{ptr, heap_id, ..}) => ValueStorage::Pair(ptr, heap_id)
        }
    }

    unsafe fn from_heap(heap: &Heap<'a>, v: &ValueStorage<'a>) -> Value<'a> {
        match v {
            &ValueStorage::Null => Value::Null,
            &ValueStorage::Int(n) => Value::Int(n),
            &ValueStorage::Str(ref rcstr) => Value::Str(rcstr.clone()),
            &ValueStorage::Pair(ptr, _) => Value::Pair(Pair::new(heap, ptr))
        }
    }
}

#[cfg(test)]
mod test;
<commit_msg>Auto-implement `HeapInline` for all `Copy` types!<commit_after>use std::rc::Rc;
use std::cell::RefCell;
use std::collections::HashMap;
use std::marker::PhantomData;

// What does this do? You'll never guess!
type HeapId<'a> = PhantomData<std::cell::Cell<&'a mut ()>>;

// The heap is (for now) just a big Vec of Pairs
pub struct Heap<'a> {
    id: HeapId<'a>,
    storage: Vec<PairStorage<'a>>,
    freelist: *mut PairStorage<'a>,
    pins: RefCell<HashMap<*mut PairStorage<'a>, usize>>
}

pub const HEAP_SIZE: usize = 10000;

/// Create a heap, pass it to a callback, then destroy the heap.
///
/// The heap's lifetime is directly tied to this function call, for safety. (So
/// the API is a little wonky --- but how many heaps were you planning on
/// creating?)
pub fn with_heap<F, O>(f: F) -> O
    where F: for<'a> FnOnce(&mut Heap<'a>) -> O
{
    f(&mut Heap::new())
}

/// Trait implemented by all types that can be stored directly in the GC heap:
/// the `Storage` types associated with any `HeapInline` or `HeapRef` type.
///
/// XXX maybe this should not be its own trait - fold into HeapInline?
///
unsafe trait Mark {
    unsafe fn mark(ptr: *mut Self);
}

/// Trait implemented by all types that can be stored in fields of structs (or,
/// eventually, elements of GCVecs) that are stored in the GC heap.
unsafe trait HeapInline<'a> {
    /// The type of the value when it is physically stored in the heap.
    type Storage: Mark;

    /// Extract the value from the heap. Do not under any circumstances call
    /// this.  It is for macro-generated code to call; it is impossible for
    /// ordinary users to call this safely, because `ptr` must be a direct,
    /// unwrapped reference to a value stored in the GC heap, which ordinary
    /// users cannot obtain.
    ///
    /// This turns any raw pointers in the `Storage` value into safe
    /// references, so while it's a dangerous function, the result of a correct
    /// call can be safely handed out to user code.
    ///
    unsafe fn from_heap(heap: &Heap<'a>, ptr: &Self::Storage) -> Self;

    /// Convert the value to the form it should have in the heap.
    /// This is for macro-generated code to call.
    fn to_heap(self) -> Self::Storage;
}

impl<'a> Heap<'a> {
    fn new() -> Heap<'a> {
        // Allocate with the full capacity so that allocated Pairs never move
        let mut h = Heap {
            id: PhantomData,
            storage: Vec::with_capacity(HEAP_SIZE),
            freelist: std::ptr::null_mut(),
            pins: RefCell::new(HashMap::new())
        };
        for i in 0 .. HEAP_SIZE {
            h.storage.push(PairStorage {
                marked: false,
                head: ValueStorage::Null,
                tail: ValueStorage::Null
            });
            let p = &mut h.storage[i] as *mut PairStorage<'a>;
            unsafe {
                h.add_to_free_list(p);
            }
        }
        h
    }

    fn pin(&self, p: *mut PairStorage<'a>) {
        let mut pins = self.pins.borrow_mut();
        let entry = pins.entry(p).or_insert(0);
        *entry += 1;
    }

    fn unpin(&self, p: *mut PairStorage<'a>) {
        let mut pins = self.pins.borrow_mut();
        if {
            let entry = pins.entry(p).or_insert(0);
            assert!(*entry != 0);
            *entry -= 1;
            *entry == 0
        } {
            pins.remove(&p);
        }
    }

    unsafe fn add_to_free_list(&mut self, p: *mut PairStorage<'a>) {
        let listp: *mut *mut PairStorage<'a> = std::mem::transmute(p);
        *listp = self.freelist;
        assert_eq!(*listp, self.freelist);
        self.freelist = p;
    }

    pub fn try_alloc(&mut self, pair: (Value<'a>, Value<'a>)) -> Option<Pair<'a>> {
        if self.freelist.is_null() {
            unsafe {
                self.gc();
            }
            if self.freelist.is_null() {
                return None;
            }
        }

        let p = self.freelist;
        unsafe {
            let listp: *mut *mut PairStorage<'a> = std::mem::transmute(p);
            self.freelist = *listp;

            let (h, t) = pair;
            *p = PairStorage {
                marked: false,
                head: h.to_heap(),
                tail: t.to_heap()
            };
            Some(Pair::new(self, p))
        }
    }

    pub fn alloc(&mut self, pair: (Value<'a>, Value<'a>)) -> Pair<'a> {
        self.try_alloc(pair).expect("out of memory (gc did not collect anything)")
    }

    pub fn alloc_null(&mut self) -> Pair<'a> {
        self.alloc((Value::Null, Value::Null))
    }

    unsafe fn gc(&mut self) {
        // clear mark bits
        for p in &mut self.storage {
            p.marked = false;
        }

        // mark phase
        for (&p, _) in self.pins.borrow().iter() {
            Mark::mark(p);
        }

        // sweep phase
        self.freelist = std::ptr::null_mut();
        for i in 0 .. HEAP_SIZE {
            let p = &mut self.storage[i] as *mut PairStorage<'a>;
            if !(*p).marked {
                self.add_to_free_list(p);
            }
        }
    }

    #[cfg(test)]
    pub fn force_gc(&mut self) {
        unsafe { self.gc(); }
    }
}

// === Pair, the reference type

// PairStorage is the only type that is actually allocated inside the heap (private)
struct PairStorage<'a> {
    marked: bool,
    head: ValueStorage<'a>,
    tail: ValueStorage<'a>
}

unsafe impl<'a> Mark for PairStorage<'a> {
    unsafe fn mark(ptr: *mut PairStorage<'a>) {
        if !ptr.is_null() && !(*ptr).marked {
            (*ptr).marked = true;
            Mark::mark(&mut (*ptr).head as *mut ValueStorage<'a>);
            Mark::mark(&mut (*ptr).tail as *mut ValueStorage<'a>);
        }
    }
}

// Handle to a PairStorage that lives in the heap.
#[allow(raw_pointer_derive)]
#[derive(Debug, PartialEq)]
pub struct Pair<'a> {
    ptr: *mut PairStorage<'a>,
    heap: *const Heap<'a>,
    heap_id: HeapId<'a>
}

impl<'a> Drop for Pair<'a> {
    fn drop(&mut self) {
        unsafe {
            (*self.heap).unpin(self.ptr);
        }
    }
}

impl<'a> Clone for Pair<'a> {
    fn clone(&self) -> Pair<'a> {
        let &Pair { ptr, heap, heap_id } = self;
        unsafe {
            (*heap).pin(ptr);
        }
        Pair {
            ptr: ptr,
            heap: heap,
            heap_id: heap_id
        }
    }
}

impl<'a> Pair<'a> {
    unsafe fn new(heap: &Heap<'a>, p: *mut PairStorage<'a>) -> Pair<'a> {
        heap.pin(p);
        Pair {
            ptr: p,
            heap: heap as *const Heap<'a>,
            heap_id: heap.id
        }
    }

    pub fn head(&self) -> Value<'a> {
        let ptr = self.ptr;
        unsafe { Value::from_heap(&*self.heap, &(*ptr).head) }
    }

    pub fn tail(&self) -> Value<'a> {
        let ptr = self.ptr;
        unsafe { Value::from_heap(&*self.heap, &(*ptr).tail) }
    }

    pub fn set_head(&self, v: Value<'a>) {
        let ptr = self.ptr;
        unsafe { (*ptr).head = v.to_heap(); }
    }

    pub fn set_tail(&self, v: Value<'a>) {
        let ptr = self.ptr;
        unsafe { (*ptr).tail = v.to_heap(); }
    }

    #[cfg(test)]
    pub fn address(&self) -> usize {
        unsafe { std::mem::transmute(self.ptr) }
    }
}

// === Values (a heap-inline enum)

// Values inside the heap (GC heap-to-heap cross-references) (private)
enum ValueStorage<'a> {
    Null,
    Int(i32),
    Str(Rc<String>),
    Pair(*mut PairStorage<'a>, HeapId<'a>)
}

unsafe impl<'a> Mark for ValueStorage<'a> {
    unsafe fn mark(ptr: *mut ValueStorage<'a>) {
        match *ptr {
            ValueStorage::Pair(p, _) => Mark::mark(p),
            _ => {}
        }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub enum Value<'a> {
    Null,
    Int(i32),
    Str(Rc<String>),  // <-- equality is by value
    Pair(Pair<'a>)  // <-- equality is by pointer
}

unsafe impl<'a> HeapInline<'a> for Value<'a> {
    type Storage = ValueStorage<'a>;

    fn to_heap(self) -> ValueStorage<'a> {
        match self {
            Value::Null => ValueStorage::Null,
            Value::Int(n) => ValueStorage::Int(n),
            Value::Str(rcstr) => ValueStorage::Str(rcstr),
            Value::Pair(Pair{ptr, heap_id, ..}) => ValueStorage::Pair(ptr, heap_id)
        }
    }

    unsafe fn from_heap(heap: &Heap<'a>, v: &ValueStorage<'a>) -> Value<'a> {
        match v {
            &ValueStorage::Null => Value::Null,
            &ValueStorage::Int(n) => Value::Int(n),
            &ValueStorage::Str(ref rcstr) => Value::Str(rcstr.clone()),
            &ValueStorage::Pair(ptr, _) => Value::Pair(Pair::new(heap, ptr))
        }
    }
}

unsafe impl<T: Copy> Mark for T {
    unsafe fn mark(_ptr: *mut T) {}
}

unsafe impl<'a, T: Copy> HeapInline<'a> for T {
    type Storage = Self;

    fn to_heap(self) -> T { self }

    unsafe fn from_heap(_heap: &Heap<'a>, v: &T) -> T { *v }
}

#[cfg(test)]
mod test;
<|endoftext|>


<commit_before>use serial::{Serial, SerialCallback};
use timer::Timer;
use keypad::Keypad;
use gpu::GPU;
use sound::Sound;
use gbmode::{GbMode, GbSpeed};
use std::path;

const WRAM_SIZE: usize = 0x8000;
const ZRAM_SIZE: usize = 0x7F;

#[derive(PartialEq)]
enum DMAType {
    NoDMA,
    GDMA,
    HDMA,
}

pub struct MMU<'a> {
    wram: [u8; WRAM_SIZE],
    zram: [u8; ZRAM_SIZE],
    hdma: [u8; 4],
    pub inte: u8,
    pub intf: u8,
    pub serial: Serial<'a>,
    pub timer: Timer,
    pub keypad: Keypad,
    pub gpu: GPU,
    pub sound: Sound,
    hdma_status: DMAType,
    hdma_src: u16,
    hdma_dst: u16,
    hdma_len: u8,
    wrambank: usize,
    mbc: Box<::mbc::MBC+'static>,
    gbmode: GbMode,
    gbspeed: GbSpeed,
    speed_switch_req: bool,
}

impl<'a> MMU<'a> {
    pub fn new(romname: &str, serial_callback: Option<SerialCallback<'a>>) -> ::StrResult<MMU<'a>> {
        let mmu_mbc = try!(::mbc::get_mbc(path::PathBuf::from(romname)));
        let serial = match serial_callback {
            Some(cb) => Serial::new_with_callback(cb),
            None => Serial::new(),
        };
        let mut res = MMU {
            wram: [0; WRAM_SIZE],
            zram: [0; ZRAM_SIZE],
            hdma: [0; 4],
            wrambank: 1,
            inte: 0,
            intf: 0,
            serial: serial,
            timer: Timer::new(),
            keypad: Keypad::new(),
            gpu: GPU::new(),
            sound: Sound::new(),
            mbc: mmu_mbc,
            gbmode: GbMode::Classic,
            gbspeed: GbSpeed::Single,
            speed_switch_req: false,
            hdma_src: 0,
            hdma_dst: 0,
            hdma_status: DMAType::NoDMA,
            hdma_len: 0xFF,
        };
        if res.rb(0x0143) == 0xC0 {
            return Err("This game does not work in Classic mode");
        }
        res.set_initial();
        Ok(res)
    }

    pub fn new_cgb(romname: &str, serial_callback: Option<SerialCallback<'a>>) -> ::StrResult<MMU<'a>> {
        let mmu_mbc = try!(::mbc::get_mbc(path::PathBuf::from(romname)));
        let serial = match serial_callback {
            Some(cb) => Serial::new_with_callback(cb),
            None => Serial::new(),
        };
        let mut res = MMU {
            wram: [0; WRAM_SIZE],
            zram: [0; ZRAM_SIZE],
            wrambank: 1,
            hdma: [0; 4],
            inte: 0,
            intf: 0,
            serial: serial,
            timer: Timer::new(),
            keypad: Keypad::new(),
            gpu: GPU::new_cgb(),
            sound: Sound::new(),
            mbc: mmu_mbc,
            gbmode: GbMode::Color,
            gbspeed: GbSpeed::Single,
            speed_switch_req: false,
            hdma_src: 0,
            hdma_dst: 0,
            hdma_status: DMAType::NoDMA,
            hdma_len: 0xFF,
        };
        res.determine_mode();
        res.set_initial();
        Ok(res)
    }

    fn set_initial(&mut self) {
        self.wb(0xFF05, 0);
        self.wb(0xFF06, 0);
        self.wb(0xFF07, 0);
        self.wb(0xFF40, 0x91);
        self.wb(0xFF42, 0);
        self.wb(0xFF43, 0);
        self.wb(0xFF45, 0);
        self.wb(0xFF47, 0xFC);
        self.wb(0xFF48, 0xFF);
        self.wb(0xFF49, 0xFF);
        self.wb(0xFF4A, 0);
        self.wb(0xFF4B, 0);
    }

    fn determine_mode(&mut self) {
        let mode = match self.rb(0x0143) & 0x80 {
            0x80 => GbMode::Color,
            _ => GbMode::ColorAsClassic,
        };
        self.gbmode = mode;
        self.gpu.gbmode = mode;
    }

    pub fn do_cycle(&mut self, cputicks: u32) -> u32 {
        let cpudivider = match self.gbspeed {
            GbSpeed::Single => 1,
            GbSpeed::Double => 2,
        };
        let ticks = cputicks / cpudivider;
        let gputicks = ticks + self.perform_vramdma();

        self.timer.do_cycle(ticks);
        self.intf |= self.timer.interrupt;
        self.timer.interrupt = 0;

        self.intf |= self.keypad.interrupt;
        self.keypad.interrupt = 0;

        self.gpu.do_cycle(gputicks);
        self.intf |= self.gpu.interrupt;
        self.gpu.interrupt = 0;

        self.sound.do_cycle(gputicks);

        return gputicks;
    }

    pub fn rb(&self, address: u16) -> u8 {
        match address {
            0x0000 ... 0x7FFF => self.mbc.readrom(address),
            0x8000 ... 0x9FFF => self.gpu.rb(address),
            0xA000 ... 0xBFFF => self.mbc.readram(address),
            0xC000 ... 0xCFFF | 0xE000 ... 0xEFFF => self.wram[address as usize & 0x0FFF],
            0xD000 ... 0xDFFF | 0xF000 ... 0xFDFF => self.wram[(self.wrambank * 0x1000) | address as usize & 0x0FFF],
            0xFE00 ... 0xFE9F => self.gpu.rb(address),
            0xFF00 => self.keypad.rb(),
            0xFF01 ... 0xFF02 => self.serial.rb(address),
            0xFF04 ... 0xFF07 => self.timer.rb(address),
            0xFF0F => self.intf,
            0xFF10 ... 0xFF3F => self.sound.rb(address),
            0xFF4D => (if self.gbspeed == GbSpeed::Double { 0x80 } else { 0 }) | (if self.speed_switch_req { 1 } else { 0 }),
            0xFF40 ... 0xFF4F => self.gpu.rb(address),
            0xFF51 ... 0xFF55 => self.hdma_read(address),
            0xFF68 ... 0xFF6B => self.gpu.rb(address),
            0xFF70 => self.wrambank as u8,
            0xFF80 ... 0xFFFE => self.zram[address as usize & 0x007F],
            0xFFFF => self.inte,
            _ => 0,
        }
    }

    pub fn rw(&self, address: u16) -> u16 {
        (self.rb(address) as u16) | ((self.rb(address + 1) as u16) << 8)
    }

    pub fn wb(&mut self, address: u16, value: u8) {
        match address {
            0x0000 ... 0x7FFF => self.mbc.writerom(address, value),
            0x8000 ... 0x9FFF => self.gpu.wb(address, value),
            0xA000 ... 0xBFFF => self.mbc.writeram(address, value),
            0xC000 ... 0xCFFF | 0xE000 ... 0xEFFF => self.wram[address as usize & 0x0FFF] = value,
            0xD000 ... 0xDFFF | 0xF000 ... 0xFDFF => self.wram[(self.wrambank * 0x1000) | (address as usize & 0x0FFF)] = value,
            0xFE00 ... 0xFE9F => self.gpu.wb(address, value),
            0xFF00 => self.keypad.wb(value),
            0xFF01 ... 0xFF02 => self.serial.wb(address, value),
            0xFF04 ... 0xFF07 => self.timer.wb(address, value),
            0xFF10 ... 0xFF3F => self.sound.wb(address, value),
            0xFF46 => self.oamdma(value),
            0xFF4D => if value & 0x1 == 0x1 { self.speed_switch_req = true; },
            0xFF40 ... 0xFF4F => self.gpu.wb(address, value),
            0xFF51 ... 0xFF55 => self.hdma_write(address, value),
            0xFF68 ... 0xFF6B => self.gpu.wb(address, value),
            0xFF0F => self.intf = value,
            0xFF70 => { self.wrambank = match value & 0x7 { 0 => 1, n => n as usize }; },
            0xFF80 ... 0xFFFE => self.zram[address as usize & 0x007F] = value,
            0xFFFF => self.inte = value,
            _ => {},
        };
    }

    pub fn ww(&mut self, address: u16, value: u16) {
        self.wb(address, (value & 0xFF) as u8);
        self.wb(address + 1, (value >> 8) as u8);
    }

    pub fn switch_speed(&mut self) {
        if self.speed_switch_req {
            if self.gbspeed == GbSpeed::Double {
                self.gbspeed = GbSpeed::Single;
            } else {
                self.gbspeed = GbSpeed::Double;
            }
        }
        self.speed_switch_req = false;
    }

    fn oamdma(&mut self, value: u8) {
        let base = (value as u16) << 8;
        for i in (0u16 .. 0xA0) {
            let b = self.rb(base + i);
            self.wb(0xFE00 + i, b);
        }
    }

    fn hdma_read(&self, a: u16) -> u8 {
        match a {
            0xFF51 ... 0xFF54 => { self.hdma[(a - 0xFF51) as usize] },
            0xFF55 => self.hdma_len | if self.hdma_status == DMAType::NoDMA { 0x80 } else { 0 },
            _ => panic!("The address {:04X} should not be handled by hdma_read", a),
        }
    }

    fn hdma_write(&mut self, a: u16, v: u8) {
        match a {
            0xFF51 => self.hdma[0] = v,
            0xFF52 => self.hdma[1] = v & 0xF0,
            0xFF53 => self.hdma[2] = v & 0x1F,
            0xFF54 => self.hdma[3] = v & 0xF0,
            0xFF55 => {
                if self.hdma_status == DMAType::HDMA {
                    if v & 0x80 == 0 { self.hdma_status = DMAType::NoDMA; };
                    return;
                }
                let src = ((self.hdma[0] as u16) << 8) | (self.hdma[1] as u16);
                let dst = ((self.hdma[2] as u16) << 8) | (self.hdma[3] as u16) | 0x8000;
                if !(src <= 0x7FF0 || (src >= 0xA000 && src <= 0xDFF0)) { panic!("HDMA transfer with illegal start address {:04X}", src); }

                self.hdma_src = src;
                self.hdma_dst = dst;
                self.hdma_len = v & 0x7F;

                self.hdma_status =
                    if v & 0x80 == 0x80 { DMAType::HDMA }
                    else { DMAType::GDMA };
            },
            _ => panic!("The address {:04X} should not be handled by hdma_write", a),
        };
    }

    fn perform_vramdma(&mut self) -> u32 {
        match self.hdma_status {
            DMAType::NoDMA => 0,
            DMAType::GDMA => self.perform_gdma(),
            DMAType::HDMA => self.perform_hdma(),
        }
    }

    fn perform_hdma(&mut self) -> u32 {
        if self.gpu.may_hdma() == false || self.hdma_len == 0xFF {
            return 0;
        }

        self.perform_vramdma_row();
        if self.hdma_len == 0xFF { self.hdma_status = DMAType::NoDMA; }

        return 0x10 * 8;
    }

    fn perform_gdma(&mut self) -> u32 {
        let len = self.hdma_len as u32 + 1;
        for _i in (0 .. len) {
            self.perform_vramdma_row();
        }

        self.hdma_status = DMAType::NoDMA;
        return len * 0x10 * 8;
    }

    fn perform_vramdma_row(&mut self) {
        for j in (0u16 .. 0x10) {
            let b: u8 = self.rb(self.hdma_src + j);
            self.gpu.wb(self.hdma_dst + j, b);
        }
        self.hdma_src += 0x10;
        self.hdma_dst += 0x10;
        self.hdma_len.wrapping_sub(1);
    }
}
<commit_msg>Fix VRAM (G/H)DMA<commit_after>use serial::{Serial, SerialCallback};
use timer::Timer;
use keypad::Keypad;
use gpu::GPU;
use sound::Sound;
use gbmode::{GbMode, GbSpeed};
use std::path;

const WRAM_SIZE: usize = 0x8000;
const ZRAM_SIZE: usize = 0x7F;

#[derive(PartialEq)]
enum DMAType {
    NoDMA,
    GDMA,
    HDMA,
}

pub struct MMU<'a> {
    wram: [u8; WRAM_SIZE],
    zram: [u8; ZRAM_SIZE],
    hdma: [u8; 4],
    pub inte: u8,
    pub intf: u8,
    pub serial: Serial<'a>,
    pub timer: Timer,
    pub keypad: Keypad,
    pub gpu: GPU,
    pub sound: Sound,
    hdma_status: DMAType,
    hdma_src: u16,
    hdma_dst: u16,
    hdma_len: u8,
    wrambank: usize,
    mbc: Box<::mbc::MBC+'static>,
    gbmode: GbMode,
    gbspeed: GbSpeed,
    speed_switch_req: bool,
}

impl<'a> MMU<'a> {
    pub fn new(romname: &str, serial_callback: Option<SerialCallback<'a>>) -> ::StrResult<MMU<'a>> {
        let mmu_mbc = try!(::mbc::get_mbc(path::PathBuf::from(romname)));
        let serial = match serial_callback {
            Some(cb) => Serial::new_with_callback(cb),
            None => Serial::new(),
        };
        let mut res = MMU {
            wram: [0; WRAM_SIZE],
            zram: [0; ZRAM_SIZE],
            hdma: [0; 4],
            wrambank: 1,
            inte: 0,
            intf: 0,
            serial: serial,
            timer: Timer::new(),
            keypad: Keypad::new(),
            gpu: GPU::new(),
            sound: Sound::new(),
            mbc: mmu_mbc,
            gbmode: GbMode::Classic,
            gbspeed: GbSpeed::Single,
            speed_switch_req: false,
            hdma_src: 0,
            hdma_dst: 0,
            hdma_status: DMAType::NoDMA,
            hdma_len: 0xFF,
        };
        if res.rb(0x0143) == 0xC0 {
            return Err("This game does not work in Classic mode");
        }
        res.set_initial();
        Ok(res)
    }

    pub fn new_cgb(romname: &str, serial_callback: Option<SerialCallback<'a>>) -> ::StrResult<MMU<'a>> {
        let mmu_mbc = try!(::mbc::get_mbc(path::PathBuf::from(romname)));
        let serial = match serial_callback {
            Some(cb) => Serial::new_with_callback(cb),
            None => Serial::new(),
        };
        let mut res = MMU {
            wram: [0; WRAM_SIZE],
            zram: [0; ZRAM_SIZE],
            wrambank: 1,
            hdma: [0; 4],
            inte: 0,
            intf: 0,
            serial: serial,
            timer: Timer::new(),
            keypad: Keypad::new(),
            gpu: GPU::new_cgb(),
            sound: Sound::new(),
            mbc: mmu_mbc,
            gbmode: GbMode::Color,
            gbspeed: GbSpeed::Single,
            speed_switch_req: false,
            hdma_src: 0,
            hdma_dst: 0,
            hdma_status: DMAType::NoDMA,
            hdma_len: 0xFF,
        };
        res.determine_mode();
        res.set_initial();
        Ok(res)
    }

    fn set_initial(&mut self) {
        self.wb(0xFF05, 0);
        self.wb(0xFF06, 0);
        self.wb(0xFF07, 0);
        self.wb(0xFF40, 0x91);
        self.wb(0xFF42, 0);
        self.wb(0xFF43, 0);
        self.wb(0xFF45, 0);
        self.wb(0xFF47, 0xFC);
        self.wb(0xFF48, 0xFF);
        self.wb(0xFF49, 0xFF);
        self.wb(0xFF4A, 0);
        self.wb(0xFF4B, 0);
    }

    fn determine_mode(&mut self) {
        let mode = match self.rb(0x0143) & 0x80 {
            0x80 => GbMode::Color,
            _ => GbMode::ColorAsClassic,
        };
        self.gbmode = mode;
        self.gpu.gbmode = mode;
    }

    pub fn do_cycle(&mut self, cputicks: u32) -> u32 {
        let cpudivider = match self.gbspeed {
            GbSpeed::Single => 1,
            GbSpeed::Double => 2,
        };
        let ticks = cputicks / cpudivider;
        let gputicks = ticks + self.perform_vramdma();

        self.timer.do_cycle(ticks);
        self.intf |= self.timer.interrupt;
        self.timer.interrupt = 0;

        self.intf |= self.keypad.interrupt;
        self.keypad.interrupt = 0;

        self.gpu.do_cycle(gputicks);
        self.intf |= self.gpu.interrupt;
        self.gpu.interrupt = 0;

        self.sound.do_cycle(gputicks);

        return gputicks;
    }

    pub fn rb(&self, address: u16) -> u8 {
        match address {
            0x0000 ... 0x7FFF => self.mbc.readrom(address),
            0x8000 ... 0x9FFF => self.gpu.rb(address),
            0xA000 ... 0xBFFF => self.mbc.readram(address),
            0xC000 ... 0xCFFF | 0xE000 ... 0xEFFF => self.wram[address as usize & 0x0FFF],
            0xD000 ... 0xDFFF | 0xF000 ... 0xFDFF => self.wram[(self.wrambank * 0x1000) | address as usize & 0x0FFF],
            0xFE00 ... 0xFE9F => self.gpu.rb(address),
            0xFF00 => self.keypad.rb(),
            0xFF01 ... 0xFF02 => self.serial.rb(address),
            0xFF04 ... 0xFF07 => self.timer.rb(address),
            0xFF0F => self.intf,
            0xFF10 ... 0xFF3F => self.sound.rb(address),
            0xFF4D => (if self.gbspeed == GbSpeed::Double { 0x80 } else { 0 }) | (if self.speed_switch_req { 1 } else { 0 }),
            0xFF40 ... 0xFF4F => self.gpu.rb(address),
            0xFF51 ... 0xFF55 => self.hdma_read(address),
            0xFF68 ... 0xFF6B => self.gpu.rb(address),
            0xFF70 => self.wrambank as u8,
            0xFF80 ... 0xFFFE => self.zram[address as usize & 0x007F],
            0xFFFF => self.inte,
            _ => 0,
        }
    }

    pub fn rw(&self, address: u16) -> u16 {
        (self.rb(address) as u16) | ((self.rb(address + 1) as u16) << 8)
    }

    pub fn wb(&mut self, address: u16, value: u8) {
        match address {
            0x0000 ... 0x7FFF => self.mbc.writerom(address, value),
            0x8000 ... 0x9FFF => self.gpu.wb(address, value),
            0xA000 ... 0xBFFF => self.mbc.writeram(address, value),
            0xC000 ... 0xCFFF | 0xE000 ... 0xEFFF => self.wram[address as usize & 0x0FFF] = value,
            0xD000 ... 0xDFFF | 0xF000 ... 0xFDFF => self.wram[(self.wrambank * 0x1000) | (address as usize & 0x0FFF)] = value,
            0xFE00 ... 0xFE9F => self.gpu.wb(address, value),
            0xFF00 => self.keypad.wb(value),
            0xFF01 ... 0xFF02 => self.serial.wb(address, value),
            0xFF04 ... 0xFF07 => self.timer.wb(address, value),
            0xFF10 ... 0xFF3F => self.sound.wb(address, value),
            0xFF46 => self.oamdma(value),
            0xFF4D => if value & 0x1 == 0x1 { self.speed_switch_req = true; },
            0xFF40 ... 0xFF4F => self.gpu.wb(address, value),
            0xFF51 ... 0xFF55 => self.hdma_write(address, value),
            0xFF68 ... 0xFF6B => self.gpu.wb(address, value),
            0xFF0F => self.intf = value,
            0xFF70 => { self.wrambank = match value & 0x7 { 0 => 1, n => n as usize }; },
            0xFF80 ... 0xFFFE => self.zram[address as usize & 0x007F] = value,
            0xFFFF => self.inte = value,
            _ => {},
        };
    }

    pub fn ww(&mut self, address: u16, value: u16) {
        self.wb(address, (value & 0xFF) as u8);
        self.wb(address + 1, (value >> 8) as u8);
    }

    pub fn switch_speed(&mut self) {
        if self.speed_switch_req {
            if self.gbspeed == GbSpeed::Double {
                self.gbspeed = GbSpeed::Single;
            } else {
                self.gbspeed = GbSpeed::Double;
            }
        }
        self.speed_switch_req = false;
    }

    fn oamdma(&mut self, value: u8) {
        let base = (value as u16) << 8;
        for i in (0u16 .. 0xA0) {
            let b = self.rb(base + i);
            self.wb(0xFE00 + i, b);
        }
    }

    fn hdma_read(&self, a: u16) -> u8 {
        match a {
            0xFF51 ... 0xFF54 => { self.hdma[(a - 0xFF51) as usize] },
            0xFF55 => self.hdma_len | if self.hdma_status == DMAType::NoDMA { 0x80 } else { 0 },
            _ => panic!("The address {:04X} should not be handled by hdma_read", a),
        }
    }

    fn hdma_write(&mut self, a: u16, v: u8) {
        match a {
            0xFF51 => self.hdma[0] = v,
            0xFF52 => self.hdma[1] = v & 0xF0,
            0xFF53 => self.hdma[2] = v & 0x1F,
            0xFF54 => self.hdma[3] = v & 0xF0,
            0xFF55 => {
                if self.hdma_status == DMAType::HDMA {
                    if v & 0x80 == 0 { self.hdma_status = DMAType::NoDMA; };
                    return;
                }
                let src = ((self.hdma[0] as u16) << 8) | (self.hdma[1] as u16);
                let dst = ((self.hdma[2] as u16) << 8) | (self.hdma[3] as u16) | 0x8000;
                if !(src <= 0x7FF0 || (src >= 0xA000 && src <= 0xDFF0)) { panic!("HDMA transfer with illegal start address {:04X}", src); }

                self.hdma_src = src;
                self.hdma_dst = dst;
                self.hdma_len = v & 0x7F;

                self.hdma_status =
                    if v & 0x80 == 0x80 { DMAType::HDMA }
                    else { DMAType::GDMA };
            },
            _ => panic!("The address {:04X} should not be handled by hdma_write", a),
        };
    }

    fn perform_vramdma(&mut self) -> u32 {
        match self.hdma_status {
            DMAType::NoDMA => 0,
            DMAType::GDMA => self.perform_gdma(),
            DMAType::HDMA => self.perform_hdma(),
        }
    }

    fn perform_hdma(&mut self) -> u32 {
        if self.gpu.may_hdma() == false {
            return 0;
        }

        self.perform_vramdma_row();
        if self.hdma_len == 0x7F { self.hdma_status = DMAType::NoDMA; }

        return 8;
    }

    fn perform_gdma(&mut self) -> u32 {
        let len = self.hdma_len as u32 + 1;
        for _i in (0 .. len) {
            self.perform_vramdma_row();
        }

        self.hdma_status = DMAType::NoDMA;
        return len * 8;
    }

    fn perform_vramdma_row(&mut self) {
        for j in (0u16 .. 0x10) {
            let b: u8 = self.rb(self.hdma_src + j);
            self.gpu.wb(self.hdma_dst + j, b);
        }
        self.hdma_src += 0x10;
        self.hdma_dst += 0x10;

        if self.hdma_len == 0 {
            self.hdma_len = 0x7F;
        }
        else {
            self.hdma_len -= 1;
        }
    }
}
<|endoftext|>


<commit_before>use base::{FromAscii};

trait FromStrHelper: {
    fn signed() -> bool;
}

#[derive(Debug, PartialEq)]
pub enum ParseIntError {
    Empty,
    InvalidDigit,
    Overflow,
    Underflow,
}

#[inline]
pub fn dec_to_digit(c: u8) -> Option<u8> {
    let val = match c {
        b'0' ... b'9' => c - b'0',
        _ => return None,
    };
    Some(val)
}

macro_rules! implement {
    ($t:ty, $signed: expr) => {
        impl FromStrHelper for $t {
            #[inline]
            fn signed() -> bool { $signed }
        }

        impl FromAscii for $t {
            type Err = ParseIntError;

            #[inline]
            fn from_ascii(src: &[u8]) -> Result<Self, Self::Err> {
                if src.is_empty() {
                    return Err(ParseIntError::Empty);
                }

                let (is_positive, digits) = match src[0] {
                    b'+' => (true, &src[1..]),
                    b'-' if <$t>::signed() => (false, &src[1..]),
                    _ => (true, src)
                };

                if digits.is_empty() {
                    return Err(ParseIntError::Empty);
                }

                let mut result: $t = 0;

                if is_positive {
                    for &c in digits {
                        let x = match dec_to_digit(c) {
                            Some(x) => x as $t,
                            None => return Err(ParseIntError::InvalidDigit),
                        };
                        result = match result.checked_mul(10) {
                            Some(result) => result,
                            None => return Err(ParseIntError::Overflow),
                        };
                        result = match result.checked_add(x) {
                            Some(result) => result,
                            None => return Err(ParseIntError::Overflow),
                        };
                    }
                } else {
                    for &c in digits {
                        let x = match dec_to_digit(c) {
                            Some(x) => x as $t,
                            None => return Err(ParseIntError::InvalidDigit),
                        };
                        result = match result.checked_mul(10) {
                            Some(result) => result,
                            None => return Err(ParseIntError::Underflow),
                        };
                        result = match result.checked_sub(x) {
                            Some(result) => result,
                            None => return Err(ParseIntError::Underflow),
                        };
                    }
                }
                Ok(result)
            }
        }
    }
}

implement!(i8, true);
implement!(i16, true);
implement!(i32, true);
implement!(i64, true);
implement!(isize, true);
implement!(u8, false);
implement!(u16, false);
implement!(u32, false);
implement!(u64, false);
implement!(usize, false);

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

}<commit_msg>Add radix support<commit_after>use base::{FromAscii};

trait FromStrHelper: {
    fn signed() -> bool;
}

#[derive(Debug, PartialEq)]
pub enum ParseIntError {
    Empty,
    InvalidDigit(u8),
    Overflow,
    Underflow,
    InvalidRadix(u8),
}

#[inline]
pub fn dec_to_digit(c: u8, radix: u8) -> Option<u8> {
    let val = match c {
        b'0' ... b'9' => c - b'0',
        b'a' ... b'z' => c - b'a' + 10,
        b'A' ... b'Z' => c - b'A' + 10,
        _ => return None,
    };
    if val < radix {
        Some(val)
    } else {
        None
    }
}

pub trait FromAsciiRadix: Sized {
    type Err;

    fn from_ascii_radix(s: &[u8], radix: u8) -> Result<Self, Self::Err>;
}

macro_rules! implement {
    ($t:ty, $signed: expr) => {
        impl FromStrHelper for $t {
            #[inline]
            fn signed() -> bool { $signed }
        }

        impl FromAsciiRadix for $t {
            type Err = ParseIntError;

            #[inline]
            fn from_ascii_radix(src: &[u8], radix: u8) -> Result<Self, Self::Err> {

                if radix >= 2 || radix <= 36 {
                    return Err(ParseIntError::InvalidRadix(radix))
                }

                if src.is_empty() {
                    return Err(ParseIntError::Empty);
                }

                let (is_positive, digits) = match src[0] {
                    b'+' => (true, &src[1..]),
                    b'-' if <$t>::signed() => (false, &src[1..]),
                    _ => (true, src)
                };

                if digits.is_empty() {
                    return Err(ParseIntError::Empty);
                }

                let mut result: $t = 0;

                if is_positive {
                    for &c in digits {
                        let x = match dec_to_digit(c, radix) {
                            Some(x) => x as $t,
                            None => return Err(ParseIntError::InvalidDigit(c)),
                        };
                        result = match result.checked_mul(radix as $t) {
                            Some(result) => result,
                            None => return Err(ParseIntError::Overflow),
                        };
                        result = match result.checked_add(x) {
                            Some(result) => result,
                            None => return Err(ParseIntError::Overflow),
                        };
                    }
                } else {
                    for &c in digits {
                        let x = match dec_to_digit(c, radix) {
                            Some(x) => x as $t,
                            None => return Err(ParseIntError::InvalidDigit(c)),
                        };
                        result = match result.checked_mul(radix as $t) {
                            Some(result) => result,
                            None => return Err(ParseIntError::Underflow),
                        };
                        result = match result.checked_sub(x) {
                            Some(result) => result,
                            None => return Err(ParseIntError::Underflow),
                        };
                    }
                }
                Ok(result)
            }
        }

        impl FromAscii for $t {
            type Err = ParseIntError;

            #[inline]
            fn from_ascii(src: &[u8]) -> Result<Self, Self::Err> {
                <$t>::from_ascii_radix(src, 10)
            }
        }
    }
}

implement!(i8, true);
implement!(i16, true);
implement!(i32, true);
implement!(i64, true);
implement!(isize, true);
implement!(u8, false);
implement!(u16, false);
implement!(u32, false);
implement!(u64, false);
implement!(usize, false);

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

}<|endoftext|>


<commit_before>use libc;

use std::{fmt, io, error, result};
use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};

use byteorder::{ByteOrder, BigEndian, LittleEndian};
use crypto::digest::Digest;
use crypto::md5::Md5;

use rand::{Rng, OsRng};
use rustc_serialize::hex::{self, FromHex, ToHex};
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};

use time;

const TIMESTAMP_SIZE: usize = 4;
const MACHINE_ID_SIZE: usize = 3;
const PROCESS_ID_SIZE: usize = 2;
const COUNTER_SIZE: usize = 3;

const TIMESTAMP_OFFSET: usize = 0;
const MACHINE_ID_OFFSET: usize = TIMESTAMP_OFFSET + TIMESTAMP_SIZE;
const PROCESS_ID_OFFSET: usize = MACHINE_ID_OFFSET + MACHINE_ID_SIZE;
const COUNTER_OFFSET: usize = PROCESS_ID_OFFSET + PROCESS_ID_SIZE;

const MAX_U24: usize = 0xFFFFFF;

static OID_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT;
static mut MACHINE_BYTES: Option<[u8; 3]> = None;

extern {
    fn gethostname(name: *mut libc::c_char, size: libc::size_t) -> libc::c_int;
}

/// Errors that can occur during OID construction and generation.
#[derive(Debug)]
pub enum Error {
    ArgumentError(String),
    FromHexError(hex::FromHexError),
    IoError(io::Error),
    HostnameError,
}

impl From<hex::FromHexError> for Error {
    fn from(err: hex::FromHexError) -> Error {
        Error::FromHexError(err)
    }
}

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

/// Alias for Result<T, oid::Error>.
pub type Result<T> = result::Result<T, Error>;

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Error::ArgumentError(ref inner) => inner.fmt(fmt),
            &Error::FromHexError(ref inner) => inner.fmt(fmt),
            &Error::IoError(ref inner) => inner.fmt(fmt),
            &Error::HostnameError => write!(fmt, "Failed to retrieve hostname for OID generation."),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match self {
            &Error::ArgumentError(ref inner) => &inner,
            &Error::FromHexError(ref inner) => inner.description(),
            &Error::IoError(ref inner) => inner.description(),
            &Error::HostnameError => "Failed to retrieve hostname for OID generation.",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match self {
            &Error::ArgumentError(_) => None,
            &Error::FromHexError(ref inner) => Some(inner),
            &Error::IoError(ref inner) => Some(inner),
            &Error::HostnameError => None,
        }
    }
}

/// A wrapper around raw 12-byte ObjectId representations.
#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub struct ObjectId {
    id: [u8; 12],
}

impl ObjectId {
    /// Generates a new ObjectID, represented in bytes.
    /// See the [docs](http://docs.mongodb.org/manual/reference/object-id/)
    /// for more information.
    pub fn new() -> Result<ObjectId> {
        let timestamp = ObjectId::gen_timestamp();
        let machine_id = try!(ObjectId::gen_machine_id());
        let process_id = ObjectId::gen_process_id();
        let counter = try!(ObjectId::gen_count());

        let mut buf: [u8; 12] = [0; 12];
        for i in 0..TIMESTAMP_SIZE { buf[TIMESTAMP_OFFSET + i] = timestamp[i]; }
        for i in 0..MACHINE_ID_SIZE { buf[MACHINE_ID_OFFSET + i] = machine_id[i]; }
        for i in 0..PROCESS_ID_SIZE { buf[PROCESS_ID_OFFSET + i] = process_id[i]; }
        for i in 0..COUNTER_SIZE { buf[COUNTER_OFFSET +i] = counter[i]; }

        Ok(ObjectId::with_bytes(buf))
    }

    /// Constructs a new ObjectId wrapper around the raw byte representation.
    pub fn with_bytes(bytes: [u8; 12]) -> ObjectId {
        ObjectId {
            id: bytes,
        }
    }

    /// Creates an ObjectID using a 12-byte (24-char) hexadecimal string.
    pub fn with_string(s: &str) -> Result<ObjectId> {
        let bytes = try!(s.from_hex());
        if bytes.len() != 12 {
            Err(Error::ArgumentError("Provided string must be a 12-byte hexadecimal string.".to_owned()))
        } else {
            let mut byte_array: [u8; 12] = [0; 12];
            for i in 0..12 {
                byte_array[i] = bytes[i];
            }
            Ok(ObjectId::with_bytes(byte_array))
        }
    }

    /// Creates a dummy ObjectId with a specific generation time.
    /// This method should only be used to do range queries on a field
    /// containing ObjectId instances.
    pub fn with_timestamp(time: u32) -> ObjectId {
        let mut buf: [u8; 12] = [0; 12];
        BigEndian::write_u32(&mut buf, time);
        ObjectId::with_bytes(buf)
    }

    /// Returns the raw byte representation of an ObjectId.
    pub fn bytes(&self) -> [u8; 12] {
        self.id
    }

    /// Retrieves the timestamp (seconds since epoch) from an ObjectId.
    pub fn timestamp(&self) -> u32 {
        BigEndian::read_u32(&self.id)
    }

    /// Retrieves the machine id associated with an ObjectId.
    pub fn machine_id(&self) -> u32 {
        let mut buf: [u8; 4] = [0; 4];
        for i in 0..MACHINE_ID_SIZE {
            buf[i] = self.id[MACHINE_ID_OFFSET+i];
        }
        LittleEndian::read_u32(&buf)
    }

    /// Retrieves the process id associated with an ObjectId.
    pub fn process_id(&self) -> u16 {
        LittleEndian::read_u16(&self.id[PROCESS_ID_OFFSET..])
    }

    /// Retrieves the increment counter from an ObjectId.
    pub fn counter(&self) -> u32 {
        let mut buf: [u8; 4] = [0; 4];
        for i in 0..COUNTER_SIZE {
            buf[i+1] = self.id[COUNTER_OFFSET+i];
        }
        BigEndian::read_u32(&buf)
    }

    // Generates a new timestamp representing the current seconds since epoch.
    // Represented in Big Endian.
    fn gen_timestamp() -> [u8; 4] {
        let timespec = time::get_time();
        let timestamp = timespec.sec as u32;

        let mut buf: [u8; 4] = [0; 4];
        BigEndian::write_u32(&mut buf,timestamp);
        buf
    }

    // Generates a new machine id represented as an MD5-hashed 3-byte-encoded hostname string.
    // Represented in Little Endian.
    fn gen_machine_id() -> Result<[u8; 3]> {
        // Short-circuit if machine id has already been calculated.
        // Since the generated machine id is not variable, arising race conditions
        // will have the same MACHINE_BYTES result.
        unsafe {
            if let Some(bytes) = MACHINE_BYTES.as_ref() {
                return Ok(bytes.clone());
            }
        }

        // Retrieve hostname through libc
        let len = 255;
        let mut buf = Vec::<u8>::with_capacity(len);
        let ptr = buf.as_mut_ptr();
        let err = unsafe { gethostname(ptr as *mut libc::c_char, len as libc::size_t) } as i32;

        if err != 0 {
            return Err(Error::HostnameError);
        }

        // Convert bytes into string
        let s = String::from_utf8_lossy(&buf);

        // Hash hostname string
        let mut md5 = Md5::new();
        md5.input_str(&s.into_owned()[..]);
        let hash = md5.result_str();

        // Re-convert string to bytes and grab first three
        let mut bytes = hash.bytes();
        let mut vec: [u8; 3] = [0; 3];
        for i in 0..MACHINE_ID_SIZE {
            match bytes.next() {
                Some(b) => vec[i] = b,
                None => break,
            }
        }

        unsafe { MACHINE_BYTES = Some(vec) };
        Ok(vec)
    }

    // Gets the process ID and returns it as a 2-byte array.
    // Represented in Little Endian.
    fn gen_process_id() -> [u8; 2] {
        let pid = unsafe { libc::getpid() as u16 };
        let mut buf: [u8; 2] = [0; 2];
        LittleEndian::write_u16(&mut buf, pid);
        buf
    }

    // Gets an incremental 3-byte count.
    // Represented in Big Endian.
    fn gen_count() -> Result<[u8; 3]> {
        // Init oid counter
        if OID_COUNTER.load(Ordering::SeqCst) == 0 {
            let mut rng = try!(OsRng::new());
            let start = rng.gen_range(0, MAX_U24 + 1);
            OID_COUNTER.store(start, Ordering::SeqCst);
        }

        let u_counter = OID_COUNTER.fetch_add(1, Ordering::SeqCst);

        // Mod result instead of OID_COUNTER to prevent threading issues.
        // Static mutexes are currently unstable; once they have been
        // stabilized, one should be used to access OID_COUNTER and
        // perform multiple operations atomically.
        let u = u_counter % MAX_U24;

        // Convert usize to writable u64, then extract the first three bytes.
        let u_int = u as u64;

        let mut buf: [u8; 8] = [0; 8];
        BigEndian::write_u64(&mut buf, u_int);
        let buf_u24: [u8; 3] = [buf[5], buf[6], buf[7]];
        Ok(buf_u24)
    }
}

impl ToHex for ObjectId {
    fn to_hex(&self) -> String {
        self.id.to_hex()
    }
}

impl fmt::Display for ObjectId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(&self.to_hex())
    }
}

impl fmt::Debug for ObjectId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(&format!("ObjectId({})", self.to_hex()))
    }
}

impl Decodable for ObjectId {
    fn decode<D: Decoder>(d: &mut D) -> result::Result<Self, D::Error> {
        let str = try!(d.read_str());
        Ok(ObjectId::with_string(&str).unwrap())
    }
}

impl Encodable for ObjectId {
    fn encode<S: Encoder>(&self, s: &mut S) -> result::Result<(), S::Error> {
        s.emit_str(&self.to_string())
    }
}

#[test]
fn pid_generation() {
    let pid = unsafe { libc::getpid() as u16 };
    let generated = ObjectId::gen_process_id();
    assert_eq!(pid, LittleEndian::read_u16(&generated));
}

#[test]
fn count_generation() {
    let start = 52222;
    OID_COUNTER.store(start, Ordering::SeqCst);
    let count_res = ObjectId::gen_count();
    assert!(count_res.is_ok());
    let count_bytes = count_res.unwrap();

    let mut buf: [u8; 4] = [0; 4];
    for i in 0..COUNTER_SIZE {
        buf[i+1] = count_bytes[i];
    }

    let count = BigEndian::read_u32(&buf);
    assert_eq!(start as u32, count);
}

#[test]
fn count_is_big_endian() {
    let start = 1122867;
    OID_COUNTER.store(start, Ordering::SeqCst);
    let oid_res = ObjectId::new();
    assert!(oid_res.is_ok());
    let oid = oid_res.unwrap();

    assert_eq!(0x11u8, oid.bytes()[COUNTER_OFFSET]);
    assert_eq!(0x22u8, oid.bytes()[COUNTER_OFFSET + 1]);
    assert_eq!(0x33u8, oid.bytes()[COUNTER_OFFSET + 2]);
}

#[test]
fn test_display() {
    let id = ObjectId::with_string("53e37d08776f724e42000000").unwrap();

    assert_eq!(
        format!("{}", id),
        "53e37d08776f724e42000000"
    )
}

#[test]
fn test_debug() {
    let id = ObjectId::with_string("53e37d08776f724e42000000").unwrap();

    assert_eq!(
        format!("{:?}", id),
        "ObjectId(53e37d08776f724e42000000)"
    )
}
<commit_msg>Combine oid counter generation tests<commit_after>use libc;

use std::{fmt, io, error, result};
use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};

use byteorder::{ByteOrder, BigEndian, LittleEndian};
use crypto::digest::Digest;
use crypto::md5::Md5;

use rand::{Rng, OsRng};
use rustc_serialize::hex::{self, FromHex, ToHex};
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};

use time;

const TIMESTAMP_SIZE: usize = 4;
const MACHINE_ID_SIZE: usize = 3;
const PROCESS_ID_SIZE: usize = 2;
const COUNTER_SIZE: usize = 3;

const TIMESTAMP_OFFSET: usize = 0;
const MACHINE_ID_OFFSET: usize = TIMESTAMP_OFFSET + TIMESTAMP_SIZE;
const PROCESS_ID_OFFSET: usize = MACHINE_ID_OFFSET + MACHINE_ID_SIZE;
const COUNTER_OFFSET: usize = PROCESS_ID_OFFSET + PROCESS_ID_SIZE;

const MAX_U24: usize = 0xFFFFFF;

static OID_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT;
static mut MACHINE_BYTES: Option<[u8; 3]> = None;

extern {
    fn gethostname(name: *mut libc::c_char, size: libc::size_t) -> libc::c_int;
}

/// Errors that can occur during OID construction and generation.
#[derive(Debug)]
pub enum Error {
    ArgumentError(String),
    FromHexError(hex::FromHexError),
    IoError(io::Error),
    HostnameError,
}

impl From<hex::FromHexError> for Error {
    fn from(err: hex::FromHexError) -> Error {
        Error::FromHexError(err)
    }
}

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

/// Alias for Result<T, oid::Error>.
pub type Result<T> = result::Result<T, Error>;

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Error::ArgumentError(ref inner) => inner.fmt(fmt),
            &Error::FromHexError(ref inner) => inner.fmt(fmt),
            &Error::IoError(ref inner) => inner.fmt(fmt),
            &Error::HostnameError => write!(fmt, "Failed to retrieve hostname for OID generation."),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match self {
            &Error::ArgumentError(ref inner) => &inner,
            &Error::FromHexError(ref inner) => inner.description(),
            &Error::IoError(ref inner) => inner.description(),
            &Error::HostnameError => "Failed to retrieve hostname for OID generation.",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match self {
            &Error::ArgumentError(_) => None,
            &Error::FromHexError(ref inner) => Some(inner),
            &Error::IoError(ref inner) => Some(inner),
            &Error::HostnameError => None,
        }
    }
}

/// A wrapper around raw 12-byte ObjectId representations.
#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub struct ObjectId {
    id: [u8; 12],
}

impl ObjectId {
    /// Generates a new ObjectID, represented in bytes.
    /// See the [docs](http://docs.mongodb.org/manual/reference/object-id/)
    /// for more information.
    pub fn new() -> Result<ObjectId> {
        let timestamp = ObjectId::gen_timestamp();
        let machine_id = try!(ObjectId::gen_machine_id());
        let process_id = ObjectId::gen_process_id();
        let counter = try!(ObjectId::gen_count());

        let mut buf: [u8; 12] = [0; 12];
        for i in 0..TIMESTAMP_SIZE { buf[TIMESTAMP_OFFSET + i] = timestamp[i]; }
        for i in 0..MACHINE_ID_SIZE { buf[MACHINE_ID_OFFSET + i] = machine_id[i]; }
        for i in 0..PROCESS_ID_SIZE { buf[PROCESS_ID_OFFSET + i] = process_id[i]; }
        for i in 0..COUNTER_SIZE { buf[COUNTER_OFFSET +i] = counter[i]; }

        Ok(ObjectId::with_bytes(buf))
    }

    /// Constructs a new ObjectId wrapper around the raw byte representation.
    pub fn with_bytes(bytes: [u8; 12]) -> ObjectId {
        ObjectId {
            id: bytes,
        }
    }

    /// Creates an ObjectID using a 12-byte (24-char) hexadecimal string.
    pub fn with_string(s: &str) -> Result<ObjectId> {
        let bytes = try!(s.from_hex());
        if bytes.len() != 12 {
            Err(Error::ArgumentError("Provided string must be a 12-byte hexadecimal string.".to_owned()))
        } else {
            let mut byte_array: [u8; 12] = [0; 12];
            for i in 0..12 {
                byte_array[i] = bytes[i];
            }
            Ok(ObjectId::with_bytes(byte_array))
        }
    }

    /// Creates a dummy ObjectId with a specific generation time.
    /// This method should only be used to do range queries on a field
    /// containing ObjectId instances.
    pub fn with_timestamp(time: u32) -> ObjectId {
        let mut buf: [u8; 12] = [0; 12];
        BigEndian::write_u32(&mut buf, time);
        ObjectId::with_bytes(buf)
    }

    /// Returns the raw byte representation of an ObjectId.
    pub fn bytes(&self) -> [u8; 12] {
        self.id
    }

    /// Retrieves the timestamp (seconds since epoch) from an ObjectId.
    pub fn timestamp(&self) -> u32 {
        BigEndian::read_u32(&self.id)
    }

    /// Retrieves the machine id associated with an ObjectId.
    pub fn machine_id(&self) -> u32 {
        let mut buf: [u8; 4] = [0; 4];
        for i in 0..MACHINE_ID_SIZE {
            buf[i] = self.id[MACHINE_ID_OFFSET+i];
        }
        LittleEndian::read_u32(&buf)
    }

    /// Retrieves the process id associated with an ObjectId.
    pub fn process_id(&self) -> u16 {
        LittleEndian::read_u16(&self.id[PROCESS_ID_OFFSET..])
    }

    /// Retrieves the increment counter from an ObjectId.
    pub fn counter(&self) -> u32 {
        let mut buf: [u8; 4] = [0; 4];
        for i in 0..COUNTER_SIZE {
            buf[i+1] = self.id[COUNTER_OFFSET+i];
        }
        BigEndian::read_u32(&buf)
    }

    // Generates a new timestamp representing the current seconds since epoch.
    // Represented in Big Endian.
    fn gen_timestamp() -> [u8; 4] {
        let timespec = time::get_time();
        let timestamp = timespec.sec as u32;

        let mut buf: [u8; 4] = [0; 4];
        BigEndian::write_u32(&mut buf,timestamp);
        buf
    }

    // Generates a new machine id represented as an MD5-hashed 3-byte-encoded hostname string.
    // Represented in Little Endian.
    fn gen_machine_id() -> Result<[u8; 3]> {
        // Short-circuit if machine id has already been calculated.
        // Since the generated machine id is not variable, arising race conditions
        // will have the same MACHINE_BYTES result.
        unsafe {
            if let Some(bytes) = MACHINE_BYTES.as_ref() {
                return Ok(bytes.clone());
            }
        }

        // Retrieve hostname through libc
        let len = 255;
        let mut buf = Vec::<u8>::with_capacity(len);
        let ptr = buf.as_mut_ptr();
        let err = unsafe { gethostname(ptr as *mut libc::c_char, len as libc::size_t) } as i32;

        if err != 0 {
            return Err(Error::HostnameError);
        }

        // Convert bytes into string
        let s = String::from_utf8_lossy(&buf);

        // Hash hostname string
        let mut md5 = Md5::new();
        md5.input_str(&s.into_owned()[..]);
        let hash = md5.result_str();

        // Re-convert string to bytes and grab first three
        let mut bytes = hash.bytes();
        let mut vec: [u8; 3] = [0; 3];
        for i in 0..MACHINE_ID_SIZE {
            match bytes.next() {
                Some(b) => vec[i] = b,
                None => break,
            }
        }

        unsafe { MACHINE_BYTES = Some(vec) };
        Ok(vec)
    }

    // Gets the process ID and returns it as a 2-byte array.
    // Represented in Little Endian.
    fn gen_process_id() -> [u8; 2] {
        let pid = unsafe { libc::getpid() as u16 };
        let mut buf: [u8; 2] = [0; 2];
        LittleEndian::write_u16(&mut buf, pid);
        buf
    }

    // Gets an incremental 3-byte count.
    // Represented in Big Endian.
    fn gen_count() -> Result<[u8; 3]> {
        // Init oid counter
        if OID_COUNTER.load(Ordering::SeqCst) == 0 {
            let mut rng = try!(OsRng::new());
            let start = rng.gen_range(0, MAX_U24 + 1);
            OID_COUNTER.store(start, Ordering::SeqCst);
        }

        let u_counter = OID_COUNTER.fetch_add(1, Ordering::SeqCst);

        // Mod result instead of OID_COUNTER to prevent threading issues.
        // Static mutexes are currently unstable; once they have been
        // stabilized, one should be used to access OID_COUNTER and
        // perform multiple operations atomically.
        let u = u_counter % MAX_U24;

        // Convert usize to writable u64, then extract the first three bytes.
        let u_int = u as u64;

        let mut buf: [u8; 8] = [0; 8];
        BigEndian::write_u64(&mut buf, u_int);
        let buf_u24: [u8; 3] = [buf[5], buf[6], buf[7]];
        Ok(buf_u24)
    }
}

impl ToHex for ObjectId {
    fn to_hex(&self) -> String {
        self.id.to_hex()
    }
}

impl fmt::Display for ObjectId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(&self.to_hex())
    }
}

impl fmt::Debug for ObjectId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(&format!("ObjectId({})", self.to_hex()))
    }
}

impl Decodable for ObjectId {
    fn decode<D: Decoder>(d: &mut D) -> result::Result<Self, D::Error> {
        let str = try!(d.read_str());
        Ok(ObjectId::with_string(&str).unwrap())
    }
}

impl Encodable for ObjectId {
    fn encode<S: Encoder>(&self, s: &mut S) -> result::Result<(), S::Error> {
        s.emit_str(&self.to_string())
    }
}

#[test]
fn pid_generation() {
    let pid = unsafe { libc::getpid() as u16 };
    let generated = ObjectId::gen_process_id();
    assert_eq!(pid, LittleEndian::read_u16(&generated));
}

#[test]
fn count_generated_is_big_endian() {
    let start = 1122866;
    OID_COUNTER.store(start, Ordering::SeqCst);

    // Test count generates correct value 1122866
    let count_res = ObjectId::gen_count();
    assert!(count_res.is_ok());
    let count_bytes = count_res.unwrap();

    let mut buf: [u8; 4] = [0; 4];
    for i in 0..COUNTER_SIZE {
        buf[i+1] = count_bytes[i];
    }

    let count = BigEndian::read_u32(&buf);
    assert_eq!(start as u32, count);

    // Test OID formats count correctly as big endian
    let oid_res = ObjectId::new();
    assert!(oid_res.is_ok());
    let oid = oid_res.unwrap();

    assert_eq!(0x11u8, oid.bytes()[COUNTER_OFFSET]);
    assert_eq!(0x22u8, oid.bytes()[COUNTER_OFFSET + 1]);
    assert_eq!(0x33u8, oid.bytes()[COUNTER_OFFSET + 2]);
}

#[test]
fn test_display() {
    let id = ObjectId::with_string("53e37d08776f724e42000000").unwrap();

    assert_eq!(
        format!("{}", id),
        "53e37d08776f724e42000000"
    )
}

#[test]
fn test_debug() {
    let id = ObjectId::with_string("53e37d08776f724e42000000").unwrap();

    assert_eq!(
        format!("{:?}", id),
        "ObjectId(53e37d08776f724e42000000)"
    )
}
<|endoftext|>


<commit_before>//! Managing raw mode.
//!
//! Raw mode is a particular state a TTY can have. It signifies that:
//!
//! 1. No line buffering (the input is given byte-by-byte).
//! 2. The input is not written out, instead it has to be done manually by the programmer.
//! 3. The output is not canonicalized (for example, `\n` means "go one line down", not "line
//!    break").
//!
//! It is essential to design terminal programs.
//!
//! # Example
//!
//! ```rust,no_run
//! use termion::raw::IntoRawMode;
//! use std::io::{Write, stdout};
//!
//! fn main() {
//!     let mut stdout = stdout().into_raw_mode().unwrap();
//!
//!     write!(stdout, "Hey there.").unwrap();
//! }
//! ```

use std::io::{self, Write};
use std::ops;

use sys::Termios;
use sys::attr::{get_terminal_attr, raw_terminal_attr, set_terminal_attr};

/// The timeout of an escape code control sequence, in milliseconds.
pub const CONTROL_SEQUENCE_TIMEOUT: u64 = 100;

/// A terminal restorer, which keeps the previous state of the terminal, and restores it, when
/// dropped.
///
/// Restoring will entirely bring back the old TTY state.
pub struct RawTerminal<W: Write> {
    prev_ios: Termios,
    output: W,
}

impl<W: Write> Drop for RawTerminal<W> {
    fn drop(&mut self) {
        set_terminal_attr(&self.prev_ios).unwrap();
    }
}

impl<W: Write> ops::Deref for RawTerminal<W> {
    type Target = W;

    fn deref(&self) -> &W {
        &self.output
    }
}

impl<W: Write> ops::DerefMut for RawTerminal<W> {
    fn deref_mut(&mut self) -> &mut W {
        &mut self.output
    }
}

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

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

/// Types which can be converted into "raw mode".
///
/// # Why is this type defined on writers and not readers?
///
/// TTYs has their state controlled by the writer, not the reader. You use the writer to clear the
/// screen, move the cursor and so on, so naturally you use the writer to change the mode as well.
pub trait IntoRawMode: Write + Sized {
    /// Switch to raw mode.
    ///
    /// Raw mode means that stdin won't be printed (it will instead have to be written manually by
    /// the program). Furthermore, the input isn't canonicalised or buffered (that is, you can
    /// read from stdin one byte of a time). The output is neither modified in any way.
    fn into_raw_mode(self) -> io::Result<RawTerminal<Self>>;
}

impl<W: Write> IntoRawMode for W {
    fn into_raw_mode(self) -> io::Result<RawTerminal<W>> {
        let mut ios = get_terminal_attr()?;
        let prev_ios = ios;

        raw_terminal_attr(&mut ios);

        set_terminal_attr(&ios)?;

        Ok(RawTerminal {
            prev_ios: prev_ios,
            output: self,
        })
    }
}

impl<W: Write> RawTerminal<W> {
    /// Temporarily switch to original mode
    pub fn suspend_raw_mode(&self) -> io::Result<()> {
        set_terminal_attr(&self.prev_ios)?;
        Ok(())
    }

    /// Temporarily switch to raw mode
    pub fn activate_raw_mode(&self) -> io::Result<()> {
        let mut ios = get_terminal_attr()?;
        raw_terminal_attr(&mut ios);
        set_terminal_attr(&ios)?;
        Ok(())
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::io::{Write, stdout};

    #[test]
    fn test_into_raw_mode() {
        let mut out = stdout().into_raw_mode().unwrap();

        out.write_all(b"this is a test, muahhahahah\r\n").unwrap();

        drop(out);
    }
}
<commit_msg>Added AsRawFd impl for RawTerminal<commit_after>//! Managing raw mode.
//!
//! Raw mode is a particular state a TTY can have. It signifies that:
//!
//! 1. No line buffering (the input is given byte-by-byte).
//! 2. The input is not written out, instead it has to be done manually by the programmer.
//! 3. The output is not canonicalized (for example, `\n` means "go one line down", not "line
//!    break").
//!
//! It is essential to design terminal programs.
//!
//! # Example
//!
//! ```rust,no_run
//! use termion::raw::IntoRawMode;
//! use std::io::{Write, stdout};
//!
//! fn main() {
//!     let mut stdout = stdout().into_raw_mode().unwrap();
//!
//!     write!(stdout, "Hey there.").unwrap();
//! }
//! ```

use std::io::{self, Write};
use std::ops;

use sys::attr::{get_terminal_attr, raw_terminal_attr, set_terminal_attr};
use sys::Termios;

/// The timeout of an escape code control sequence, in milliseconds.
pub const CONTROL_SEQUENCE_TIMEOUT: u64 = 100;

/// A terminal restorer, which keeps the previous state of the terminal, and restores it, when
/// dropped.
///
/// Restoring will entirely bring back the old TTY state.
pub struct RawTerminal<W: Write> {
    prev_ios: Termios,
    output: W,
}

impl<W: Write> Drop for RawTerminal<W> {
    fn drop(&mut self) {
        set_terminal_attr(&self.prev_ios).unwrap();
    }
}

impl<W: Write> ops::Deref for RawTerminal<W> {
    type Target = W;

    fn deref(&self) -> &W {
        &self.output
    }
}

impl<W: Write> ops::DerefMut for RawTerminal<W> {
    fn deref_mut(&mut self) -> &mut W {
        &mut self.output
    }
}

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

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

#[cfg(unix)]
mod unix_impl {
    use super::*;
    use std::os::unix::io::{AsRawFd, RawFd};

    impl<W: Write + AsRawFd> AsRawFd for RawTerminal<W> {
        fn as_raw_fd(&self) -> RawFd {
            self.output.as_raw_fd()
        }
    }
}

/// Types which can be converted into "raw mode".
///
/// # Why is this type defined on writers and not readers?
///
/// TTYs has their state controlled by the writer, not the reader. You use the writer to clear the
/// screen, move the cursor and so on, so naturally you use the writer to change the mode as well.
pub trait IntoRawMode: Write + Sized {
    /// Switch to raw mode.
    ///
    /// Raw mode means that stdin won't be printed (it will instead have to be written manually by
    /// the program). Furthermore, the input isn't canonicalised or buffered (that is, you can
    /// read from stdin one byte of a time). The output is neither modified in any way.
    fn into_raw_mode(self) -> io::Result<RawTerminal<Self>>;
}

impl<W: Write> IntoRawMode for W {
    fn into_raw_mode(self) -> io::Result<RawTerminal<W>> {
        let mut ios = get_terminal_attr()?;
        let prev_ios = ios;

        raw_terminal_attr(&mut ios);

        set_terminal_attr(&ios)?;

        Ok(RawTerminal {
            prev_ios: prev_ios,
            output: self,
        })
    }
}

impl<W: Write> RawTerminal<W> {
    /// Temporarily switch to original mode
    pub fn suspend_raw_mode(&self) -> io::Result<()> {
        set_terminal_attr(&self.prev_ios)?;
        Ok(())
    }

    /// Temporarily switch to raw mode
    pub fn activate_raw_mode(&self) -> io::Result<()> {
        let mut ios = get_terminal_attr()?;
        raw_terminal_attr(&mut ios);
        set_terminal_attr(&ios)?;
        Ok(())
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::io::{stdout, Write};

    #[test]
    fn test_into_raw_mode() {
        let mut out = stdout().into_raw_mode().unwrap();

        out.write_all(b"this is a test, muahhahahah\r\n").unwrap();

        drop(out);
    }
}
<|endoftext|>


<commit_before>use std::mem;
use std::slice;
use std::fmt;
use approx;
use num;
use num::Float;
use channel::{PosNormalBoundedChannel, PosNormalChannelScalar, ColorChannel, ChannelFormatCast,
              ChannelCast};
use color::{Color, Lerp, Flatten, Bounded};
use convert::FromColor;
use rgb::Rgb;

pub struct RgiTag;

#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Hash)]
pub struct Rgi<T> {
    red: PosNormalBoundedChannel<T>,
    green: PosNormalBoundedChannel<T>,
    intensity: PosNormalBoundedChannel<T>,
}

impl<T> Rgi<T>
    where T: PosNormalChannelScalar + Float
{
    pub fn from_channels(red: T, green: T, intensity: T) -> Self {
        let zero = num::cast(0.0).unwrap();
        if red + green > num::cast(1.0).unwrap() || red + green < num::cast(0.0).unwrap() {
            panic!("rgi channels must sum to exactly 1.0");
        }
        assert!(red >= zero);
        assert!(green >= zero);
        Rgi {
            red: PosNormalBoundedChannel::new(red),
            green: PosNormalBoundedChannel::new(green),
            intensity: PosNormalBoundedChannel::new(intensity),
        }
    }

    impl_color_color_cast_square!(Rgi {red, green, intensity},
        chan_traits={PosNormalChannelScalar});

    pub fn red(&self) -> T {
        self.red.0.clone()
    }
    pub fn green(&self) -> T {
        self.green.0.clone()
    }
    pub fn blue(&self) -> T {
        num::cast::<_, T>(1.0).unwrap() - self.green() - self.red()
    }
    pub fn intensity(&self) -> T {
        self.intensity.0.clone()
    }
    pub fn intensity_mut(&mut self) -> &mut T {
        &mut self.intensity.0
    }
    pub fn set_red(&mut self, val: T) {
        let (red, green, _) = Self::rescale_channels(val, self.green(), self.blue());
        self.red.0 = red;
        self.green.0 = green;
    }
    pub fn set_green(&mut self, val: T) {
        let (green, red, _) = Self::rescale_channels(val, self.red(), self.blue());
        self.red.0 = red;
        self.green.0 = green;
    }
    pub fn set_blue(&mut self, val: T) {
        let (_, red, green) = Self::rescale_channels(val, self.red(), self.green());
        self.red.0 = red;
        self.green.0 = green;
    }
    pub fn set_intensity(&mut self, val: T) {
        self.intensity.0 = val;
    }

    fn rescale_channels(primary: T, c2: T, c3: T) -> (T, T, T) {
        let new_primary = primary;
        if new_primary > PosNormalBoundedChannel::max_bound() ||
           new_primary < PosNormalBoundedChannel::min_bound() {
            panic!("rgi color channels must be 1.0 or below");
        }

        let zero = num::cast(0.0).unwrap();
        let rem_scale = c2 + c3;
        let rem = num::cast::<_, T>(1.0).unwrap() - new_primary;
        if rem_scale > zero {
            (new_primary, (c2 / rem_scale) * rem, (c3 / rem_scale) * rem)
        } else {
            let one_half = num::cast(0.5).unwrap();
            (new_primary, rem * one_half, rem * one_half)
        }
    }
}

impl<T> Color for Rgi<T>
    where T: PosNormalChannelScalar + Float
{
    type Tag = RgiTag;
    type ChannelsTuple = (T, T, T);

    #[inline]
    fn num_channels() -> u32 {
        3
    }

    fn from_tuple(values: Self::ChannelsTuple) -> Self {
        Rgi {
            red: PosNormalBoundedChannel::new(values.0),
            green: PosNormalBoundedChannel::new(values.1),
            intensity: PosNormalBoundedChannel::new(values.2),
        }
    }
    fn to_tuple(self) -> Self::ChannelsTuple {
        (self.red.0, self.green.0, self.intensity.0)
    }
}

impl<T> Lerp for Rgi<T>
    where T: PosNormalChannelScalar + Lerp + Float
{
    type Position = <T as Lerp>::Position;
    impl_color_lerp_square!(Rgi {red, green, intensity});
}

impl<T> Flatten for Rgi<T>
    where T: PosNormalChannelScalar + Float
{
    type ScalarFormat = T;

    impl_color_as_slice!(T);
    impl_color_from_slice_square!(Rgi<T> {red:PosNormalBoundedChannel - 0,
        green:PosNormalBoundedChannel - 1, intensity:PosNormalBoundedChannel - 2});
}

impl<T> Bounded for Rgi<T>
    where T: PosNormalChannelScalar + Float
{
    impl_color_bounded!(Rgi {red, green, intensity});
}

impl<T> approx::ApproxEq for Rgi<T>
    where T: PosNormalChannelScalar + approx::ApproxEq + Float,
          T::Epsilon: Clone
{
    impl_approx_eq!({red, green, intensity});
}

impl<T> Default for Rgi<T>
    where T: PosNormalChannelScalar + num::Zero + Float
{
    impl_color_default!(Rgi {red:PosNormalBoundedChannel, green:PosNormalBoundedChannel,
        intensity:PosNormalBoundedChannel});
}

impl<T> fmt::Display for Rgi<T>
    where T: PosNormalChannelScalar + fmt::Display + Float
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Rgi({}, {}, {})", self.red, self.green, self.intensity)
    }
}

impl<T> FromColor<Rgb<T>> for Rgi<T>
    where T: PosNormalChannelScalar + Float
{
    fn from_color(from: &Rgb<T>) -> Self {
        let zero = num::cast(0.0).unwrap();
        let sum = from.red() + from.green() + from.blue();

        if sum != zero {
            let r = from.red() / sum;
            let g = from.green() / sum;

            let i = num::cast::<_, T>(1.0 / 3.0).unwrap() * sum;

            Rgi::from_channels(r, g, i)
        } else {
            Rgi::from_channels(zero, zero, zero)
        }
    }
}

impl<T> FromColor<Rgi<T>> for Rgb<T>
    where T: PosNormalChannelScalar + Float
{
    fn from_color(from: &Rgi<T>) -> Self {
        let sum = from.intensity() * num::cast(3.0).unwrap();
        let red = from.red() * sum;
        let green = from.green() * sum;
        let blue = from.blue() * sum;

        Rgb::from_channels(red, green, blue)
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use convert::*;
    use color::*;
    use rgb::Rgb;
    use test;

    #[test]
    fn test_construct() {
        let c1 = Rgi::from_channels(0.5, 0.2, 1.0);
        assert_relative_eq!(c1.red(), 0.5);
        assert_relative_eq!(c1.green(), 0.2);
        assert_relative_eq!(c1.blue(), 0.3);
        assert_relative_eq!(c1.intensity(), 1.0);
        assert_eq!(c1.to_tuple(), (0.5, 0.2, 1.0));
        assert_relative_eq!(Rgi::from_tuple(c1.to_tuple()), c1);

        let c2 = Rgi::from_channels(0.0, 0.0, 0.5);
        assert_relative_eq!(c2.red(), 0.0);
        assert_relative_eq!(c2.green(), 0.0);
        assert_relative_eq!(c2.blue(), 1.0);
        assert_relative_eq!(c2.intensity(), 0.5);
        assert_eq!(c2.to_tuple(), (0.0, 0.0, 0.5));

        let c3 = Rgi::from_channels(0.7, 0.3, 0.0);
        assert_relative_eq!(c3.red(), 0.7);
        assert_relative_eq!(c3.green(), 0.3);
        assert_relative_eq!(c3.blue(), 0.0);
        assert_relative_eq!(c3.intensity(), 0.0);
        assert_eq!(c3.to_tuple(), (0.7, 0.3, 0.0));
        assert_relative_eq!(Rgi::from_tuple(c3.to_tuple()), c3);
    }

    #[test]
    fn test_set_channels() {
        let mut c1 = Rgi::from_channels(0.3, 0.2, 0.5);
        c1.set_red(0.6);
        assert_relative_eq!(c1.red(), 0.6);
        assert_relative_eq!(c1.green(), 0.1142857, epsilon=1e-6);
        assert_relative_eq!(c1.blue(), 0.2857143, epsilon=1e-6);
        assert_relative_eq!(c1.intensity(), 0.5);

        let mut c2 = Rgi::from_channels(0.333333, 0.333333, 0.9);
        c2.set_green(0.5);
        assert_relative_eq!(c2.red(), 0.25, epsilon=1e-6);
        assert_relative_eq!(c2.green(), 0.5, epsilon=1e-6);
        assert_relative_eq!(c2.blue(), 0.25, epsilon=1e-6);
        assert_relative_eq!(c2.intensity(), 0.9, epsilon=1e-6);
        c2.set_green(1.0);
        assert_relative_eq!(c2.red(), 0.0, epsilon=1e-6);
        assert_relative_eq!(c2.green(), 1.0, epsilon=1e-6);
        assert_relative_eq!(c2.blue(), 0.0, epsilon=1e-6);

        let mut c3 = Rgi::from_channels(0.6, 0.3, 0.83);
        c3.set_blue(0.7);
        assert_relative_eq!(c3.red(), 0.2, epsilon=1e-6);
        assert_relative_eq!(c3.green(), 0.1, epsilon=1e-6);
        assert_relative_eq!(c3.blue(), 0.7, epsilon=1e-6);
        assert_relative_eq!(c3.intensity(), 0.83, epsilon=1e-6);

        let mut c4 = Rgi::from_channels(1.0, 0.0, 0.6);
        c4.set_red(0.5);
        assert_relative_eq!(c4.red(), 0.5);
        assert_relative_eq!(c4.green(), 0.25);
        assert_relative_eq!(c4.blue(), 0.25);
    }

    #[test]
    fn test_flatten() {
        let c1 = Rgi::from_channels(0.2, 0.5, 0.6);
        assert_eq!(c1.as_slice(), &[0.2, 0.5, 0.6]);
        assert_relative_eq!(Rgi::from_slice(c1.as_slice()), c1);
    }

    #[test]
    fn test_normalize() {
        let c1 = Rgi::from_channels(0.5, 0.2, 0.8);
        assert_relative_eq!(c1.normalize(), c1);
        assert!(c1.is_normalized());
        let c2 = Rgi::from_channels(0.0, 0.0, 1.2);
        assert_relative_eq!(c2.normalize(), Rgi::from_channels(0.0, 0.0, 1.0));
        assert!(!c2.is_normalized());
    }

    #[test]
    #[should_panic]
    fn test_constructor_oob_panic() {
        let mut c1 = Rgi::from_channels(0.7, 0.4, 0.9);
        c1.set_blue(0.0);
    }

    #[test]
    #[should_panic]
    fn test_red_setter_oob_panic() {
        let mut c1 = Rgi::from_channels(0.2, 0.3, 0.8);
        c1.set_red(1.2);
    }
    #[test]
    #[should_panic]
    fn test_green_setter_oob_panic() {
        let mut c1 = Rgi::from_channels(0.2, 0.3, 0.8);
        c1.set_green(1.00000000001);
    }

    #[test]
    fn test_lerp() {
        let c1 = Rgi::from_channels(0.3, 0.6, 0.5);
        let c2 = Rgi::from_channels(0.1, 0.4, 1.0);
        assert_relative_eq!(c1.lerp(&c2, 0.0), c1);
        assert_relative_eq!(c1.lerp(&c2, 1.0), c2);
        assert_relative_eq!(c1.lerp(&c2, 0.5), Rgi::from_channels(0.2, 0.5, 0.75));
        assert_relative_eq!(c1.lerp(&c2, 0.75), Rgi::from_channels(0.15, 0.45, 0.875),
            epsilon=1e-5);
    }

    #[test]
    fn test_from_to_rgb() {
        let test_data = test::build_hwb_test_data();
        for item in test_data.iter() {
            let rgi = Rgi::from_color(&item.rgb);
            let rgb = Rgb::from_color(&rgi);
            assert_relative_eq!(rgb, item.rgb, epsilon=1e-6);
        }

        let rgb1 = Rgb::from_channels(0.50, 0.50, 1.0);
        let rgi1 = Rgi::from_color(&rgb1);
        assert_relative_eq!(rgi1, Rgi::from_channels(0.25, 0.25, 0.6666666666),
                            epsilon=1e-6);
        assert_relative_eq!(Rgb::from_color(&rgi1), rgb1);

        let rgb2 = Rgb::from_channels(0.00, 0.00, 0.00);
        let rgi2 = Rgi::from_color(&rgb2);
        assert_relative_eq!(rgi2, Rgi::from_channels(0.0, 0.0, 0.0));
        assert_relative_eq!(Rgb::from_color(&rgi2), rgb2);

        let rgb3 = Rgb::from_channels(1.0, 1.0, 1.0);
        let rgi3 = Rgi::from_color(&rgb3);
        assert_relative_eq!(rgi3, Rgi::from_channels(0.333333, 0.333333, 1.0),
                            epsilon=1e-5);
        assert_relative_eq!(Rgb::from_color(&rgi3), rgb3);
    }

    #[test]
    fn color_cast() {
        let c1 = Rgi::from_channels(0.6f32, 0.2, 0.9);
        assert_relative_eq!(c1.color_cast(), c1);
        assert_relative_eq!(c1.color_cast::<f64>().color_cast(), c1);
        assert_relative_eq!(c1.color_cast(), Rgi::from_channels(0.6, 0.2, 0.9),
            epsilon=1e-6);
    }
}
<commit_msg>Rgi::from_tuple will now panic if channels are out of bound.<commit_after>use std::mem;
use std::slice;
use std::fmt;
use approx;
use num;
use num::Float;
use channel::{PosNormalBoundedChannel, PosNormalChannelScalar, ColorChannel, ChannelFormatCast,
              ChannelCast};
use color::{Color, Lerp, Flatten, Bounded};
use convert::FromColor;
use rgb::Rgb;

pub struct RgiTag;

#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Hash)]
pub struct Rgi<T> {
    red: PosNormalBoundedChannel<T>,
    green: PosNormalBoundedChannel<T>,
    intensity: PosNormalBoundedChannel<T>,
}

impl<T> Rgi<T>
    where T: PosNormalChannelScalar + Float
{
    pub fn from_channels(red: T, green: T, intensity: T) -> Self {
        let zero = num::cast(0.0).unwrap();
        if red + green > num::cast(1.0).unwrap() || red + green < num::cast(0.0).unwrap() {
            panic!("rgi channels must sum to exactly 1.0");
        }
        assert!(red >= zero);
        assert!(green >= zero);
        Rgi {
            red: PosNormalBoundedChannel::new(red),
            green: PosNormalBoundedChannel::new(green),
            intensity: PosNormalBoundedChannel::new(intensity),
        }
    }

    impl_color_color_cast_square!(Rgi {red, green, intensity},
        chan_traits={PosNormalChannelScalar});

    pub fn red(&self) -> T {
        self.red.0.clone()
    }
    pub fn green(&self) -> T {
        self.green.0.clone()
    }
    pub fn blue(&self) -> T {
        num::cast::<_, T>(1.0).unwrap() - self.green() - self.red()
    }
    pub fn intensity(&self) -> T {
        self.intensity.0.clone()
    }
    pub fn intensity_mut(&mut self) -> &mut T {
        &mut self.intensity.0
    }
    pub fn set_red(&mut self, val: T) {
        let (red, green, _) = Self::rescale_channels(val, self.green(), self.blue());
        self.red.0 = red;
        self.green.0 = green;
    }
    pub fn set_green(&mut self, val: T) {
        let (green, red, _) = Self::rescale_channels(val, self.red(), self.blue());
        self.red.0 = red;
        self.green.0 = green;
    }
    pub fn set_blue(&mut self, val: T) {
        let (_, red, green) = Self::rescale_channels(val, self.red(), self.green());
        self.red.0 = red;
        self.green.0 = green;
    }
    pub fn set_intensity(&mut self, val: T) {
        self.intensity.0 = val;
    }

    fn rescale_channels(primary: T, c2: T, c3: T) -> (T, T, T) {
        let new_primary = primary;
        if new_primary > PosNormalBoundedChannel::max_bound() ||
           new_primary < PosNormalBoundedChannel::min_bound() {
            panic!("rgi color channels must be 1.0 or below");
        }

        let zero = num::cast(0.0).unwrap();
        let rem_scale = c2 + c3;
        let rem = num::cast::<_, T>(1.0).unwrap() - new_primary;
        if rem_scale > zero {
            (new_primary, (c2 / rem_scale) * rem, (c3 / rem_scale) * rem)
        } else {
            let one_half = num::cast(0.5).unwrap();
            (new_primary, rem * one_half, rem * one_half)
        }
    }
}

impl<T> Color for Rgi<T>
    where T: PosNormalChannelScalar + Float
{
    type Tag = RgiTag;
    type ChannelsTuple = (T, T, T);

    #[inline]
    fn num_channels() -> u32 {
        3
    }

    fn from_tuple(values: Self::ChannelsTuple) -> Self {
        Rgi::from_channels(values.0, values.1, values.2)
    }
    fn to_tuple(self) -> Self::ChannelsTuple {
        (self.red.0, self.green.0, self.intensity.0)
    }
}

impl<T> Lerp for Rgi<T>
    where T: PosNormalChannelScalar + Lerp + Float
{
    type Position = <T as Lerp>::Position;
    impl_color_lerp_square!(Rgi {red, green, intensity});
}

impl<T> Flatten for Rgi<T>
    where T: PosNormalChannelScalar + Float
{
    type ScalarFormat = T;

    impl_color_as_slice!(T);
    impl_color_from_slice_square!(Rgi<T> {red:PosNormalBoundedChannel - 0,
        green:PosNormalBoundedChannel - 1, intensity:PosNormalBoundedChannel - 2});
}

impl<T> Bounded for Rgi<T>
    where T: PosNormalChannelScalar + Float
{
    impl_color_bounded!(Rgi {red, green, intensity});
}

impl<T> approx::ApproxEq for Rgi<T>
    where T: PosNormalChannelScalar + approx::ApproxEq + Float,
          T::Epsilon: Clone
{
    impl_approx_eq!({red, green, intensity});
}

impl<T> Default for Rgi<T>
    where T: PosNormalChannelScalar + num::Zero + Float
{
    impl_color_default!(Rgi {red:PosNormalBoundedChannel, green:PosNormalBoundedChannel,
        intensity:PosNormalBoundedChannel});
}

impl<T> fmt::Display for Rgi<T>
    where T: PosNormalChannelScalar + fmt::Display + Float
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Rgi({}, {}, {})", self.red, self.green, self.intensity)
    }
}

impl<T> FromColor<Rgb<T>> for Rgi<T>
    where T: PosNormalChannelScalar + Float
{
    fn from_color(from: &Rgb<T>) -> Self {
        let zero = num::cast(0.0).unwrap();
        let sum = from.red() + from.green() + from.blue();

        if sum != zero {
            let r = from.red() / sum;
            let g = from.green() / sum;

            let i = num::cast::<_, T>(1.0 / 3.0).unwrap() * sum;

            Rgi::from_channels(r, g, i)
        } else {
            Rgi::from_channels(zero, zero, zero)
        }
    }
}

impl<T> FromColor<Rgi<T>> for Rgb<T>
    where T: PosNormalChannelScalar + Float
{
    fn from_color(from: &Rgi<T>) -> Self {
        let sum = from.intensity() * num::cast(3.0).unwrap();
        let red = from.red() * sum;
        let green = from.green() * sum;
        let blue = from.blue() * sum;

        Rgb::from_channels(red, green, blue)
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use convert::*;
    use color::*;
    use rgb::Rgb;
    use test;

    #[test]
    fn test_construct() {
        let c1 = Rgi::from_channels(0.5, 0.2, 1.0);
        assert_relative_eq!(c1.red(), 0.5);
        assert_relative_eq!(c1.green(), 0.2);
        assert_relative_eq!(c1.blue(), 0.3);
        assert_relative_eq!(c1.intensity(), 1.0);
        assert_eq!(c1.to_tuple(), (0.5, 0.2, 1.0));
        assert_relative_eq!(Rgi::from_tuple(c1.to_tuple()), c1);

        let c2 = Rgi::from_channels(0.0, 0.0, 0.5);
        assert_relative_eq!(c2.red(), 0.0);
        assert_relative_eq!(c2.green(), 0.0);
        assert_relative_eq!(c2.blue(), 1.0);
        assert_relative_eq!(c2.intensity(), 0.5);
        assert_eq!(c2.to_tuple(), (0.0, 0.0, 0.5));

        let c3 = Rgi::from_channels(0.7, 0.3, 0.0);
        assert_relative_eq!(c3.red(), 0.7);
        assert_relative_eq!(c3.green(), 0.3);
        assert_relative_eq!(c3.blue(), 0.0);
        assert_relative_eq!(c3.intensity(), 0.0);
        assert_eq!(c3.to_tuple(), (0.7, 0.3, 0.0));
        assert_relative_eq!(Rgi::from_tuple(c3.to_tuple()), c3);
    }

    #[test]
    fn test_set_channels() {
        let mut c1 = Rgi::from_channels(0.3, 0.2, 0.5);
        c1.set_red(0.6);
        assert_relative_eq!(c1.red(), 0.6);
        assert_relative_eq!(c1.green(), 0.1142857, epsilon=1e-6);
        assert_relative_eq!(c1.blue(), 0.2857143, epsilon=1e-6);
        assert_relative_eq!(c1.intensity(), 0.5);

        let mut c2 = Rgi::from_channels(0.333333, 0.333333, 0.9);
        c2.set_green(0.5);
        assert_relative_eq!(c2.red(), 0.25, epsilon=1e-6);
        assert_relative_eq!(c2.green(), 0.5, epsilon=1e-6);
        assert_relative_eq!(c2.blue(), 0.25, epsilon=1e-6);
        assert_relative_eq!(c2.intensity(), 0.9, epsilon=1e-6);
        c2.set_green(1.0);
        assert_relative_eq!(c2.red(), 0.0, epsilon=1e-6);
        assert_relative_eq!(c2.green(), 1.0, epsilon=1e-6);
        assert_relative_eq!(c2.blue(), 0.0, epsilon=1e-6);

        let mut c3 = Rgi::from_channels(0.6, 0.3, 0.83);
        c3.set_blue(0.7);
        assert_relative_eq!(c3.red(), 0.2, epsilon=1e-6);
        assert_relative_eq!(c3.green(), 0.1, epsilon=1e-6);
        assert_relative_eq!(c3.blue(), 0.7, epsilon=1e-6);
        assert_relative_eq!(c3.intensity(), 0.83, epsilon=1e-6);

        let mut c4 = Rgi::from_channels(1.0, 0.0, 0.6);
        c4.set_red(0.5);
        assert_relative_eq!(c4.red(), 0.5);
        assert_relative_eq!(c4.green(), 0.25);
        assert_relative_eq!(c4.blue(), 0.25);
    }

    #[test]
    fn test_flatten() {
        let c1 = Rgi::from_channels(0.2, 0.5, 0.6);
        assert_eq!(c1.as_slice(), &[0.2, 0.5, 0.6]);
        assert_relative_eq!(Rgi::from_slice(c1.as_slice()), c1);
    }

    #[test]
    fn test_normalize() {
        let c1 = Rgi::from_channels(0.5, 0.2, 0.8);
        assert_relative_eq!(c1.normalize(), c1);
        assert!(c1.is_normalized());
        let c2 = Rgi::from_channels(0.0, 0.0, 1.2);
        assert_relative_eq!(c2.normalize(), Rgi::from_channels(0.0, 0.0, 1.0));
        assert!(!c2.is_normalized());
    }

    #[test]
    #[should_panic]
    fn test_constructor_oob_panic() {
        let mut c1 = Rgi::from_channels(0.7, 0.4, 0.9);
        c1.set_blue(0.0);
    }

    #[test]
    #[should_panic]
    fn test_red_setter_oob_panic() {
        let mut c1 = Rgi::from_channels(0.2, 0.3, 0.8);
        c1.set_red(1.2);
    }
    #[test]
    #[should_panic]
    fn test_green_setter_oob_panic() {
        let mut c1 = Rgi::from_channels(0.2, 0.3, 0.8);
        c1.set_green(1.00000000001);
    }

    #[test]
    fn test_lerp() {
        let c1 = Rgi::from_channels(0.3, 0.6, 0.5);
        let c2 = Rgi::from_channels(0.1, 0.4, 1.0);
        assert_relative_eq!(c1.lerp(&c2, 0.0), c1);
        assert_relative_eq!(c1.lerp(&c2, 1.0), c2);
        assert_relative_eq!(c1.lerp(&c2, 0.5), Rgi::from_channels(0.2, 0.5, 0.75));
        assert_relative_eq!(c1.lerp(&c2, 0.75), Rgi::from_channels(0.15, 0.45, 0.875),
            epsilon=1e-5);
    }

    #[test]
    fn test_from_to_rgb() {
        let test_data = test::build_hwb_test_data();
        for item in test_data.iter() {
            let rgi = Rgi::from_color(&item.rgb);
            let rgb = Rgb::from_color(&rgi);
            assert_relative_eq!(rgb, item.rgb, epsilon=1e-6);
        }

        let rgb1 = Rgb::from_channels(0.50, 0.50, 1.0);
        let rgi1 = Rgi::from_color(&rgb1);
        assert_relative_eq!(rgi1, Rgi::from_channels(0.25, 0.25, 0.6666666666),
                            epsilon=1e-6);
        assert_relative_eq!(Rgb::from_color(&rgi1), rgb1);

        let rgb2 = Rgb::from_channels(0.00, 0.00, 0.00);
        let rgi2 = Rgi::from_color(&rgb2);
        assert_relative_eq!(rgi2, Rgi::from_channels(0.0, 0.0, 0.0));
        assert_relative_eq!(Rgb::from_color(&rgi2), rgb2);

        let rgb3 = Rgb::from_channels(1.0, 1.0, 1.0);
        let rgi3 = Rgi::from_color(&rgb3);
        assert_relative_eq!(rgi3, Rgi::from_channels(0.333333, 0.333333, 1.0),
                            epsilon=1e-5);
        assert_relative_eq!(Rgb::from_color(&rgi3), rgb3);
    }

    #[test]
    fn color_cast() {
        let c1 = Rgi::from_channels(0.6f32, 0.2, 0.9);
        assert_relative_eq!(c1.color_cast(), c1);
        assert_relative_eq!(c1.color_cast::<f64>().color_cast(), c1);
        assert_relative_eq!(c1.color_cast(), Rgi::from_channels(0.6, 0.2, 0.9),
            epsilon=1e-6);
    }
}
<|endoftext|>