<commit_before>#![feature(core)]
#![feature(std_misc)]
#![feature(fs)]
#![feature(io)]
#![feature(process)]

//! #Introduction
//! This crate focuses on geting system information.
//!
//! For now it supports Linux, Mac OS X and Windows.
//! And now it can get information of kernel/cpu/memory/disk/load/hostname and so on.
//!

use std::ffi;
use std::io::Read;
use std::fs::File;

/// System load average value.
#[repr(C)]
pub struct LoadAvg {
    /// Average load within one minite.
    pub one: f64,
    /// Average load within five minites.
    pub five: f64,
    /// Average load within fifteen minites.
    pub fifteen: f64
}

/// System memory information.
#[repr(C)]
pub struct MemInfo {
    /// Total physical memory.
    pub total: u64,
    pub free:  u64,
    pub avail: u64,

    pub buffers: u64,
    pub cached:  u64,

    /// Total swap memory.
    pub swap_total: u64,
    pub swap_free:  u64
}

/// System momory information.
#[repr(C)]
pub struct DiskInfo {
    pub total: u64,
    pub free: u64
}

extern {
    fn get_os_type() -> *const i8;
    fn get_os_release() -> *const i8;

    fn get_cpu_num() -> u32;
    fn get_cpu_speed() -> u64;

    fn get_loadavg() -> LoadAvg;
    fn get_proc_total() -> u64;

    fn get_mem_info() -> MemInfo;
    fn get_disk_info() -> DiskInfo;
}

/// Get operation system type.
///
/// Such as "Linux", "Darwin", "Windows".
pub fn os_type() -> Result<String, String> {
    if cfg!(target_os = "linux") {
        let mut f = File::open("/proc/sys/kernel/ostype").unwrap();
        let mut s = String::new();
        let _ = f.read_to_string(&mut s).unwrap();
        s.pop();  // pop '\n'
        Ok(s)
    } else if cfg!(target_os = "macos") ||
        cfg!(target_os = "windows")
    {
        Ok(unsafe {
            let p = get_os_type();
            String::from_utf8_lossy(ffi::CStr::from_ptr(p).to_bytes()).into_owned()
        })
    } else {
        Err("Unsupported system".to_string())
    }
}

/// Get operation system release version.
///
/// Such as "3.19.0-gentoo"
pub fn os_release() -> Result<String, String> {
    if cfg!(target_os = "linux") {
        let mut f = File::open("/proc/sys/kernel/osrelease").unwrap();
        let mut s = String::new();
        let _ = f.read_to_string(&mut s).unwrap();
        s.pop();
        Ok(s)
    } else if cfg!(target_os = "macos") ||
        cfg!(target_os = "windows")
    {
        Ok(unsafe {
            let p = get_os_release();
            String::from_utf8_lossy(ffi::CStr::from_ptr(p).to_bytes()).into_owned()
        })
    } else {
        Err("Unsupported system".to_string())
    }
}

/// Get cpu num quantity.
///
/// Notice, it returns the logical cpu quantity.
pub fn cpu_num() -> Result<u32, String> {
    if cfg!(target_os = "linux")
        || cfg!(target_os = "macos") || cfg!(target_os = "windows")
    {
        Ok(unsafe { get_cpu_num() })
    } else {
        Err("Unsupported system".to_string())
    }
}

/// Get cpu speed.
///
/// Such as 2500, that is 2500 MHz.
pub fn cpu_speed() -> Result<u64, String> {
    if cfg!(target_os = "linux") {
        // /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq
        let mut f = File::open("/proc/cpuinfo").unwrap();
        let mut s = String::new();
        let _ = f.read_to_string(&mut s).unwrap();
        let mut lines = s.as_slice().split('\n');
        Ok({
            for _ in 0..7 {
                lines.next();
            }
            let mut words = lines.next().unwrap().split(':');
            words.next();
            let s = words.next().unwrap().trim().trim_right_matches('\n');
            s.parse::<f64>().unwrap() as u64
        })
    } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        Ok(unsafe { get_cpu_speed() })
    } else {
        Err("Unsupported system".to_string())
    }
}

/// Get system load average value.
///
/// Notice, on windows, one/five/fifteen of the LoadAvg returned are the current load.
pub fn loadavg() -> Result<LoadAvg, String> {
    if cfg!(target_os = "linux") {
        let mut f = File::open("/proc/loadavg").unwrap();
        let mut s = String::new();
        let _ = f.read_to_string(&mut s).unwrap();
        let mut words = s.as_slice().split(' ');
        let one = words.next().unwrap().parse::<f64>().unwrap();
        let five = words.next().unwrap().parse::<f64>().unwrap();
        let fifteen = words.next().unwrap().parse::<f64>().unwrap();
        Ok(LoadAvg { one: one, five: five, fifteen: fifteen} )
    } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        Ok(unsafe { get_loadavg() })
    } else {
        Err("Unsupported system".to_string())
    }
}

/// Get current processes quantity.
///
/// Notice, it temporarily does not support Windows.
pub fn proc_total() -> Result<u64, String> {
    if cfg!(target_os = "linux") {
        let mut f = File::open("/proc/loadavg").unwrap();
        let mut s = String::new();
        let _ = f.read_to_string(&mut s).unwrap();
        Ok({
            let mut words = s.as_slice().splitn(3, ' ');
            for _ in 0..3 {
                words.next();
            }
            let mut words = words.next().unwrap().split('/');
            words.next();
            let mut words = words.next().unwrap().split(' ');
            words.next().unwrap().parse::<u64>().unwrap()
        })
    } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        Ok(unsafe { get_proc_total() })
    } else {
        Err("Unsupported system".to_string())
    }
}

// Analyse number from line.
fn get_mem_num(line: &str) -> u64 {
    let mut line = line.splitn(1, ' ');
    line.next();
    line.next().unwrap().trim_left().split(' ').next().unwrap()
        .parse::<u64>().unwrap()
}

/// Get memory information.
///
/// On Mac OS X and Windows, the buffers and cached variables of the MemInfo returned are zero.
pub fn mem_info() -> Result<MemInfo, String> {
    if cfg!(target_os = "linux") {
        let mut f = File::open("/proc/meminfo").unwrap();
        let mut s = String::new();
        let _ = f.read_to_string(&mut s).unwrap();
        let mut lines = s.as_slice().split('\n');
        let total = get_mem_num(lines.next().unwrap());
        let free = get_mem_num(lines.next().unwrap());
        let avail = get_mem_num(lines.next().unwrap());
        let buffers = get_mem_num(lines.next().unwrap());
        let cached = get_mem_num(lines.next().unwrap());
        let swap_total = {
            for _ in 0..9 {
                lines.next();
            }
            get_mem_num(lines.next().unwrap())
        };
        let swap_free = get_mem_num(lines.next().unwrap());

        Ok(MemInfo{ total: total, free: free, avail: avail,
                    buffers: buffers, cached: cached,
                    swap_total: swap_total, swap_free: swap_free})
    } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        Ok(unsafe { get_mem_info() })
    } else {
        Err("Unsupported system".to_string())
    }
}

/// Get disk information.
///
/// Notice, it just calculate current disk on Windows.
pub fn disk_info() -> Result<DiskInfo, String> {
    if cfg!(target_os = "linux") ||
        cfg!(target_os = "macos") ||
        cfg!(target_os = "windows")
    {
        Ok(unsafe { get_disk_info() })
    } else {
        Err("Unsupported system".to_string())
    }
}

pub fn hostname() -> Result<String, String> {
    use std::process::Command;
    if cfg!(unix) {
        let output = match Command::new("hostname").output() {
            Ok(o)  => o,
            Err(e) => return Err(format!("failed to execute process: {}", e)),
        };
        let mut s = String::from_utf8(output.stdout).unwrap();
        s.pop();  // pop '\n'
        Ok(s)
    } else if cfg!(windows) {
        let output = match Command::new("hostname").output() {
            Ok(o)  => o,
            Err(e) => return Err(format!("failed to execute process: {}", e)),
        };
        let mut s = String::from_utf8(output.stdout).unwrap();
        s.pop();  // pop '\n'
        Ok(s)
    } else {
        Err("Unsupported system".to_string())
    }
}

<commit_msg>add a comment<commit_after>#![feature(core)]
#![feature(std_misc)]
#![feature(fs)]
#![feature(io)]
#![feature(process)]

//! #Introduction
//! This crate focuses on geting system information.
//!
//! For now it supports Linux, Mac OS X and Windows.
//! And now it can get information of kernel/cpu/memory/disk/load/hostname and so on.
//!

use std::ffi;
use std::io::Read;
use std::fs::File;

/// System load average value.
#[repr(C)]
pub struct LoadAvg {
    /// Average load within one minite.
    pub one: f64,
    /// Average load within five minites.
    pub five: f64,
    /// Average load within fifteen minites.
    pub fifteen: f64
}

/// System memory information.
#[repr(C)]
pub struct MemInfo {
    /// Total physical memory.
    pub total: u64,
    pub free:  u64,
    pub avail: u64,

    pub buffers: u64,
    pub cached:  u64,

    /// Total swap memory.
    pub swap_total: u64,
    pub swap_free:  u64
}

/// System momory information.
#[repr(C)]
pub struct DiskInfo {
    pub total: u64,
    pub free: u64
}

extern {
    fn get_os_type() -> *const i8;
    fn get_os_release() -> *const i8;

    fn get_cpu_num() -> u32;
    fn get_cpu_speed() -> u64;

    fn get_loadavg() -> LoadAvg;
    fn get_proc_total() -> u64;

    fn get_mem_info() -> MemInfo;
    fn get_disk_info() -> DiskInfo;
}

/// Get operation system type.
///
/// Such as "Linux", "Darwin", "Windows".
pub fn os_type() -> Result<String, String> {
    if cfg!(target_os = "linux") {
        let mut f = File::open("/proc/sys/kernel/ostype").unwrap();
        let mut s = String::new();
        let _ = f.read_to_string(&mut s).unwrap();
        s.pop();  // pop '\n'
        Ok(s)
    } else if cfg!(target_os = "macos") ||
        cfg!(target_os = "windows")
    {
        Ok(unsafe {
            let p = get_os_type();
            String::from_utf8_lossy(ffi::CStr::from_ptr(p).to_bytes()).into_owned()
        })
    } else {
        Err("Unsupported system".to_string())
    }
}

/// Get operation system release version.
///
/// Such as "3.19.0-gentoo"
pub fn os_release() -> Result<String, String> {
    if cfg!(target_os = "linux") {
        let mut f = File::open("/proc/sys/kernel/osrelease").unwrap();
        let mut s = String::new();
        let _ = f.read_to_string(&mut s).unwrap();
        s.pop();
        Ok(s)
    } else if cfg!(target_os = "macos") ||
        cfg!(target_os = "windows")
    {
        Ok(unsafe {
            let p = get_os_release();
            String::from_utf8_lossy(ffi::CStr::from_ptr(p).to_bytes()).into_owned()
        })
    } else {
        Err("Unsupported system".to_string())
    }
}

/// Get cpu num quantity.
///
/// Notice, it returns the logical cpu quantity.
pub fn cpu_num() -> Result<u32, String> {
    if cfg!(target_os = "linux")
        || cfg!(target_os = "macos") || cfg!(target_os = "windows")
    {
        Ok(unsafe { get_cpu_num() })
    } else {
        Err("Unsupported system".to_string())
    }
}

/// Get cpu speed.
///
/// Such as 2500, that is 2500 MHz.
pub fn cpu_speed() -> Result<u64, String> {
    if cfg!(target_os = "linux") {
        // /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq
        let mut f = File::open("/proc/cpuinfo").unwrap();
        let mut s = String::new();
        let _ = f.read_to_string(&mut s).unwrap();
        let mut lines = s.as_slice().split('\n');
        Ok({
            for _ in 0..7 {
                lines.next();
            }
            let mut words = lines.next().unwrap().split(':');
            words.next();
            let s = words.next().unwrap().trim().trim_right_matches('\n');
            s.parse::<f64>().unwrap() as u64
        })
    } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        Ok(unsafe { get_cpu_speed() })
    } else {
        Err("Unsupported system".to_string())
    }
}

/// Get system load average value.
///
/// Notice, on windows, one/five/fifteen of the LoadAvg returned are the current load.
pub fn loadavg() -> Result<LoadAvg, String> {
    if cfg!(target_os = "linux") {
        let mut f = File::open("/proc/loadavg").unwrap();
        let mut s = String::new();
        let _ = f.read_to_string(&mut s).unwrap();
        let mut words = s.as_slice().split(' ');
        let one = words.next().unwrap().parse::<f64>().unwrap();
        let five = words.next().unwrap().parse::<f64>().unwrap();
        let fifteen = words.next().unwrap().parse::<f64>().unwrap();
        Ok(LoadAvg { one: one, five: five, fifteen: fifteen} )
    } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        Ok(unsafe { get_loadavg() })
    } else {
        Err("Unsupported system".to_string())
    }
}

/// Get current processes quantity.
///
/// Notice, it temporarily does not support Windows.
pub fn proc_total() -> Result<u64, String> {
    if cfg!(target_os = "linux") {
        let mut f = File::open("/proc/loadavg").unwrap();
        let mut s = String::new();
        let _ = f.read_to_string(&mut s).unwrap();
        Ok({
            let mut words = s.as_slice().splitn(3, ' ');
            for _ in 0..3 {
                words.next();
            }
            let mut words = words.next().unwrap().split('/');
            words.next();
            let mut words = words.next().unwrap().split(' ');
            words.next().unwrap().parse::<u64>().unwrap()
        })
    } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        Ok(unsafe { get_proc_total() })
    } else {
        Err("Unsupported system".to_string())
    }
}

// Analyse number from line.
fn get_mem_num(line: &str) -> u64 {
    let mut line = line.splitn(1, ' ');
    line.next();
    line.next().unwrap().trim_left().split(' ').next().unwrap()
        .parse::<u64>().unwrap()
}

/// Get memory information.
///
/// On Mac OS X and Windows, the buffers and cached variables of the MemInfo returned are zero.
pub fn mem_info() -> Result<MemInfo, String> {
    if cfg!(target_os = "linux") {
        let mut f = File::open("/proc/meminfo").unwrap();
        let mut s = String::new();
        let _ = f.read_to_string(&mut s).unwrap();
        let mut lines = s.as_slice().split('\n');
        let total = get_mem_num(lines.next().unwrap());
        let free = get_mem_num(lines.next().unwrap());
        let avail = get_mem_num(lines.next().unwrap());
        let buffers = get_mem_num(lines.next().unwrap());
        let cached = get_mem_num(lines.next().unwrap());
        let swap_total = {
            for _ in 0..9 {
                lines.next();
            }
            get_mem_num(lines.next().unwrap())
        };
        let swap_free = get_mem_num(lines.next().unwrap());

        Ok(MemInfo{ total: total, free: free, avail: avail,
                    buffers: buffers, cached: cached,
                    swap_total: swap_total, swap_free: swap_free})
    } else if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        Ok(unsafe { get_mem_info() })
    } else {
        Err("Unsupported system".to_string())
    }
}

/// Get disk information.
///
/// Notice, it just calculate current disk on Windows.
pub fn disk_info() -> Result<DiskInfo, String> {
    if cfg!(target_os = "linux") ||
        cfg!(target_os = "macos") ||
        cfg!(target_os = "windows")
    {
        Ok(unsafe { get_disk_info() })
    } else {
        Err("Unsupported system".to_string())
    }
}

/// Get hostname.
pub fn hostname() -> Result<String, String> {
    use std::process::Command;
    if cfg!(unix) {
        let output = match Command::new("hostname").output() {
            Ok(o)  => o,
            Err(e) => return Err(format!("failed to execute process: {}", e)),
        };
        let mut s = String::from_utf8(output.stdout).unwrap();
        s.pop();  // pop '\n'
        Ok(s)
    } else if cfg!(windows) {
        let output = match Command::new("hostname").output() {
            Ok(o)  => o,
            Err(e) => return Err(format!("failed to execute process: {}", e)),
        };
        let mut s = String::from_utf8(output.stdout).unwrap();
        s.pop();  // pop '\n'
        Ok(s)
    } else {
        Err("Unsupported system".to_string())
    }
}

<|endoftext|>


<commit_before>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[crate_id = "github.com/mozilla-servo/rust-layers#layers:0.1"];
#[crate_type = "lib"];
#[crate_type = "dylib"];
#[crate_type = "rlib"];

#[feature(managed_boxes)];

#[feature(phase)];
#[phase(syntax, link)] extern crate log;

extern crate geom;
extern crate opengles;
extern crate std;
extern crate serialize;

#[cfg(target_os="macos")]
extern crate core_foundation;
#[cfg(target_os="macos")]
extern crate io_surface;
#[cfg(target_os="macos")]
extern crate collections;

#[cfg(target_os="linux")]
extern crate xlib;

#[cfg(target_os="android")]
extern crate egl;

pub mod layers;
pub mod color;
pub mod rendergl;
pub mod scene;
pub mod texturegl;
pub mod util;

pub mod platform {
    #[cfg(target_os="linux")]
    pub mod linux {
        pub mod surface;
    }
    #[cfg(target_os="macos")]
    pub mod macos {
        pub mod surface;
    }
    #[cfg(target_os="android")]
    pub mod android {
        pub mod surface;
    }
    pub mod surface;
}

<commit_msg>Update to current rust: use the new attributes syntax.<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![crate_id = "github.com/mozilla-servo/rust-layers#layers:0.1"]
#![crate_type = "lib"]
#![crate_type = "dylib"]
#![crate_type = "rlib"]

#![feature(managed_boxes, phase)]

extern crate geom;
#[phase(syntax, link)]
extern crate log;
extern crate opengles;
extern crate std;
extern crate serialize;

#[cfg(target_os="macos")]
extern crate core_foundation;
#[cfg(target_os="macos")]
extern crate io_surface;
#[cfg(target_os="macos")]
extern crate collections;

#[cfg(target_os="linux")]
extern crate xlib;

#[cfg(target_os="android")]
extern crate egl;

pub mod layers;
pub mod color;
pub mod rendergl;
pub mod scene;
pub mod texturegl;
pub mod util;

pub mod platform {
    #[cfg(target_os="linux")]
    pub mod linux {
        pub mod surface;
    }
    #[cfg(target_os="macos")]
    pub mod macos {
        pub mod surface;
    }
    #[cfg(target_os="android")]
    pub mod android {
        pub mod surface;
    }
    pub mod surface;
}

<|endoftext|>


<commit_before>//! # The Redox OS Kernel, version 2
//!
//! The Redox OS Kernel is a hybrid kernel that supports X86 systems and
//! provides Unix-like syscalls for primarily Rust applications
//!
//! ## Syscalls
//! Syscalls in Redox are often handled by userspace `schemes`.
//! The essential syscalls in Redox are as follows:
//!
//! ### Open
//! `open(path: &str, flags: usize) -> Result<file_descriptor: usize>`
//!
//! Open a file, providing a path as a `&str` and flags, defined elsewhere.
//!
//! Returns a number, known as a file descriptor, that is passed to other syscalls
//!
//! ### Close
//! `close(file_descriptor: usize) -> Result<()>`
//!
//! Close a file descriptor, providing the file descriptor from `open`
//!
//! Returns an error, `EBADF`, if the file descriptor was not found.
//!
//! This potential error is often ignored by userspace
//!
//! ### Duplicate
//! `dup(file_descriptor: usize) -> Result<file_descriptor: usize>`
//!
//! Duplicate a file descriptor, providing the file descriptor from `open`
//!
//! Returns a new file descriptor, or an error
//!
//! ### Read
//! `read(file_descriptor: usize, buffer: &mut [u8]) -> Result<count: usize>`
//!
//! Read from a file descriptor, providing the file descriptor from `open` and a mutable buffer
//!
//! Returns the number of bytes actually read, or an error
//!
//! ### Write
//! `write(file_descriptor: usize, buffer: &[u8]) -> Result<count: usize>`
//!
//! Write to a file descriptor, providing the file descriptor from `open` and a const buffer
//!
//! Returns the number of bytes actually written, or an error
//!
//! ### Stat
//! `fstat(file_descriptor: usize, stat: &mut Stat) -> Result<()>`
//!
//! Get information from a file descriptor, providing the file descriptor from `open`
//! and a mutable Stat struct, defined elsewhere.
//!
//! Returns an error if the operation failed
//!
//! ### Path
//! `fpath(file_descriptor: usize, buffer: &mut [u8]) -> Result<count: usize>`
//!
//! Read the path of a file descriptor, providing the file descriptor from `open` and
//! a mutable buffer.
//!
//! Returns the number of bytes actually read, or an error
//!
//! The buffer should be 4096 bytes, to ensure that the entire path will fit.
//! An error will be returned, `ENOBUFS`, if the buffer is not long enough for the name.
//! In this case, it is recommended to add one page, 4096 bytes, to the buffer and retry.

#![feature(alloc)]
#![feature(asm)]
#![feature(collections)]
#![feature(const_fn)]
#![feature(drop_types_in_const)]
#![feature(question_mark)]
#![feature(thread_local)]
#![no_std]

use arch::interrupt;

/// Architecture specific items (test)
#[cfg(test)]
#[macro_use]
extern crate arch_test as arch;

/// Architecture specific items (ARM)
#[cfg(all(not(test), target_arch = "arm"))]
#[macro_use]
extern crate arch_arm as arch;

/// Architecture specific items (x86_64)
#[cfg(all(not(test), target_arch = "x86_64"))]
#[macro_use]
extern crate arch_x86_64 as arch;

extern crate alloc;
#[macro_use]
extern crate collections;

#[macro_use]
extern crate bitflags;
extern crate goblin;
extern crate spin;

/// Context management
pub mod context;

/// ELF file parsing
#[cfg(all(not(test), target_arch = "x86_64"))]
pub mod elf;

/// Schemes, filesystem handlers
pub mod scheme;

/// Syscall handlers
pub mod syscall;

/// Tests
#[cfg(test)]
pub mod tests;

pub extern fn context_test() {
    print!("Test\n");
    unsafe { context::switch(); }

    print!("Test halt\n");
    loop {
        unsafe { interrupt::enable_and_halt(); }
    }
}

#[no_mangle]
pub extern fn kmain() {
    context::init();

    let pid = syscall::getpid();
    println!("BSP: {:?}", pid);

    if let Ok(_context_lock) = context::contexts_mut().spawn(context_test) {
        print!("Spawned context\n");
    }

    print!("Main\n");
    unsafe { context::switch(); }

    print!("Main halt\n");
    loop {
        unsafe { interrupt::enable_and_halt(); }
    }
}

#[no_mangle]
pub extern fn kmain_ap(id: usize) {
    context::init();

    let pid = syscall::getpid();
    println!("AP {}: {:?}", id, pid);

    loop {
        unsafe { interrupt::enable_and_halt() }
    }
}
<commit_msg>Improve efficiency of kernel console<commit_after>//! # The Redox OS Kernel, version 2
//!
//! The Redox OS Kernel is a hybrid kernel that supports X86 systems and
//! provides Unix-like syscalls for primarily Rust applications
//!
//! ## Syscalls
//! Syscalls in Redox are often handled by userspace `schemes`.
//! The essential syscalls in Redox are as follows:
//!
//! ### Open
//! `open(path: &str, flags: usize) -> Result<file_descriptor: usize>`
//!
//! Open a file, providing a path as a `&str` and flags, defined elsewhere.
//!
//! Returns a number, known as a file descriptor, that is passed to other syscalls
//!
//! ### Close
//! `close(file_descriptor: usize) -> Result<()>`
//!
//! Close a file descriptor, providing the file descriptor from `open`
//!
//! Returns an error, `EBADF`, if the file descriptor was not found.
//!
//! This potential error is often ignored by userspace
//!
//! ### Duplicate
//! `dup(file_descriptor: usize) -> Result<file_descriptor: usize>`
//!
//! Duplicate a file descriptor, providing the file descriptor from `open`
//!
//! Returns a new file descriptor, or an error
//!
//! ### Read
//! `read(file_descriptor: usize, buffer: &mut [u8]) -> Result<count: usize>`
//!
//! Read from a file descriptor, providing the file descriptor from `open` and a mutable buffer
//!
//! Returns the number of bytes actually read, or an error
//!
//! ### Write
//! `write(file_descriptor: usize, buffer: &[u8]) -> Result<count: usize>`
//!
//! Write to a file descriptor, providing the file descriptor from `open` and a const buffer
//!
//! Returns the number of bytes actually written, or an error
//!
//! ### Stat
//! `fstat(file_descriptor: usize, stat: &mut Stat) -> Result<()>`
//!
//! Get information from a file descriptor, providing the file descriptor from `open`
//! and a mutable Stat struct, defined elsewhere.
//!
//! Returns an error if the operation failed
//!
//! ### Path
//! `fpath(file_descriptor: usize, buffer: &mut [u8]) -> Result<count: usize>`
//!
//! Read the path of a file descriptor, providing the file descriptor from `open` and
//! a mutable buffer.
//!
//! Returns the number of bytes actually read, or an error
//!
//! The buffer should be 4096 bytes, to ensure that the entire path will fit.
//! An error will be returned, `ENOBUFS`, if the buffer is not long enough for the name.
//! In this case, it is recommended to add one page, 4096 bytes, to the buffer and retry.

#![feature(alloc)]
#![feature(asm)]
#![feature(collections)]
#![feature(const_fn)]
#![feature(drop_types_in_const)]
#![feature(question_mark)]
#![feature(thread_local)]
#![no_std]

use arch::interrupt;

/// Architecture specific items (test)
#[cfg(test)]
#[macro_use]
extern crate arch_test as arch;

/// Architecture specific items (ARM)
#[cfg(all(not(test), target_arch = "arm"))]
#[macro_use]
extern crate arch_arm as arch;

/// Architecture specific items (x86_64)
#[cfg(all(not(test), target_arch = "x86_64"))]
#[macro_use]
extern crate arch_x86_64 as arch;

extern crate alloc;
#[macro_use]
extern crate collections;

#[macro_use]
extern crate bitflags;
extern crate goblin;
extern crate spin;

/// Context management
pub mod context;

/// ELF file parsing
#[cfg(all(not(test), target_arch = "x86_64"))]
pub mod elf;

/// Schemes, filesystem handlers
pub mod scheme;

/// Syscall handlers
pub mod syscall;

/// Tests
#[cfg(test)]
pub mod tests;

pub extern fn context_test() {
    print!("Test\n");
    unsafe { context::switch(); }

    print!("Test halt\n");
    loop {
        unsafe { interrupt::enable_and_halt(); }
    }
}

#[no_mangle]
pub extern fn kmain() {
    context::init();

    let pid = syscall::getpid();
    println!("BSP: {:?}", pid);

    /*
    if let Ok(_context_lock) = context::contexts_mut().spawn(context_test) {
        print!("Spawned context\n");
    }

    print!("Main\n");
    unsafe { context::switch(); }

    print!("Main halt\n");
    */

    loop {
        unsafe { interrupt::enable_and_halt(); }
    }
}

#[no_mangle]
pub extern fn kmain_ap(id: usize) {
    context::init();

    let pid = syscall::getpid();
    println!("AP {}: {:?}", id, pid);

    loop {
        unsafe { interrupt::enable_and_halt() }
    }
}
<|endoftext|>


<commit_before>/**
Katy Williamson kcw4sn
Ben Terner bt3ze
@virginia.edu

Final Project for CS4414 - Operating Systems
A parallel MST implementation on images in Rust

*/

/*
some documentation:
Pixel object is composed of r,g,b values, a color, and an x,y index that takes the place of its adjacency list
Point is just an (x,y) value to denote a pixel's location
Edge contains two points: source and dest, along with the edge cost between them

*/

extern mod extra;
use std::{os, num,hashmap} ;
use extra::{arc,priority_queue};

struct Pixel{
    r: int,
    b: int,
    g: int,
    color: int,
    x: int,
    y: int
}

impl Pixel {
    fn new(red: int, blue: int, green: int, x: int, y: int) -> Pixel {
        Pixel{
            r: red,
            b: blue,
            g: green,
            color: -1,
            x: x,
            y: y
        }
    }
}

impl Clone for Pixel{
    fn clone(&self) -> Pixel {
        Pixel{
            r: self.r,
            b: self.b,
            g: self.g,
            color: self.color,
            x: self.x,
            y: self.y
        }
    }
}

struct Point {
    x: int,
    y: int
}

impl Point{
    fn new(x: int, y: int)-> Point {
        Point {
            x: x,
            y: y
        }
    }
}

struct Edge {
    source: Point,
    dest: Point,
    cost: float
}

impl Edge {
    fn new(s: Point, d: Point, cost: float) -> Edge {
        Edge {
            source: s,
            dest: d,
            cost: cost
        }
    }
}

impl Ord for Edge {
    fn lt(&self, other: &Edge) -> bool {
        self.cost < other.cost
    }
}

fn edgeCost(a: &Pixel, b: &Pixel) -> float {
    num::sqrt( (
            a.r*a.r-b.r*b.r + a.g*a.g-b.g*b.g + a.b*a.b-b.b*b.b ) as float)
}

fn readImage( filename: &~str) -> ~ [ ~[Pixel]] {
    ~[~[]]
}

fn main(){
    let argv =  os::args();
    println(argv.to_str());

    let pixels: ~[ ~[Pixel] ] = readImage(&argv[1]);

    // width and height should be replaced by just reading them from the file
    let width = match from_str::<int>(argv[2]) {
        Some(x) => x,
        None() => 0
    };
    let height = match from_str::<int>(argv[3]) {
        Some(x) => x,
        None() => 0
    };

    let mut find_arcs: ~[ ~[arc::RWArc<Pixel>] ] =  ~[ ~[]];
    let mut heit = 0;
    let mut wid = 0;
    loop {
        loop {
            find_arcs[heit][wid] = arc::RWArc::new(pixels[heit][wid]);
                wid+=1;
            if(wid == width) {
                wid = 0;
                break;
            }
        }
        heit+=1;
        if(heit == height) {
            break;
        }
    }

    let arcs = find_arcs; // now we have an immutable array that can be shared

    let corners = [ (0,0),(0,width-1),(height-1,0),(height-1,width-1) ];

    for &corner in corners.iter() {
        let (a,b) = corner;
        let shared_arcs = arcs.clone();
        do spawn { // split into threads here

            let mut x=a;
            let mut y=b;
            /*
            weird compiler error:
            let corners = [ (0,0),(0,width-1),(height-1,0),(height-1,width-1) ];
            for &corner in corners.iter(){
            do spawn {
            let mut x = 0;
            let mut y = 0;
            (x,y) = corner
                 }
             }
             */

            let mut queue: priority_queue::PriorityQueue<Edge> =  priority_queue::PriorityQueue::new();
            let mut visited: hashmap::HashMap<(int,int),bool> = hashmap::HashMap::new();

            let mut newvisit: bool = true;

            loop { // iterate through items in the queue, which contains all of the edges/vertices
                if(newvisit){
                    let neighbors = [ (x,y-1),(x+1,y), (x,y+1), (x,y-1)];
                    for &coord in neighbors.iter() {
                        let (w,z) = coord;
                        if w >=0 && w < width && z >=0 && z < height { // bounds checking
                            // if neighbor at coord has not been or colored
                            let mut newvertex = false;
                            let mut uncolored = false;
                            do shared_arcs[w][z].read |dest| {
                                if dest.color < 0 {
                                    uncolored = true; }
                            }
                            if uncolored {
                                do shared_arcs[w][z].write |dest| {
                                    if dest.color < 0 {
                                        do shared_arcs[x][y].read |src| {
                                            dest.color = src.color;
                                        }
                                        newvertex = true;
                                    }
                                }
                            }
                            if newvertex { // then we have a new vertex
                                do shared_arcs[x][y].read |src| {
                                    do shared_arcs[w][z].read |dest| {
                                        queue.push( Edge::new(Point::new(x,y),Point::new(w,z),edgeCost(src,dest)));
                                    }
                                }
                            }
                        }
                    }
                }

                let edge = queue.maybe_pop();
                match edge {
                    Some(e) => {
                        // not in any tree
                        let coord = (e.dest.x,e.dest.y);
                        if *visited.get(&coord) == false { // use visited hashmap to figure out if we're at a new vertex. returns false if it can't return a vertex?
                            visited.insert(coord,true);
                            x = e.dest.x;
                            y = e.dest.y;
                            newvisit = true;
                        } else {
                            newvisit = false;
                        }
                        None => { break; } // this should execute at the end when there are no more unvisited or uncolored nodes for a thread
                    }
                }
            }
        }
    }
}
<commit_msg>compiles again.<commit_after>/**
Katy Williamson kcw4sn
Ben Terner bt3ze
@virginia.edu

Final Project for CS4414 - Operating Systems
A parallel MST implementation on images in Rust

*/

/*
some documentation:
Pixel object is composed of r,g,b values, a color, and an x,y index that takes the place of its adjacency list
Point is just an (x,y) value to denote a pixel's location
Edge contains two points: source and dest, along with the edge cost between them

*/

extern mod extra;
use std::{os, num,hashmap} ;
use extra::{arc,priority_queue};

struct Pixel{
    r: int,
    b: int,
    g: int,
    color: int,
    x: int,
    y: int
}

impl Pixel {
    fn new(red: int, blue: int, green: int, x: int, y: int) -> Pixel {
        Pixel{
            r: red,
            b: blue,
            g: green,
            color: -1,
            x: x,
            y: y
        }
    }
}

impl Clone for Pixel{
    fn clone(&self) -> Pixel {
        Pixel{
            r: self.r,
            b: self.b,
            g: self.g,
            color: self.color,
            x: self.x,
            y: self.y
        }
    }
}

struct Point {
    x: int,
    y: int
}

impl Point{
    fn new(x: int, y: int)-> Point {
        Point {
            x: x,
            y: y
        }
    }
}

struct Edge {
    source: Point,
    dest: Point,
    cost: float
}

impl Edge {
    fn new(s: Point, d: Point, cost: float) -> Edge {
        Edge {
            source: s,
            dest: d,
            cost: cost
        }
    }
}

impl Ord for Edge {
    fn lt(&self, other: &Edge) -> bool {
        self.cost < other.cost
    }
}

fn edgeCost(a: &Pixel, b: &Pixel) -> float {
    num::sqrt( (
            a.r*a.r-b.r*b.r + a.g*a.g-b.g*b.g + a.b*a.b-b.b*b.b ) as float)
}

fn readImage( filename: &~str) -> ~ [ ~[Pixel]] {
    ~[~[]]
}

fn main(){
    let argv =  os::args();
    println(argv.to_str());

    let pixels: ~[ ~[Pixel] ] = readImage(&argv[1]);

    // width and height should be replaced by just reading them from the file
    let width = match from_str::<int>(argv[2]) {
        Some(x) => x,
        None() => 0
    };
    let height = match from_str::<int>(argv[3]) {
        Some(x) => x,
        None() => 0
    };

    let mut find_arcs: ~[ ~[arc::RWArc<Pixel>] ] =  ~[ ~[]];
    let mut heit = 0;
    let mut wid = 0;
    loop {
        loop {
            find_arcs[heit][wid] = arc::RWArc::new(pixels[heit][wid]);
                wid+=1;
            if(wid == width) {
                wid = 0;
                break;
            }
        }
        heit+=1;
        if(heit == height) {
            break;
        }
    }

    let arcs = find_arcs; // now we have an immutable array that can be shared

    let corners = [ (0,0),(0,width-1),(height-1,0),(height-1,width-1) ];

    for &corner in corners.iter() {
        let (a,b) = corner;
        let shared_arcs = arcs.clone();
        do spawn { // split into threads here

            let mut x=a;
            let mut y=b;
            /*
            weird compiler error:
            let corners = [ (0,0),(0,width-1),(height-1,0),(height-1,width-1) ];
            for &corner in corners.iter(){
            do spawn {
            let mut x = 0;
            let mut y = 0;
            (x,y) = corner
                 }
             }
             */

            let mut queue: priority_queue::PriorityQueue<Edge> =  priority_queue::PriorityQueue::new();
            let mut visited: hashmap::HashMap<(int,int),bool> = hashmap::HashMap::new();

            let mut newvisit: bool = true;

            loop { // iterate through items in the queue, which contains all of the edges/vertices
                if(newvisit){
                    let neighbors = [ (x,y-1),(x+1,y), (x,y+1), (x,y-1)];
                    for &coord in neighbors.iter() {
                        let (w,z) = coord;
                        if w >=0 && w < width && z >=0 && z < height { // bounds checking
                            // if neighbor at coord has not been or colored
                            let mut newvertex = false;
                            let mut uncolored = false;
                            do shared_arcs[w][z].read |dest| {
                                if dest.color < 0 {
                                    uncolored = true; }
                            }
                            if uncolored {
                                do shared_arcs[w][z].write |dest| {
                                    if dest.color < 0 {
                                        do shared_arcs[x][y].read |src| {
                                            dest.color = src.color;
                                        }
                                        newvertex = true;
                                    }
                                }
                            }
                            if newvertex { // then we have a new vertex
                                do shared_arcs[x][y].read |src| {
                                    do shared_arcs[w][z].read |dest| {
                                        queue.push( Edge::new(Point::new(x,y),Point::new(w,z),edgeCost(src,dest)));
                                    }
                                }
                            }
                        }
                    }
                }

                let edge = queue.maybe_pop();
                match edge {
                    Some(e) => {
                        // not in any tree
                        let coord = (e.dest.x,e.dest.y);
                        if *visited.get(&coord) == false { // use visited hashmap to figure out if we're at a new vertex. returns false if it can't return a vertex?
                            visited.insert(coord,true);
                            x = e.dest.x;
                            y = e.dest.y;
                            newvisit = true;
                        } else {
                            newvisit = false;
                        }
                    },
                    None => { break; } // this should execute at the end when there are no more unvisited or uncolored nodes for a thread
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use color::PuyoColor;
use column_puyo_list::ColumnPuyoList;
use decision::Decision;
use field::{self, BitField, FieldHeight, FieldIsEmpty};
use std;

#[derive(Clone, Debug, PartialEq)]
pub struct CoreField {
    field: BitField,
    height: [i16; 8],
}

impl CoreField {
    pub fn new() -> CoreField {
        CoreField {
            field: BitField::new(),
            height: [0; 8],
        }
    }

    pub fn from_str(s: &str) -> CoreField {
        let mut cf = CoreField {
            field: BitField::from_str(s),
            height: [0; 8],
        };

        for x in 1 .. field::WIDTH + 1 {
            for y in 1 .. 15 {
                if cf.is_empty(x, y) {
                    cf.height[x] = (y - 1) as i16;
                    break
                }
            }
        }

        cf
    }

    pub fn color(&self, x: usize, y: usize) -> PuyoColor {
        self.field.color(x, y)
    }

    pub fn height(&self, x: usize) -> usize {
        self.height[x] as usize
    }

    pub fn is_color(&self, x: usize, y: usize, c: PuyoColor) -> bool {
        self.field.is_color(x, y, c)
    }

    pub fn is_normal_color(&self, x: usize, y: usize) -> bool {
        self.field.is_normal_color(x, y)
    }

    pub fn is_empty(&self, x: usize, y: usize) -> bool {
        self.field.is_empty(x, y)
    }

    pub fn field(&self) -> &BitField {
        &self.field
    }

    pub fn is_chigiri_decision(&self, decision: &Decision) -> bool {
        debug_assert!(decision.valid(), "decision {:?} should be valid", decision);
        let axis_x = decision.axis_x();
        let child_x = decision.child_x();
        if axis_x == child_x {
            return false;
        }

        self.height(axis_x) != self.height(child_x)
    }

    pub fn is_connected(&self, x: usize, y: usize) -> bool {
        self.field.is_connected(x, y)
    }

    pub fn count_connected_max4(&self, x: usize, y: usize) -> usize {
        self.field.count_connected_max4(x, y)
    }

    pub fn count_connected_max4_with_color(&self, x: usize, y: usize, c: PuyoColor) -> usize {
        self.field.count_connected_max4_with_color(x, y, c)
    }

    pub fn drop_puyo_on_with_max_height(&mut self, x: usize, c: PuyoColor, max_height: usize) -> bool {
        debug_assert!(c != PuyoColor::EMPTY);
        debug_assert!(max_height <= 14);

        if self.height(x) >= std::cmp::min(13, max_height) {
            return false;
        }

        debug_assert!(self.color(x, self.height(x) + 1) == PuyoColor::EMPTY,
                      "x={} max_height={}", x, max_height);

        self.height[x] += 1;
        self.field.set_color(x, self.height[x] as usize, c);

        true
    }

    pub fn drop_column_puyo_list(&mut self, cpl: &ColumnPuyoList) -> bool {
        self.drop_column_puyo_list_with_max_height(cpl, 13)
    }

    pub fn drop_column_puyo_list_with_max_height(&mut self, cpl: &ColumnPuyoList, max_height: usize) -> bool {
        // check size
        for x in 1..7 {
            if self.height(x) + cpl.size_on(x) > max_height {
                return false;
            }
        }

        for x in 1..7 {
            let s = cpl.size_on(x);
            for i in 0..s {
                self.height[x] += 1;
                let c = cpl.get(x, i);
                let h = self.height(x);
                self.field.set_color(x, h, c);
            }
        }

        true
    }
}

impl FieldHeight for CoreField {
    fn height(&self, x: usize) -> usize {
        CoreField::height(self, x)
    }
}

impl FieldIsEmpty for CoreField {
    fn is_empty(&self, x: usize, y: usize) -> bool {
        CoreField::is_empty(self, x, y)
    }
}

#[cfg(test)]
mod tests {
    use super::CoreField;
    use color::PuyoColor;
    use column_puyo_list::ColumnPuyoList;
    use decision::Decision;
    use field;

    #[test]
    fn test_constructor() {
        let cf = CoreField::new();

        for x in 1 .. field::WIDTH + 1 {
            for y in 1 .. field::HEIGHT + 1 {
                assert!(cf.is_empty(x, y));
                assert!(cf.is_color(x, y, PuyoColor::EMPTY));
                assert_eq!(PuyoColor::EMPTY, cf.color(x, y));
            }
        }

        for x in 1 .. field::WIDTH + 1 {
            assert_eq!(0, cf.height(x));
        }
    }

    #[test]
    fn test_from_str() {
        let cf = CoreField::from_str(concat!(
            "R.....",
            "RRRB.."));

        assert_eq!(PuyoColor::WALL, cf.color(0, 1));
        assert_eq!(PuyoColor::RED, cf.color(1, 1));
        assert_eq!(PuyoColor::RED, cf.color(2, 1));
        assert_eq!(PuyoColor::RED, cf.color(3, 1));
        assert_eq!(PuyoColor::BLUE, cf.color(4, 1));
        assert_eq!(PuyoColor::EMPTY, cf.color(5, 1));
        assert_eq!(PuyoColor::EMPTY, cf.color(6, 1));
        assert_eq!(PuyoColor::WALL, cf.color(7, 1));

        assert_eq!(2, cf.height(1));
        assert_eq!(1, cf.height(2));
        assert_eq!(1, cf.height(3));
        assert_eq!(1, cf.height(4));
        assert_eq!(0, cf.height(5));
        assert_eq!(0, cf.height(6));
    }

    #[test]
    fn test_drop_puyo_on() {
        let mut cf = CoreField::from_str(concat!(
            ".....R", // 13
            "OOOOOR", // 12
            "OOOOOO",
            "OOOOOO",
            "OOOOOO",
            "OOOOOO", // 8
            "OOOOOO",
            "OOOOOO",
            "OOOOOO",
            "OOOOOO", // 4
            "OOOOOO",
            "OOOOOO",
            "OOOOOO"));

        assert!(cf.drop_puyo_on_with_max_height(3, PuyoColor::BLUE, 13));
        assert!(cf.drop_puyo_on_with_max_height(4, PuyoColor::BLUE, 13));
        assert!(!cf.drop_puyo_on_with_max_height(4, PuyoColor::BLUE, 13));
        assert!(!cf.drop_puyo_on_with_max_height(6, PuyoColor::BLUE, 13));

        let expected = CoreField::from_str(concat!(
            "..BB.R", // 13
            "OOOOOR", // 12
            "OOOOOO",
            "OOOOOO",
            "OOOOOO",
            "OOOOOO", // 8
            "OOOOOO",
            "OOOOOO",
            "OOOOOO",
            "OOOOOO", // 4
            "OOOOOO",
            "OOOOOO",
            "OOOOOO"));

        assert_eq!(cf, expected);
    }

    #[test]
    fn test_drop_column_puyo_list_on() {
        let mut cf = CoreField::from_str(concat!(
            ".....R", // 13
            "OOOOOR", // 12
            "OOOOOO",
            "OOOOOO",
            "OOOOOO",
            "OOOOOO", // 8
            "OOOOOO",
            "OOOOOO",
            "OOOOOO",
            "OOOOOO", // 4
            "OOOOOO",
            "OOOOOO",
            "OOOOOO"));

        let mut cpl = ColumnPuyoList::new();
        assert!(cpl.add(3, PuyoColor::BLUE));
        assert!(cpl.add(4, PuyoColor::BLUE));
        assert!(cf.drop_column_puyo_list_with_max_height(&cpl, 13));

        let expected = CoreField::from_str(concat!(
            "..BB.R", // 13
            "OOOOOR", // 12
            "OOOOOO",
            "OOOOOO",
            "OOOOOO",
            "OOOOOO", // 8
            "OOOOOO",
            "OOOOOO",
            "OOOOOO",
            "OOOOOO", // 4
            "OOOOOO",
            "OOOOOO",
            "OOOOOO"));

        assert_eq!(cf, expected);
    }

    #[test]
    fn test_is_chigiri_decision_1() {
        let cf = CoreField::new();

        assert!(!cf.is_chigiri_decision(&Decision::new(3, 0)));
        assert!(!cf.is_chigiri_decision(&Decision::new(3, 1)));
        assert!(!cf.is_chigiri_decision(&Decision::new(3, 2)));
        assert!(!cf.is_chigiri_decision(&Decision::new(3, 3)));
    }

    #[test]
    fn test_is_chigiri_decision_2() {
        let cf = CoreField::from_str("..O...");

        assert!(!cf.is_chigiri_decision(&Decision::new(3, 0)));
        assert!(cf.is_chigiri_decision(&Decision::new(3, 1)));
        assert!(!cf.is_chigiri_decision(&Decision::new(3, 2)));
        assert!(cf.is_chigiri_decision(&Decision::new(3, 3)));
    }
}
<commit_msg>Port CoreField::frames_to_drop_next<commit_after>use color::PuyoColor;
use column_puyo_list::ColumnPuyoList;
use decision::Decision;
use field::{self, BitField, FieldHeight, FieldIsEmpty};
use frame;

use std;

#[derive(Clone, Debug, PartialEq)]
pub struct CoreField {
    field: BitField,
    height: [i16; 8],
}

impl CoreField {
    pub fn new() -> CoreField {
        CoreField {
            field: BitField::new(),
            height: [0; 8],
        }
    }

    pub fn from_str(s: &str) -> CoreField {
        let mut cf = CoreField {
            field: BitField::from_str(s),
            height: [0; 8],
        };

        for x in 1 .. field::WIDTH + 1 {
            for y in 1 .. 15 {
                if cf.is_empty(x, y) {
                    cf.height[x] = (y - 1) as i16;
                    break
                }
            }
        }

        cf
    }

    pub fn color(&self, x: usize, y: usize) -> PuyoColor {
        self.field.color(x, y)
    }

    pub fn height(&self, x: usize) -> usize {
        self.height[x] as usize
    }

    pub fn is_color(&self, x: usize, y: usize, c: PuyoColor) -> bool {
        self.field.is_color(x, y, c)
    }

    pub fn is_normal_color(&self, x: usize, y: usize) -> bool {
        self.field.is_normal_color(x, y)
    }

    pub fn is_empty(&self, x: usize, y: usize) -> bool {
        self.field.is_empty(x, y)
    }

    pub fn field(&self) -> &BitField {
        &self.field
    }

    pub fn is_chigiri_decision(&self, decision: &Decision) -> bool {
        debug_assert!(decision.valid(), "decision {:?} should be valid", decision);
        let axis_x = decision.axis_x();
        let child_x = decision.child_x();
        if axis_x == child_x {
            return false;
        }

        self.height(axis_x) != self.height(child_x)
    }

    pub fn is_connected(&self, x: usize, y: usize) -> bool {
        self.field.is_connected(x, y)
    }

    pub fn count_connected_max4(&self, x: usize, y: usize) -> usize {
        self.field.count_connected_max4(x, y)
    }

    pub fn count_connected_max4_with_color(&self, x: usize, y: usize, c: PuyoColor) -> usize {
        self.field.count_connected_max4_with_color(x, y, c)
    }

    pub fn drop_puyo_on_with_max_height(&mut self, x: usize, c: PuyoColor, max_height: usize) -> bool {
        debug_assert!(c != PuyoColor::EMPTY);
        debug_assert!(max_height <= 14);

        if self.height(x) >= std::cmp::min(13, max_height) {
            return false;
        }

        debug_assert!(self.color(x, self.height(x) + 1) == PuyoColor::EMPTY,
                      "x={} max_height={}", x, max_height);

        self.height[x] += 1;
        self.field.set_color(x, self.height[x] as usize, c);

        true
    }

    pub fn drop_column_puyo_list(&mut self, cpl: &ColumnPuyoList) -> bool {
        self.drop_column_puyo_list_with_max_height(cpl, 13)
    }

    pub fn drop_column_puyo_list_with_max_height(&mut self, cpl: &ColumnPuyoList, max_height: usize) -> bool {
        // check size
        for x in 1..7 {
            if self.height(x) + cpl.size_on(x) > max_height {
                return false;
            }
        }

        for x in 1..7 {
            let s = cpl.size_on(x);
            for i in 0..s {
                self.height[x] += 1;
                let c = cpl.get(x, i);
                let h = self.height(x);
                self.field.set_color(x, h, c);
            }
        }

        true
    }

    pub fn frames_to_drop_next(&self, decision: &Decision) -> usize {
        // TODO(mayah): This calculation should be more accurate. We need to compare this with
        // actual AC puyo2 and duel server algorithm. These must be much the same.

        // TODO(mayah): When "kabegoe" happens, we need more frames.
        const KABEGOE_PENALTY: usize = 6;

        let x1 = decision.axis_x();
        let x2 = decision.child_x();

        let mut drop_frames = frame::FRAMES_TO_MOVE_HORIZONTALLY[(3 - x1 as isize).abs() as usize];

        if decision.rot() == 0 {
            let drop_height = field::HEIGHT as isize - self.height(x1) as isize;
            if drop_height <= 0 {
                // TODO(mayah): We need to add penalty here. How much penalty is necessary?
                drop_frames += KABEGOE_PENALTY + frame::FRAMES_GROUNDING;
            } else {
                drop_frames += frame::FRAMES_TO_DROP_FAST[drop_height as usize] + frame::FRAMES_GROUNDING;
            }
        } else if decision.rot() == 2 {
            let mut drop_height = (field::HEIGHT as isize) - (self.height(x1) as isize) - 1;
            // TODO: If puyo lines are high enough, rotation might take time. We should measure this later.
            // It looks we need 3 frames to waiting that each rotation has completed.
            if drop_height < 6 {
                drop_height = 6;
            }

            drop_frames += frame::FRAMES_TO_DROP_FAST[drop_height as usize] + frame::FRAMES_GROUNDING;
        } else {
            if self.height(x1) == self.height(x2) {
                let drop_height = field::HEIGHT as isize - self.height(x1) as isize;
                if drop_height <= 0 {
                    drop_frames += KABEGOE_PENALTY + frame::FRAMES_GROUNDING;
                } else if drop_height < 3 {
                    drop_frames += frame::FRAMES_TO_DROP_FAST[3] + frame::FRAMES_GROUNDING;
                } else {
                    drop_frames += frame::FRAMES_TO_DROP_FAST[drop_height as usize] + frame::FRAMES_GROUNDING;
                }
            } else {
                let min_height = std::cmp::min(self.height(x1), self.height(x2));
                let max_height = std::cmp::max(self.height(x1), self.height(x2));
                let diff_height = max_height - min_height;
                let drop_height = field::HEIGHT as isize - max_height as isize;
                if drop_height <= 0 {
                    drop_frames += KABEGOE_PENALTY;
                } else if drop_height < 3 {
                    drop_frames += frame::FRAMES_TO_DROP_FAST[3];
                } else {
                    drop_frames += frame::FRAMES_TO_DROP_FAST[drop_height as usize];
                }
                drop_frames += frame::FRAMES_GROUNDING;
                drop_frames += frame::FRAMES_TO_DROP[diff_height as usize];
                drop_frames += frame::FRAMES_GROUNDING;
            }
        }

        drop_frames
    }
}

impl FieldHeight for CoreField {
    fn height(&self, x: usize) -> usize {
        CoreField::height(self, x)
    }
}

impl FieldIsEmpty for CoreField {
    fn is_empty(&self, x: usize, y: usize) -> bool {
        CoreField::is_empty(self, x, y)
    }
}

#[cfg(test)]
mod tests {
    use super::CoreField;
    use color::PuyoColor;
    use column_puyo_list::ColumnPuyoList;
    use decision::Decision;
    use field;
    use frame;

    #[test]
    fn test_constructor() {
        let cf = CoreField::new();

        for x in 1 .. field::WIDTH + 1 {
            for y in 1 .. field::HEIGHT + 1 {
                assert!(cf.is_empty(x, y));
                assert!(cf.is_color(x, y, PuyoColor::EMPTY));
                assert_eq!(PuyoColor::EMPTY, cf.color(x, y));
            }
        }

        for x in 1 .. field::WIDTH + 1 {
            assert_eq!(0, cf.height(x));
        }
    }

    #[test]
    fn test_from_str() {
        let cf = CoreField::from_str(concat!(
            "R.....",
            "RRRB.."));

        assert_eq!(PuyoColor::WALL, cf.color(0, 1));
        assert_eq!(PuyoColor::RED, cf.color(1, 1));
        assert_eq!(PuyoColor::RED, cf.color(2, 1));
        assert_eq!(PuyoColor::RED, cf.color(3, 1));
        assert_eq!(PuyoColor::BLUE, cf.color(4, 1));
        assert_eq!(PuyoColor::EMPTY, cf.color(5, 1));
        assert_eq!(PuyoColor::EMPTY, cf.color(6, 1));
        assert_eq!(PuyoColor::WALL, cf.color(7, 1));

        assert_eq!(2, cf.height(1));
        assert_eq!(1, cf.height(2));
        assert_eq!(1, cf.height(3));
        assert_eq!(1, cf.height(4));
        assert_eq!(0, cf.height(5));
        assert_eq!(0, cf.height(6));
    }

    #[test]
    fn test_drop_puyo_on() {
        let mut cf = CoreField::from_str(concat!(
            ".....R", // 13
            "OOOOOR", // 12
            "OOOOOO",
            "OOOOOO",
            "OOOOOO",
            "OOOOOO", // 8
            "OOOOOO",
            "OOOOOO",
            "OOOOOO",
            "OOOOOO", // 4
            "OOOOOO",
            "OOOOOO",
            "OOOOOO"));

        assert!(cf.drop_puyo_on_with_max_height(3, PuyoColor::BLUE, 13));
        assert!(cf.drop_puyo_on_with_max_height(4, PuyoColor::BLUE, 13));
        assert!(!cf.drop_puyo_on_with_max_height(4, PuyoColor::BLUE, 13));
        assert!(!cf.drop_puyo_on_with_max_height(6, PuyoColor::BLUE, 13));

        let expected = CoreField::from_str(concat!(
            "..BB.R", // 13
            "OOOOOR", // 12
            "OOOOOO",
            "OOOOOO",
            "OOOOOO",
            "OOOOOO", // 8
            "OOOOOO",
            "OOOOOO",
            "OOOOOO",
            "OOOOOO", // 4
            "OOOOOO",
            "OOOOOO",
            "OOOOOO"));

        assert_eq!(cf, expected);
    }

    #[test]
    fn test_drop_column_puyo_list_on() {
        let mut cf = CoreField::from_str(concat!(
            ".....R", // 13
            "OOOOOR", // 12
            "OOOOOO",
            "OOOOOO",
            "OOOOOO",
            "OOOOOO", // 8
            "OOOOOO",
            "OOOOOO",
            "OOOOOO",
            "OOOOOO", // 4
            "OOOOOO",
            "OOOOOO",
            "OOOOOO"));

        let mut cpl = ColumnPuyoList::new();
        assert!(cpl.add(3, PuyoColor::BLUE));
        assert!(cpl.add(4, PuyoColor::BLUE));
        assert!(cf.drop_column_puyo_list_with_max_height(&cpl, 13));

        let expected = CoreField::from_str(concat!(
            "..BB.R", // 13
            "OOOOOR", // 12
            "OOOOOO",
            "OOOOOO",
            "OOOOOO",
            "OOOOOO", // 8
            "OOOOOO",
            "OOOOOO",
            "OOOOOO",
            "OOOOOO", // 4
            "OOOOOO",
            "OOOOOO",
            "OOOOOO"));

        assert_eq!(cf, expected);
    }

    #[test]
    fn test_is_chigiri_decision_1() {
        let cf = CoreField::new();

        assert!(!cf.is_chigiri_decision(&Decision::new(3, 0)));
        assert!(!cf.is_chigiri_decision(&Decision::new(3, 1)));
        assert!(!cf.is_chigiri_decision(&Decision::new(3, 2)));
        assert!(!cf.is_chigiri_decision(&Decision::new(3, 3)));
    }

    #[test]
    fn test_is_chigiri_decision_2() {
        let cf = CoreField::from_str("..O...");

        assert!(!cf.is_chigiri_decision(&Decision::new(3, 0)));
        assert!(cf.is_chigiri_decision(&Decision::new(3, 1)));
        assert!(!cf.is_chigiri_decision(&Decision::new(3, 2)));
        assert!(cf.is_chigiri_decision(&Decision::new(3, 3)));
    }

    #[test]
    fn test_frames_to_drop_next_without_chigiri() {
        // TODO(mayah): We have to confirm this.
        let cf = CoreField::new();

        assert_eq!(frame::FRAMES_TO_DROP_FAST[field::HEIGHT] + frame::FRAMES_GROUNDING,
                   cf.frames_to_drop_next(&Decision::new(3, 0)));
        assert_eq!(frame::FRAMES_TO_DROP_FAST[field::HEIGHT] + frame::FRAMES_GROUNDING,
                   cf.frames_to_drop_next(&Decision::new(3, 1)));
        assert_eq!(frame::FRAMES_TO_DROP_FAST[field::HEIGHT - 1] + frame::FRAMES_GROUNDING,
                   cf.frames_to_drop_next(&Decision::new(3, 2)));
        assert_eq!(frame::FRAMES_TO_DROP_FAST[field::HEIGHT] + frame::FRAMES_GROUNDING,
                   cf.frames_to_drop_next(&Decision::new(3, 3)));
        assert_eq!(frame::FRAMES_TO_MOVE_HORIZONTALLY[2] + frame::FRAMES_TO_DROP_FAST[field::HEIGHT] + frame::FRAMES_GROUNDING,
                   cf.frames_to_drop_next(&Decision::new(1, 0)));
    }

    #[test]
    fn test_frames_to_drop_next_with_chigiri() {
        let cf = CoreField::from_str(concat!(
            "..O...",
            "..O...",
            "..O...",
            "..O...",
        ));

        let expected = frame::FRAMES_TO_DROP_FAST[field::HEIGHT - 4] + frame::FRAMES_GROUNDING +
            frame::FRAMES_TO_DROP[4] + frame::FRAMES_GROUNDING;
        assert_eq!(expected, cf.frames_to_drop_next(&Decision::new(3, 1)));
    }

    #[test]
    fn test_frames_to_drop_next_on_13th_row() {
        let cf = CoreField::from_str(concat!(
            "OO.OOO", // 12
            "OOOOOO",
            "OOOOOO",
            "OOOOOO",
            "OOOOOO", // 8
            "OOOOOO",
            "OOOOOO",
            "OOOOOO",
            "OOOOOO", // 4
            "OOOOOO",
            "OOOOOO",
            "OOOOOO",
        ));

        assert_eq!(11, cf.height(3));
        assert_eq!(12, cf.height(4));

        // We cannot put with Decision(4, 2).

        assert_eq!(6 + frame::FRAMES_TO_MOVE_HORIZONTALLY[1] + frame::FRAMES_GROUNDING,
                   cf.frames_to_drop_next(&Decision::new(4, 0)));
        assert_eq!(6 + frame::FRAMES_TO_MOVE_HORIZONTALLY[1] + frame::FRAMES_GROUNDING,
                   cf.frames_to_drop_next(&Decision::new(4, 1)));
        assert_eq!(6 + frame::FRAMES_TO_MOVE_HORIZONTALLY[1] + frame::FRAMES_GROUNDING + frame::FRAMES_TO_DROP[1] + frame::FRAMES_GROUNDING,
                   cf.frames_to_drop_next(&Decision::new(4, 3)));
    }
}
<|endoftext|>


<commit_before>use collections::String;

use std::mem;

use byteorder::{ByteOrder, BigEndian};

use serde;

use defs::*;
use error::*;

pub struct Deserializer<F: FnMut(&mut [u8]) -> Result<(), Error>> {
    input: F
}

struct SeqVisitor<'a, F: 'a + FnMut(&mut [u8]) -> Result<(), Error>> {
    de: &'a mut Deserializer<F>,
    count: usize
}

impl<'a, F: FnMut(&mut [u8]) -> Result<(), Error>> SeqVisitor<'a, F> {
    fn new(de: &'a mut Deserializer<F>, count: usize) -> SeqVisitor<'a, F> {
        SeqVisitor {
            de: de,
            count: count
        }
    }
}

impl<'a, F: FnMut(&mut [u8]) -> Result<(), Error>> serde::de::SeqVisitor for SeqVisitor<'a, F> {
    type Error = Error;

    fn visit<T>(&mut self) -> Result<Option<T>, Error>
        where T: serde::Deserialize {
        if self.count == 0 {
            return Ok(None);
        }

        self.count -= 1;

        Ok(Some(try!(T::deserialize(self.de))))
    }

    fn end(&mut self) -> Result<(), Error> {
        if self.count != 0 {
            Err(Error::simple(Reason::ExtraItems))
        } else {
            Ok(())
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.count, Some(self.count))
    }
}

impl<'a, F: FnMut(&mut [u8]) -> Result<(), Error>> serde::de::MapVisitor for SeqVisitor<'a, F> {
    type Error = Error;

    fn visit_key<K>(&mut self) -> Result<Option<K>, Error>
        where K: serde::Deserialize {
        serde::de::SeqVisitor::visit(self)
    }

    fn visit_value<V>(&mut self) -> Result<V, Error>
        where V: serde::Deserialize {
        try!(serde::de::SeqVisitor::visit(self)).ok_or(Error::simple(Reason::EndOfStream))
    }

    fn end(&mut self) -> Result<(), Error> {
        serde::de::SeqVisitor::end(self)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.count / 2, Some((self.count + 1) / 2))
    }
}

impl<F: FnMut(&mut [u8]) -> Result<(), Error>> Deserializer<F> {
    pub const fn new(input: F) -> Deserializer<F> {
        Deserializer {
            input: input
        }
    }

    fn input(&mut self, buf: &mut [u8]) -> Result<(), Error> {
        self.input.call_mut((buf,))
    }
}

impl<F: FnMut(&mut [u8]) -> Result<(), Error>> serde::Deserializer for Deserializer<F> {
    type Error = Error;

    fn deserialize<V>(&mut self, mut visitor: V) -> Result<V::Value, Error>
        where V: serde::de::Visitor {
        let mut buf = [0];
        try!(self.input(&mut buf));

        match buf[0] {
            v if POS_FIXINT.contains(v) => {
                visitor.visit_u8(v)
            }
            v if NEG_FIXINT.contains(v) => {
                visitor.visit_i8(unsafe {mem::transmute(v)})
            }
            v if FIXMAP.contains(v) => {
                let size = (buf[0] & !FIXMAP_MASK) as usize * 2;
                visitor.visit_map(SeqVisitor::new(self, size))
            }
            v if FIXARRAY.contains(v) => {
                let size = (buf[0] & !FIXARRAY_MASK) as usize;
                visitor.visit_seq(SeqVisitor::new(self, size))
            }
            v if FIXSTR.contains(v) => {
                let mut buf = vec![0; (buf[0] & !FIXSTR_MASK) as usize];
                try!(self.input(buf.as_mut_slice()));
                visitor.visit_string(
                    try!(String::from_utf8(buf)
                         .map_err(|e| Error::new(Reason::UTF8Error, format!("{}", e)))))
            }
            NIL => visitor.visit_none(),
            FALSE => visitor.visit_bool(false),
            TRUE => visitor.visit_bool(true),
            BIN8 => {
                let mut buf = [0];
                try!(self.input(&mut buf));
                let mut buf = vec![0; buf[0] as usize];
                try!(self.input(buf.as_mut_slice()));
                visitor.visit_byte_buf(buf)
            }
            BIN16 => {
                let mut buf = [0; U16_BYTES];
                try!(self.input(&mut buf));
                let mut buf = vec![0; BigEndian::read_u16(&buf) as usize];
                try!(self.input(buf.as_mut_slice()));
                visitor.visit_byte_buf(buf)
            }
            BIN32 => {
                let mut buf = [0; U32_BYTES];
                try!(self.input(&mut buf));
                let mut buf = vec![0; BigEndian::read_u32(&buf)as usize];
                try!(self.input(buf.as_mut_slice()));
                visitor.visit_byte_buf(buf)
            }
            EXT8 | EXT16 | EXT32 => {
                Err(Error::simple(Reason::BadType))
            }
            UINT8 => {
                let mut buf = [0];
                try!(self.input(&mut buf));
                visitor.visit_u8(buf[0])
            }
            UINT16 => {
                let mut buf = [0; U16_BYTES];
                try!(self.input(&mut buf));
                visitor.visit_u16(BigEndian::read_u16(&buf))
            }
            UINT32 => {
                let mut buf = [0; U32_BYTES];
                try!(self.input(&mut buf));
                visitor.visit_u32(BigEndian::read_u32(&buf))
            }
            UINT64 => {
                let mut buf = [0; U64_BYTES];
                try!(self.input(&mut buf));
                visitor.visit_u64(BigEndian::read_u64(&buf))
            }
            INT8 => {
                let mut buf = [0];
                try!(self.input(&mut buf));
                visitor.visit_i8(unsafe {mem::transmute(buf[0])})
            }
            INT16 => {
                let mut buf = [0; U16_BYTES];
                try!(self.input(&mut buf));
                visitor.visit_i16(BigEndian::read_i16(&buf))
            }
            INT32 => {
                let mut buf = [0; U32_BYTES];
                try!(self.input(&mut buf));
                visitor.visit_i32(BigEndian::read_i32(&buf))
            }
            INT64 => {
                let mut buf = [0; U64_BYTES];
                try!(self.input(&mut buf));
                visitor.visit_i64(BigEndian::read_i64(&buf))
            }
            FIXEXT1 | FIXEXT2 | FIXEXT4 | FIXEXT8 | FIXEXT16 => {
                Err(Error::simple(Reason::BadType))
            }
            STR8 => {
                let mut buf = [0];
                try!(self.input(&mut buf));
                let mut buf = vec![0; buf[0] as usize];
                try!(self.input(buf.as_mut_slice()));
                visitor.visit_string(
                    try!(String::from_utf8(buf)
                         .map_err(|e| Error::new(Reason::UTF8Error, format!("{}", e)))))
            }
            STR16 => {
                let mut buf = [0; U16_BYTES];
                try!(self.input(&mut buf));
                let mut buf = vec![0; BigEndian::read_u16(&buf) as usize];
                try!(self.input(buf.as_mut_slice()));
                visitor.visit_string(
                    try!(String::from_utf8(buf)
                         .map_err(|e| Error::new(Reason::UTF8Error, format!("{}", e)))))
            }
            STR32 => {
                let mut buf = [0; U32_BYTES];
                try!(self.input(&mut buf));
                let mut buf = vec![0; BigEndian::read_u32(&buf) as usize];
                try!(self.input(buf.as_mut_slice()));
                visitor.visit_string(
                    try!(String::from_utf8(buf)
                         .map_err(|e| Error::new(Reason::UTF8Error, format!("{}", e)))))
            }
            ARRAY16 => {
                let mut buf = [0; U16_BYTES];
                try!(self.input(&mut buf));
                let size = BigEndian::read_u16(&buf);
                visitor.visit_seq(SeqVisitor::new(self, size as usize))
            }
            ARRAY32 => {
                let mut buf = [0; U32_BYTES];
                try!(self.input(&mut buf));
                let size = BigEndian::read_u32(&buf);
                visitor.visit_seq(SeqVisitor::new(self, size as usize))
            }
            MAP16 => {
                let mut buf = [0; U16_BYTES];
                try!(self.input(&mut buf));
                let size = BigEndian::read_u16(&buf);
                visitor.visit_map(SeqVisitor::new(self, size as usize * 2))
            }
            MAP32 => {
                let mut buf = [0; U16_BYTES];
                try!(self.input(&mut buf));
                let size = BigEndian::read_u32(&buf);
                visitor.visit_map(SeqVisitor::new(self, size as usize * 2))
            }
            _ => {
                Err(Error::simple(Reason::BadType))
            }
        }
    }
}
<commit_msg>Fragment things a bit differently<commit_after>use collections::String;

use std::mem;

use byteorder::{ByteOrder, BigEndian};

use serde;

use defs::*;
use error::*;

pub struct Deserializer<F: FnMut(&mut [u8]) -> Result<(), Error>> {
    input: F
}

struct SeqVisitor<'a, F: 'a + FnMut(&mut [u8]) -> Result<(), Error>> {
    de: &'a mut Deserializer<F>,
    count: usize
}

impl<'a, F: FnMut(&mut [u8]) -> Result<(), Error>> SeqVisitor<'a, F> {
    fn new(de: &'a mut Deserializer<F>, count: usize) -> SeqVisitor<'a, F> {
        SeqVisitor {
            de: de,
            count: count
        }
    }
}

impl<'a, F: FnMut(&mut [u8]) -> Result<(), Error>> serde::de::SeqVisitor for SeqVisitor<'a, F> {
    type Error = Error;

    fn visit<T>(&mut self) -> Result<Option<T>, Error>
        where T: serde::Deserialize {
        if self.count == 0 {
            return Ok(None);
        }

        self.count -= 1;

        Ok(Some(try!(T::deserialize(self.de))))
    }

    fn end(&mut self) -> Result<(), Error> {
        if self.count != 0 {
            Err(Error::simple(Reason::ExtraItems))
        } else {
            Ok(())
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.count, Some(self.count))
    }
}

impl<'a, F: FnMut(&mut [u8]) -> Result<(), Error>> serde::de::MapVisitor for SeqVisitor<'a, F> {
    type Error = Error;

    fn visit_key<K>(&mut self) -> Result<Option<K>, Error>
        where K: serde::Deserialize {
        serde::de::SeqVisitor::visit(self)
    }

    fn visit_value<V>(&mut self) -> Result<V, Error>
        where V: serde::Deserialize {
        try!(serde::de::SeqVisitor::visit(self)).ok_or(Error::simple(Reason::EndOfStream))
    }

    fn end(&mut self) -> Result<(), Error> {
        serde::de::SeqVisitor::end(self)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.count / 2, Some((self.count + 1) / 2))
    }
}

impl<F: FnMut(&mut [u8]) -> Result<(), Error>> serde::Deserializer for Deserializer<F> {
    type Error = Error;

    fn deserialize<V>(&mut self, visitor: V) -> Result<V::Value, Error>
        where V: serde::de::Visitor {
        let mut buf = [0];
        try!(self.input(&mut buf));
        self.parse_as(visitor, buf[0])
    }
}

impl<F: FnMut(&mut [u8]) -> Result<(), Error>> Deserializer<F> {
    pub const fn new(input: F) -> Deserializer<F> {
        Deserializer {
            input: input
        }
    }

    fn input(&mut self, buf: &mut [u8]) -> Result<(), Error> {
        self.input.call_mut((buf,))
    }

    fn parse_as<V>(&mut self, mut visitor: V, ty: u8) -> Result<V::Value, Error>
        where V: serde::de::Visitor {
        match ty {
            v if POS_FIXINT.contains(v) => {
                visitor.visit_u8(v)
            }
            v if NEG_FIXINT.contains(v) => {
                visitor.visit_i8(unsafe {mem::transmute(v)})
            }
            v if FIXMAP.contains(v) => {
                let size = (v & !FIXMAP_MASK) as usize * 2;
                visitor.visit_map(SeqVisitor::new(self, size))
            }
            v if FIXARRAY.contains(v) => {
                let size = (v & !FIXARRAY_MASK) as usize;
                visitor.visit_seq(SeqVisitor::new(self, size))
            }
            v if FIXSTR.contains(v) => {
                let mut buf = vec![0; (v & !FIXSTR_MASK) as usize];
                try!(self.input(buf.as_mut_slice()));
                visitor.visit_string(
                    try!(String::from_utf8(buf)
                         .map_err(|e| Error::new(Reason::UTF8Error, format!("{}", e)))))
            }
            NIL => visitor.visit_none(),
            FALSE => visitor.visit_bool(false),
            TRUE => visitor.visit_bool(true),
            BIN8 => {
                let mut buf = [0];
                try!(self.input(&mut buf));
                let mut buf = vec![0; buf[0] as usize];
                try!(self.input(buf.as_mut_slice()));
                visitor.visit_byte_buf(buf)
            }
            BIN16 => {
                let mut buf = [0; U16_BYTES];
                try!(self.input(&mut buf));
                let mut buf = vec![0; BigEndian::read_u16(&buf) as usize];
                try!(self.input(buf.as_mut_slice()));
                visitor.visit_byte_buf(buf)
            }
            BIN32 => {
                let mut buf = [0; U32_BYTES];
                try!(self.input(&mut buf));
                let mut buf = vec![0; BigEndian::read_u32(&buf)as usize];
                try!(self.input(buf.as_mut_slice()));
                visitor.visit_byte_buf(buf)
            }
            EXT8 | EXT16 | EXT32 => {
                Err(Error::simple(Reason::BadType))
            }
            UINT8 => {
                let mut buf = [0];
                try!(self.input(&mut buf));
                visitor.visit_u8(buf[0])
            }
            UINT16 => {
                let mut buf = [0; U16_BYTES];
                try!(self.input(&mut buf));
                visitor.visit_u16(BigEndian::read_u16(&buf))
            }
            UINT32 => {
                let mut buf = [0; U32_BYTES];
                try!(self.input(&mut buf));
                visitor.visit_u32(BigEndian::read_u32(&buf))
            }
            UINT64 => {
                let mut buf = [0; U64_BYTES];
                try!(self.input(&mut buf));
                visitor.visit_u64(BigEndian::read_u64(&buf))
            }
            INT8 => {
                let mut buf = [0];
                try!(self.input(&mut buf));
                visitor.visit_i8(unsafe {mem::transmute(buf[0])})
            }
            INT16 => {
                let mut buf = [0; U16_BYTES];
                try!(self.input(&mut buf));
                visitor.visit_i16(BigEndian::read_i16(&buf))
            }
            INT32 => {
                let mut buf = [0; U32_BYTES];
                try!(self.input(&mut buf));
                visitor.visit_i32(BigEndian::read_i32(&buf))
            }
            INT64 => {
                let mut buf = [0; U64_BYTES];
                try!(self.input(&mut buf));
                visitor.visit_i64(BigEndian::read_i64(&buf))
            }
            FIXEXT1 | FIXEXT2 | FIXEXT4 | FIXEXT8 | FIXEXT16 => {
                Err(Error::simple(Reason::BadType))
            }
            STR8 => {
                let mut buf = [0];
                try!(self.input(&mut buf));
                let mut buf = vec![0; buf[0] as usize];
                try!(self.input(buf.as_mut_slice()));
                visitor.visit_string(
                    try!(String::from_utf8(buf)
                         .map_err(|e| Error::new(Reason::UTF8Error, format!("{}", e)))))
            }
            STR16 => {
                let mut buf = [0; U16_BYTES];
                try!(self.input(&mut buf));
                let mut buf = vec![0; BigEndian::read_u16(&buf) as usize];
                try!(self.input(buf.as_mut_slice()));
                visitor.visit_string(
                    try!(String::from_utf8(buf)
                         .map_err(|e| Error::new(Reason::UTF8Error, format!("{}", e)))))
            }
            STR32 => {
                let mut buf = [0; U32_BYTES];
                try!(self.input(&mut buf));
                let mut buf = vec![0; BigEndian::read_u32(&buf) as usize];
                try!(self.input(buf.as_mut_slice()));
                visitor.visit_string(
                    try!(String::from_utf8(buf)
                         .map_err(|e| Error::new(Reason::UTF8Error, format!("{}", e)))))
            }
            ARRAY16 => {
                let mut buf = [0; U16_BYTES];
                try!(self.input(&mut buf));
                let size = BigEndian::read_u16(&buf);
                visitor.visit_seq(SeqVisitor::new(self, size as usize))
            }
            ARRAY32 => {
                let mut buf = [0; U32_BYTES];
                try!(self.input(&mut buf));
                let size = BigEndian::read_u32(&buf);
                visitor.visit_seq(SeqVisitor::new(self, size as usize))
            }
            MAP16 => {
                let mut buf = [0; U16_BYTES];
                try!(self.input(&mut buf));
                let size = BigEndian::read_u16(&buf);
                visitor.visit_map(SeqVisitor::new(self, size as usize * 2))
            }
            MAP32 => {
                let mut buf = [0; U16_BYTES];
                try!(self.input(&mut buf));
                let size = BigEndian::read_u32(&buf);
                visitor.visit_map(SeqVisitor::new(self, size as usize * 2))
            }
            _ => {
                Err(Error::simple(Reason::BadType))
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright:: Copyright (c) 2015-2016 The Habitat Maintainers
//
// The terms of the Evaluation Agreement (Habitat) between Chef Software Inc.
// and the party accessing this file ("Licensee") apply to Licensee's use of
// the Software until such time that the Software is made available under an
// open source license such as the Apache 2.0 License.

use std::path::PathBuf;

pub const ROOT_PATH: &'static str = "/opt/bldr";
pub const PACKAGE_HOME: &'static str = "/opt/bldr/pkgs";
pub const SERVICE_HOME: &'static str = "/opt/bldr/svc";
pub const PACKAGE_CACHE: &'static str = "/opt/bldr/cache/pkgs";
/// The default path where source artifacts are downloaded, extracted, & compiled
pub const CACHE_SRC_PATH: &'static str = "/opt/bldr/cache/src";
pub const GPG_CACHE: &'static str = "/opt/bldr/cache/gpg";
pub const KEY_CACHE: &'static str = "/opt/bldr/cache/keys";

pub fn service_path(service_name: &str) -> PathBuf {
    PathBuf::from(SERVICE_HOME).join(service_name)
}
<commit_msg>Use `HAB_CACHE_ARTIFACT_PATH` for download path of package artifacts.<commit_after>// Copyright:: Copyright (c) 2015-2016 The Habitat Maintainers
//
// The terms of the Evaluation Agreement (Habitat) between Chef Software Inc.
// and the party accessing this file ("Licensee") apply to Licensee's use of
// the Software until such time that the Software is made available under an
// open source license such as the Apache 2.0 License.

use std::path::PathBuf;

pub const ROOT_PATH: &'static str = "/opt/bldr";
pub const PACKAGE_HOME: &'static str = "/opt/bldr/pkgs";
pub const SERVICE_HOME: &'static str = "/opt/bldr/svc";
/// The default download root path for package artifacts, used on package installation
pub const CACHE_ARTIFACT_PATH: &'static str = "/opt/bldr/cache/artifacts";
/// The default path where source artifacts are downloaded, extracted, & compiled
pub const CACHE_SRC_PATH: &'static str = "/opt/bldr/cache/src";
pub const GPG_CACHE: &'static str = "/opt/bldr/cache/gpg";
pub const KEY_CACHE: &'static str = "/opt/bldr/cache/keys";

pub fn service_path(service_name: &str) -> PathBuf {
    PathBuf::from(SERVICE_HOME).join(service_name)
}
<|endoftext|>


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

type Cell = u8;

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

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

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

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

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

    pub fn decrement(&mut self) {
        self.cells[self.data_pointer] = self.cells[self.data_pointer]
            .checked_sub(1)
            .unwrap_or(Cell::max_value());
    }

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

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

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

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_new() {
        let vm = VM::new();
        assert!(vm.cells[0] == 0);
        assert!(vm.cells[30_000 - 1] == 0);
        assert!(vm.cells[0] == 0);
    }

    #[test]
    fn test_increment() {
        let mut vm = VM::new();
        vm.increment();
        assert!(vm.cells[0] == 1);
    }

    #[test]
    fn test_decrement() {
        const STARTING_VALUE: u8 = 2;

        let mut vm = VM::new();
        vm.cells[0] = STARTING_VALUE;
        vm.decrement();
        assert!(vm.cells[0] == STARTING_VALUE - 1);
    }
}
<commit_msg>Add unit test for VM.right_shift()<commit_after>use std::io;
use std::io::Read;
use command::Command;

type Cell = u8;

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

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

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

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

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

    pub fn decrement(&mut self) {
        self.cells[self.data_pointer] = self.cells[self.data_pointer]
            .checked_sub(1)
            .unwrap_or(Cell::max_value());
    }

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

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

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

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_new() {
        let vm = VM::new();
        assert!(vm.cells[0] == 0);
        assert!(vm.cells[30_000 - 1] == 0);
        assert!(vm.cells[0] == 0);
    }

    #[test]
    fn test_increment() {
        let mut vm = VM::new();
        vm.increment();
        assert!(vm.cells[0] == 1);
    }

    #[test]
    fn test_decrement() {
        const STARTING_VALUE: u8 = 2;

        let mut vm = VM::new();
        vm.cells[0] = STARTING_VALUE;
        vm.decrement();
        assert!(vm.cells[0] == STARTING_VALUE - 1);
    }

    #[test]
    fn test_right_shift() {
        let mut vm = VM::new();
        vm.right_shift();
        assert!(vm.data_pointer == 1);
    }
}
<|endoftext|>


<commit_before>use std::kinds::marker::NoCopy;
use std::slice::raw::buf_as_slice;
use std::str::raw::c_str_to_static_slice;
use libc::{c_char, c_uint, c_void, ptrdiff_t, size_t};
use libc;

use {encode, Encode};

pub struct Sel {
	ptr: *const c_void,
}

pub struct Ivar {
	nocopy: NoCopy,
}

pub struct Method {
	nocopy: NoCopy,
}

pub struct Class {
	nocopy: NoCopy,
}

pub struct Object {
	nocopy: NoCopy,
}

pub type Imp = extern fn(*mut Object, Sel, ...) -> *mut Object;

#[link(name = "Foundation", kind = "framework")]
extern {
	pub fn sel_registerName(name: *const c_char) -> Sel;
	pub fn sel_getName(sel: Sel) -> *const c_char;

	pub fn objc_getClass(name: *const c_char) -> *const Class;
	pub fn class_getName(cls: *const Class) -> *const c_char;
	pub fn class_getInstanceSize(cls: *const Class) -> size_t;
	pub fn class_getInstanceMethod(cls: *const Class, sel: Sel) -> *const Method;
	pub fn class_getInstanceVariable(cls: *const Class, name: *const c_char) -> *const Ivar;
	pub fn class_copyIvarList(cls: *const Class, outCount: *mut c_uint) -> *mut *const Ivar;
	pub fn class_addMethod(cls: *mut Class, name: Sel, imp: Imp, types: *const c_char) -> bool;
	pub fn class_addIvar(cls: *mut Class, name: *const c_char, size: size_t, alignment: u8, types: *const c_char) -> bool;

	pub fn objc_allocateClassPair(superclass: *const Class, name: *const c_char, extraBytes: size_t) -> *mut Class;
	pub fn objc_disposeClassPair(cls: *mut Class);
	pub fn objc_registerClassPair(cls: *mut Class);

	pub fn object_getClass(obj: *const Object) -> *const Class;

	pub fn ivar_getName(ivar: *const Ivar) -> *const c_char;
	pub fn ivar_getOffset(ivar: *const Ivar) -> ptrdiff_t;
	pub fn ivar_getTypeEncoding(ivar: *const Ivar) -> *const c_char;

	pub fn objc_msgSend(obj: *mut Object, op: Sel, ...) -> *mut Object;

	pub fn method_getName(method: *const Method) -> Sel;
	pub fn method_getImplementation(method: *const Method) -> Imp;
	pub fn method_getTypeEncoding(method: *const Method) -> *const c_char;
	pub fn method_getNumberOfArguments(method: *const Method) -> c_uint;
	pub fn method_setImplementation(method: *mut Method, imp: Imp) -> Imp;
	pub fn method_exchangeImplementations(m1: *mut Method, m2: *mut Method);
}

impl Sel {
	pub fn register(name: &str) -> Sel {
		name.with_c_str(|name| unsafe {
			sel_registerName(name)
		})
	}

	pub fn name(&self) -> &str {
		unsafe {
			let name = sel_getName(*self);
			c_str_to_static_slice(name)
		}
	}
}

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

impl Eq for Sel { }

impl Clone for Sel {
	fn clone(&self) -> Sel { *self }
}

impl Ivar {
	pub fn name(&self) -> &str {
		unsafe {
			let name = ivar_getName(self);
			c_str_to_static_slice(name)
		}
	}

	pub fn offset(&self) -> int {
		let offset = unsafe {
			ivar_getOffset(self)
		};
		offset as int
	}

	pub fn type_encoding(&self) -> &str {
		unsafe {
			let encoding = ivar_getTypeEncoding(self);
			c_str_to_static_slice(encoding)
		}
	}
}

impl Method {
	pub fn name(&self) -> Sel {
		unsafe {
			method_getName(self)
		}
	}

	pub fn type_encoding(&self) -> &str {
		unsafe {
			let encoding = method_getTypeEncoding(self);
			c_str_to_static_slice(encoding)
		}
	}

	pub fn arguments(&self) -> uint {
		unsafe {
			method_getNumberOfArguments(self) as uint
		}
	}

	pub fn implementation(&self) -> Imp {
		unsafe {
			method_getImplementation(self)
		}
	}

	pub unsafe fn set_implementation(&mut self, imp: Imp) -> Imp {
		method_setImplementation(self, imp)
	}

	pub unsafe fn exchange_implementation(&mut self, other: &mut Method) {
		method_exchangeImplementations(self, other);
	}
}

impl Class {
	pub fn get(name: &str) -> Option<&'static Class> {
		let cls = name.with_c_str(|name| unsafe {
			objc_getClass(name)
		});
		if cls.is_null() {
			None
		} else {
			Some(unsafe { &*cls })
		}
	}

	pub fn name(&self) -> &str {
		unsafe {
			let name = class_getName(self);
			c_str_to_static_slice(name)
		}
	}

	pub fn instance_size(&self) -> uint {
		unsafe {
			class_getInstanceSize(self) as uint
		}
	}

	pub fn instance_method(&self, sel: Sel) -> Option<&Method> {
		let method = unsafe {
			class_getInstanceMethod(self, sel)
		};
		if method.is_null() {
			None
		} else {
			Some(unsafe { &*method })
		}
	}

	pub fn instance_variable(&self, name: &str) -> Option<&Ivar> {
		let ivar = name.with_c_str(|name| unsafe {
			class_getInstanceVariable(self, name)
		});
		if ivar.is_null() {
			None
		} else {
			Some(unsafe { &*ivar })
		}
	}

	pub fn instance_variables(&self) -> Vec<&Ivar> {
		unsafe {
			let mut count: c_uint = 0;
			let ivars = class_copyIvarList(self, &mut count);
			let vec = buf_as_slice(ivars as *const _, count as uint, |ivars| {
				ivars.to_vec()
			});
			libc::free(ivars as *mut c_void);
			vec
		}
	}
}

impl PartialEq for Class {
	fn eq(&self, other: &Class) -> bool {
		self as *const Class == other as *const Class
	}
}

impl Eq for Class { }

impl Object {
	pub fn class(&self) -> &'static Class {
		unsafe {
			&*object_getClass(self)
		}
	}

	pub unsafe fn get_ivar<T: Encode>(&self, name: &str) -> &T {
		let cls = self.class();
		let ptr = match cls.instance_variable(name) {
			Some(ivar) => {
				assert!(ivar.type_encoding() == encode::<T>());
				let offset = ivar.offset();
				let self_ptr = self as *const Object;
				(self_ptr as *const u8).offset(offset) as *const T
			}
			None => fail!("Ivar {} not found on class {}", name, cls.name()),
		};
		&*ptr
	}

	pub unsafe fn get_mut_ivar<T: Encode>(&mut self, name: &str) -> &mut T {
		let cls = self.class();
		let ptr = match cls.instance_variable(name) {
			Some(ivar) => {
				assert!(ivar.type_encoding() == encode::<T>());
				let offset = ivar.offset();
				let self_ptr = self as *mut Object;
				(self_ptr as *mut u8).offset(offset) as *mut T
			}
			None => fail!("Ivar {} not found on class {}", name, cls.name()),
		};
		&mut *ptr
	}

	pub unsafe fn set_ivar<T: Encode>(&mut self, name: &str, value: T) {
		*self.get_mut_ivar::<T>(name) = value;
	}
}

pub trait Message { }

impl Message for Object { }

impl Message for Class { }

pub trait ToMessage {
	fn as_ptr(&self) -> *mut Object;

	fn is_nil(&self) -> bool {
		self.as_ptr().is_null()
	}
}

impl<T: Message> ToMessage for *mut T {
	fn as_ptr(&self) -> *mut Object {
		*self as *mut Object
	}
}

impl<'a, T: Message> ToMessage for &'a T {
	fn as_ptr(&self) -> *mut Object {
		(*self as *const T as *mut T).as_ptr()
	}
}
<commit_msg>Added tests for runtime.<commit_after>use std::kinds::marker::NoCopy;
use std::slice::raw::buf_as_slice;
use std::str::raw::c_str_to_static_slice;
use libc::{c_char, c_uint, c_void, ptrdiff_t, size_t};
use libc;

use {encode, Encode};

pub struct Sel {
	ptr: *const c_void,
}

pub struct Ivar {
	nocopy: NoCopy,
}

pub struct Method {
	nocopy: NoCopy,
}

pub struct Class {
	nocopy: NoCopy,
}

pub struct Object {
	nocopy: NoCopy,
}

pub type Imp = extern fn(*mut Object, Sel, ...) -> *mut Object;

#[link(name = "Foundation", kind = "framework")]
extern {
	pub fn sel_registerName(name: *const c_char) -> Sel;
	pub fn sel_getName(sel: Sel) -> *const c_char;

	pub fn objc_getClass(name: *const c_char) -> *const Class;
	pub fn class_getName(cls: *const Class) -> *const c_char;
	pub fn class_getInstanceSize(cls: *const Class) -> size_t;
	pub fn class_getInstanceMethod(cls: *const Class, sel: Sel) -> *const Method;
	pub fn class_getInstanceVariable(cls: *const Class, name: *const c_char) -> *const Ivar;
	pub fn class_copyIvarList(cls: *const Class, outCount: *mut c_uint) -> *mut *const Ivar;
	pub fn class_addMethod(cls: *mut Class, name: Sel, imp: Imp, types: *const c_char) -> bool;
	pub fn class_addIvar(cls: *mut Class, name: *const c_char, size: size_t, alignment: u8, types: *const c_char) -> bool;

	pub fn objc_allocateClassPair(superclass: *const Class, name: *const c_char, extraBytes: size_t) -> *mut Class;
	pub fn objc_disposeClassPair(cls: *mut Class);
	pub fn objc_registerClassPair(cls: *mut Class);

	pub fn object_getClass(obj: *const Object) -> *const Class;

	pub fn ivar_getName(ivar: *const Ivar) -> *const c_char;
	pub fn ivar_getOffset(ivar: *const Ivar) -> ptrdiff_t;
	pub fn ivar_getTypeEncoding(ivar: *const Ivar) -> *const c_char;

	pub fn objc_msgSend(obj: *mut Object, op: Sel, ...) -> *mut Object;

	pub fn method_getName(method: *const Method) -> Sel;
	pub fn method_getImplementation(method: *const Method) -> Imp;
	pub fn method_getTypeEncoding(method: *const Method) -> *const c_char;
	pub fn method_getNumberOfArguments(method: *const Method) -> c_uint;
	pub fn method_setImplementation(method: *mut Method, imp: Imp) -> Imp;
	pub fn method_exchangeImplementations(m1: *mut Method, m2: *mut Method);
}

impl Sel {
	pub fn register(name: &str) -> Sel {
		name.with_c_str(|name| unsafe {
			sel_registerName(name)
		})
	}

	pub fn name(&self) -> &str {
		unsafe {
			let name = sel_getName(*self);
			c_str_to_static_slice(name)
		}
	}
}

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

impl Eq for Sel { }

impl Clone for Sel {
	fn clone(&self) -> Sel { *self }
}

impl Ivar {
	pub fn name(&self) -> &str {
		unsafe {
			let name = ivar_getName(self);
			c_str_to_static_slice(name)
		}
	}

	pub fn offset(&self) -> int {
		let offset = unsafe {
			ivar_getOffset(self)
		};
		offset as int
	}

	pub fn type_encoding(&self) -> &str {
		unsafe {
			let encoding = ivar_getTypeEncoding(self);
			c_str_to_static_slice(encoding)
		}
	}
}

impl Method {
	pub fn name(&self) -> Sel {
		unsafe {
			method_getName(self)
		}
	}

	pub fn type_encoding(&self) -> &str {
		unsafe {
			let encoding = method_getTypeEncoding(self);
			c_str_to_static_slice(encoding)
		}
	}

	pub fn arguments(&self) -> uint {
		unsafe {
			method_getNumberOfArguments(self) as uint
		}
	}

	pub fn implementation(&self) -> Imp {
		unsafe {
			method_getImplementation(self)
		}
	}

	pub unsafe fn set_implementation(&mut self, imp: Imp) -> Imp {
		method_setImplementation(self, imp)
	}

	pub unsafe fn exchange_implementation(&mut self, other: &mut Method) {
		method_exchangeImplementations(self, other);
	}
}

impl Class {
	pub fn get(name: &str) -> Option<&'static Class> {
		let cls = name.with_c_str(|name| unsafe {
			objc_getClass(name)
		});
		if cls.is_null() {
			None
		} else {
			Some(unsafe { &*cls })
		}
	}

	pub fn name(&self) -> &str {
		unsafe {
			let name = class_getName(self);
			c_str_to_static_slice(name)
		}
	}

	pub fn instance_size(&self) -> uint {
		unsafe {
			class_getInstanceSize(self) as uint
		}
	}

	pub fn instance_method(&self, sel: Sel) -> Option<&Method> {
		let method = unsafe {
			class_getInstanceMethod(self, sel)
		};
		if method.is_null() {
			None
		} else {
			Some(unsafe { &*method })
		}
	}

	pub fn instance_variable(&self, name: &str) -> Option<&Ivar> {
		let ivar = name.with_c_str(|name| unsafe {
			class_getInstanceVariable(self, name)
		});
		if ivar.is_null() {
			None
		} else {
			Some(unsafe { &*ivar })
		}
	}

	pub fn instance_variables(&self) -> Vec<&Ivar> {
		unsafe {
			let mut count: c_uint = 0;
			let ivars = class_copyIvarList(self, &mut count);
			let vec = buf_as_slice(ivars as *const _, count as uint, |ivars| {
				ivars.to_vec()
			});
			libc::free(ivars as *mut c_void);
			vec
		}
	}
}

impl PartialEq for Class {
	fn eq(&self, other: &Class) -> bool {
		self as *const Class == other as *const Class
	}
}

impl Eq for Class { }

impl Object {
	pub fn class(&self) -> &'static Class {
		unsafe {
			&*object_getClass(self)
		}
	}

	pub unsafe fn get_ivar<T: Encode>(&self, name: &str) -> &T {
		let cls = self.class();
		let ptr = match cls.instance_variable(name) {
			Some(ivar) => {
				assert!(ivar.type_encoding() == encode::<T>());
				let offset = ivar.offset();
				let self_ptr = self as *const Object;
				(self_ptr as *const u8).offset(offset) as *const T
			}
			None => fail!("Ivar {} not found on class {}", name, cls.name()),
		};
		&*ptr
	}

	pub unsafe fn get_mut_ivar<T: Encode>(&mut self, name: &str) -> &mut T {
		let cls = self.class();
		let ptr = match cls.instance_variable(name) {
			Some(ivar) => {
				assert!(ivar.type_encoding() == encode::<T>());
				let offset = ivar.offset();
				let self_ptr = self as *mut Object;
				(self_ptr as *mut u8).offset(offset) as *mut T
			}
			None => fail!("Ivar {} not found on class {}", name, cls.name()),
		};
		&mut *ptr
	}

	pub unsafe fn set_ivar<T: Encode>(&mut self, name: &str, value: T) {
		*self.get_mut_ivar::<T>(name) = value;
	}
}

pub trait Message { }

impl Message for Object { }

impl Message for Class { }

pub trait ToMessage {
	fn as_ptr(&self) -> *mut Object;

	fn is_nil(&self) -> bool {
		self.as_ptr().is_null()
	}
}

impl<T: Message> ToMessage for *mut T {
	fn as_ptr(&self) -> *mut Object {
		*self as *mut Object
	}
}

impl<'a, T: Message> ToMessage for &'a T {
	fn as_ptr(&self) -> *mut Object {
		(*self as *const T as *mut T).as_ptr()
	}
}

#[cfg(test)]
mod tests {
	use std::mem;
	use super::{Class, Sel};

	#[test]
	fn test_ivar() {
		let cls = Class::get("NSObject").unwrap();
		let ivar = cls.instance_variable("isa").unwrap();
		assert!(ivar.name() == "isa");
		assert!(ivar.type_encoding() == "#");
		assert!(ivar.offset() == 0);
	}

	#[test]
	fn test_method() {
		let cls = Class::get("NSObject").unwrap();
		let sel = Sel::register("description");
		let method = cls.instance_method(sel).unwrap();
		assert!(method.name().name() == "description");
		assert!(method.type_encoding() != "");
		assert!(method.arguments() == 2);
	}

	#[test]
	fn test_class() {
		let cls = Class::get("NSObject").unwrap();
		assert!(cls.name() == "NSObject");
		assert!(cls.instance_size() == mem::size_of::<*const Class>());
	}

	#[test]
	fn test_object() {
		let cls = Class::get("NSObject").unwrap();
		let obj = unsafe {
			let obj = msg_send![cls alloc];
			let obj = msg_send![obj init];
			&*obj
		};
		assert!(obj.class() == cls);
		unsafe {
			msg_send![obj release];
		}
	}
}
<|endoftext|>