<commit_before>//! The `fix_checksum` crate provides functions that
//! validate FIX message checksum and generate checksum of FIX message.
//!
//! Please note that due to visibility reasons `|` delimiter used in all examples.
//! Real delimiter is a symbol with code `0x01` therefore a checksum of messages with
//! such delimiter will be different.
//!
//! # Examples
//!
//! ```
//! assert_eq!(false, fix_checksum::validate(""));
//!
//! let outbound_message = "8=FIX.4.2|9=73|35=0|49=BRKR|56=INVMGR|34=235|52=19980604-07:58:28|112=19980604-07:58:28|";
//! assert_eq!("196", fix_checksum::generate(outbound_message));
//! ```

fn checksum(message: &str) -> u32 {
  let mut cs: u32 = 0;
  for b in message.as_bytes() {
    cs += *b as u32;
  }
  cs %= 256;
  return cs;
}

/// This function validates FIX message checksum
///
/// # Examples
///
/// ```
/// use fix_checksum::validate;
///
/// // empty message
/// assert_eq!(false, validate(""));
///
/// // no tail
/// let inbound_message = "8=FIX.4.29=7335=049=BRKR56=INVMGR34=23552=19980604-07:58:28112=19980604-07:58:28";
/// assert_eq!(false, validate(inbound_message));
///
/// // invalid checksum
/// let inbound_message = "8=FIX.4.29=7335=049=BRKR56=INVMGR34=23552=19980604-07:58:28112=19980604-07:58:2810=231";
/// assert_eq!(false, validate(inbound_message));
///
/// // invalid checksum format
/// let inbound_message = "8=FIX.4.29=7335=049=BRKR56=INVMGR34=23552=19980604-07:58:28112=19980604-07:58:2810=2ZZ";
/// assert_eq!(false, validate(inbound_message));
///
/// let inbound_message = "8=FIX.4.29=7335=049=BRKR56=INVMGR34=23552=19980604-07:58:28112=19980604-07:58:2810=236";
/// assert_eq!(true, validate(inbound_message));
/// ```
pub fn validate(inbound_message: &str) -> bool {
  if inbound_message.is_empty() { return false; }

  let tail_start = inbound_message.find("\x01\x31\x30\x3D");
  if tail_start.is_none() { return false; }

  let split_index = tail_start.unwrap() + 1;
  let (checksum_index_start, checksum_index_end) = (split_index + 3, split_index + 6);

  let checksum_to_be = checksum(&inbound_message[..split_index]);
  let checksum_as_is = inbound_message[checksum_index_start..checksum_index_end].parse::<u32>();

  if checksum_as_is.is_err() { return false; }

  return checksum_as_is.unwrap() == checksum_to_be;
}

/// This function generates checksum of FIX message
///
/// # Examples
///
/// ```
/// use fix_checksum::generate;
///
/// let outbound_message = "8=FIX.4.2|9=73|35=0|49=BRKR|56=INVMGR|34=235|52=19980604-07:58:28|112=19980604-07:58:28|";
/// assert_eq!("196", generate(outbound_message));
/// ```
pub fn generate(outbound_message: &str) -> String {
  return checksum(outbound_message).to_string();
}

#[test]
fn it_should_calculate_fix_message_checksum() {
  let message = "8=FIX.4.29=7335=049=BRKR56=INVMGR34=23552=19980604-07:58:28112=19980604-07:58:28";
  assert_eq!(236, checksum(message));
}

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

  #[test]
  fn it_should_validate_fix_message_checksum() {
    // empty message
    assert_eq!(false, validate(""));

    // no tail
    let inbound_message = "8=FIX.4.29=7335=049=BRKR56=INVMGR34=23552=19980604-07:58:28112=19980604-07:58:28";
    assert_eq!(false, validate(inbound_message));

    // invalid checksum
    let inbound_message = "8=FIX.4.29=7335=049=BRKR56=INVMGR34=23552=19980604-07:58:28112=19980604-07:58:2810=231";
    assert_eq!(false, validate(inbound_message));

    // invalid checksum format
    let inbound_message = "8=FIX.4.29=7335=049=BRKR56=INVMGR34=23552=19980604-07:58:28112=19980604-07:58:2810=2ZZ";
    assert_eq!(false, validate(inbound_message));

    let inbound_message = "8=FIX.4.29=7335=049=BRKR56=INVMGR34=23552=19980604-07:58:28112=19980604-07:58:2810=236";
    assert_eq!(true, validate(inbound_message));
  }

  #[test]
  fn it_should_generate_fix_message_checksum() {
    let outbound_message = "8=FIX.4.29=7335=049=BRKR56=INVMGR34=23552=19980604-07:58:28112=19980604-07:58:28";
    assert_eq!("236", generate(outbound_message));
  }
}
<commit_msg>Improvement: Added tests to general documentation<commit_after>//! The `fix_checksum` crate provides functions that
//! validate FIX message checksum and generate checksum of FIX message.
//!
//! Please note that due to visibility reasons `|` delimiter used in all examples.
//! Real delimiter is a symbol with code `0x01` therefore a checksum of messages with
//! such delimiter will be different.
//!
//! # Examples
//!
//! ```
//! // empty message
//! assert_eq!(false, fix_checksum::validate(""));
//!
//! // no tail
//! let inbound_message = "8=FIX.4.29=7335=049=BRKR56=INVMGR34=23552=19980604-07:58:28112=19980604-07:58:28";
//! assert_eq!(false, fix_checksum::validate(inbound_message));
//!
//! // invalid checksum
//! let inbound_message = "8=FIX.4.29=7335=049=BRKR56=INVMGR34=23552=19980604-07:58:28112=19980604-07:58:2810=231";
//! assert_eq!(false, fix_checksum::validate(inbound_message));
//!
//! // invalid checksum format
//! let inbound_message = "8=FIX.4.29=7335=049=BRKR56=INVMGR34=23552=19980604-07:58:28112=19980604-07:58:2810=2ZZ";
//! assert_eq!(false, fix_checksum::validate(inbound_message));
//!
//! let inbound_message = "8=FIX.4.29=7335=049=BRKR56=INVMGR34=23552=19980604-07:58:28112=19980604-07:58:2810=236";
//! assert_eq!(true, fix_checksum::validate(inbound_message));
//!
//! let outbound_message = "8=FIX.4.2|9=73|35=0|49=BRKR|56=INVMGR|34=235|52=19980604-07:58:28|112=19980604-07:58:28|";
//! assert_eq!("196", fix_checksum::generate(outbound_message));
//! ```

fn checksum(message: &str) -> u32 {
  let mut cs: u32 = 0;
  for b in message.as_bytes() {
    cs += *b as u32;
  }
  cs %= 256;
  return cs;
}

/// This function validates FIX message checksum
///
/// # Examples
///
/// ```
/// use fix_checksum::validate;
///
/// // empty message
/// assert_eq!(false, validate(""));
///
/// // no tail
/// let inbound_message = "8=FIX.4.29=7335=049=BRKR56=INVMGR34=23552=19980604-07:58:28112=19980604-07:58:28";
/// assert_eq!(false, validate(inbound_message));
///
/// // invalid checksum
/// let inbound_message = "8=FIX.4.29=7335=049=BRKR56=INVMGR34=23552=19980604-07:58:28112=19980604-07:58:2810=231";
/// assert_eq!(false, validate(inbound_message));
///
/// // invalid checksum format
/// let inbound_message = "8=FIX.4.29=7335=049=BRKR56=INVMGR34=23552=19980604-07:58:28112=19980604-07:58:2810=2ZZ";
/// assert_eq!(false, validate(inbound_message));
///
/// let inbound_message = "8=FIX.4.29=7335=049=BRKR56=INVMGR34=23552=19980604-07:58:28112=19980604-07:58:2810=236";
/// assert_eq!(true, validate(inbound_message));
/// ```
pub fn validate(inbound_message: &str) -> bool {
  if inbound_message.is_empty() { return false; }

  let tail_start = inbound_message.find("\x01\x31\x30\x3D");
  if tail_start.is_none() { return false; }

  let split_index = tail_start.unwrap() + 1;
  let (checksum_index_start, checksum_index_end) = (split_index + 3, split_index + 6);

  let checksum_to_be = checksum(&inbound_message[..split_index]);
  let checksum_as_is = inbound_message[checksum_index_start..checksum_index_end].parse::<u32>();

  if checksum_as_is.is_err() { return false; }

  return checksum_as_is.unwrap() == checksum_to_be;
}

/// This function generates checksum of FIX message
///
/// # Examples
///
/// ```
/// use fix_checksum::generate;
///
/// let outbound_message = "8=FIX.4.2|9=73|35=0|49=BRKR|56=INVMGR|34=235|52=19980604-07:58:28|112=19980604-07:58:28|";
/// assert_eq!("196", generate(outbound_message));
/// ```
pub fn generate(outbound_message: &str) -> String {
  return checksum(outbound_message).to_string();
}

#[test]
fn it_should_calculate_fix_message_checksum() {
  let message = "8=FIX.4.29=7335=049=BRKR56=INVMGR34=23552=19980604-07:58:28112=19980604-07:58:28";
  assert_eq!(236, checksum(message));
}

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

  #[test]
  fn it_should_validate_fix_message_checksum() {
    // empty message
    assert_eq!(false, validate(""));

    // no tail
    let inbound_message = "8=FIX.4.29=7335=049=BRKR56=INVMGR34=23552=19980604-07:58:28112=19980604-07:58:28";
    assert_eq!(false, validate(inbound_message));

    // invalid checksum
    let inbound_message = "8=FIX.4.29=7335=049=BRKR56=INVMGR34=23552=19980604-07:58:28112=19980604-07:58:2810=231";
    assert_eq!(false, validate(inbound_message));

    // invalid checksum format
    let inbound_message = "8=FIX.4.29=7335=049=BRKR56=INVMGR34=23552=19980604-07:58:28112=19980604-07:58:2810=2ZZ";
    assert_eq!(false, validate(inbound_message));

    let inbound_message = "8=FIX.4.29=7335=049=BRKR56=INVMGR34=23552=19980604-07:58:28112=19980604-07:58:2810=236";
    assert_eq!(true, validate(inbound_message));
  }

  #[test]
  fn it_should_generate_fix_message_checksum() {
    let outbound_message = "8=FIX.4.29=7335=049=BRKR56=INVMGR34=23552=19980604-07:58:28112=19980604-07:58:28";
    assert_eq!("236", generate(outbound_message));
  }
}
<|endoftext|>


<commit_before>//! Read memory from another process' address space.
//!
//! This crate provides a trait—[`CopyAddress`](trait.CopyAddress.html),
//! and a helper function—[`copy_address`](fn.copy_address.html) that
//! allow reading memory from another process.
//!
//! Note: you may not always have permission to read memory from another
//! process! This may require `sudo` on some systems, and may fail even with
//! `sudo` on OS X. You are most likely to succeed if you are attempting to
//! read a process that you have spawned yourself.
//!
//! # Examples
//!
//! ```rust,no_run
//! # use std::io;
//! use read_process_memory::*;
//!
//! # fn foo(pid: Pid, address: usize, size: usize) -> io::Result<()> {
//! let handle = try!(pid.try_into_process_handle());
//! let bytes = try!(copy_address(address, size, &handle));
//! # Ok(())
//! # }
//! ```

#[macro_use]
extern crate log;
extern crate libc;

use std::io;

/// A trait that provides a method for reading memory from another process.
pub trait CopyAddress {
    /// Try to copy `buf.len()` bytes from `addr` in the process `self`, placing them in `buf`.
    fn copy_address(&self, addr: usize, buf: &mut [u8]) -> io::Result<()>;
}

/// A process ID.
pub use platform::Pid;
/// A handle to a running process. This is not a process ID on all platforms.
pub use platform::ProcessHandle;

/// Attempt to get a process handle for a running process.
///
/// This operation is not guaranteed to succeed. Specifically, on Windows
/// `OpenProcess` may fail, and on OS X `task_for_pid` will generally fail
/// unless run as root, and even then it may fail when called on certain
/// programs.
///
/// This should be dropped in favor of TryInto when that stabilizes:
/// https://github.com/rust-lang/rust/issues/33417
pub trait TryIntoProcessHandle {
    /// Attempt to get a `ProcessHandle` from `self`.
    fn try_into_process_handle(&self) -> io::Result<ProcessHandle>;
}

/// Trivial implementation of `TryIntoProcessHandle`.
///
/// A `ProcessHandle` is always usable.
impl TryIntoProcessHandle for ProcessHandle {
    fn try_into_process_handle(&self) -> io::Result<platform::ProcessHandle> {
        Ok(*self)
    }
}

#[cfg(target_os="linux")]
mod platform {
    use libc::{pid_t, c_void, iovec, process_vm_readv};
    use std::io;
    use std::process::Child;

    use super::{CopyAddress, TryIntoProcessHandle};

    /// On Linux a `Pid` is just a `libc::pid_t`.
    pub type Pid = pid_t;
    /// On Linux a `ProcessHandle` is just a `libc::pid_t`.
    pub type ProcessHandle = pid_t;

    /// A `process::Child` always has a pid, which is all we need on Linux.
    impl TryIntoProcessHandle for Child {
        fn try_into_process_handle(&self) -> io::Result<ProcessHandle> {
            Ok(self.id() as pid_t)
        }
    }

    impl CopyAddress for ProcessHandle {
        fn copy_address(&self, addr: usize, buf: &mut [u8]) -> io::Result<()> {
            let local_iov = iovec {
                iov_base: buf.as_mut_ptr() as *mut c_void,
                iov_len: buf.len(),
            };
            let remote_iov = iovec {
                iov_base: addr as *mut c_void,
                iov_len: buf.len(),
            };
            let result = unsafe { process_vm_readv(*self, &local_iov, 1, &remote_iov, 1, 0) };
            if result == -1 {
                Err(io::Error::last_os_error())
            } else {
                Ok(())
            }
        }
    }
}

#[cfg(target_os="macos")]
mod platform {
    extern crate mach;

    use libc::{pid_t, c_int};
    use self::mach::kern_return::{kern_return_t, KERN_SUCCESS};
    use self::mach::port::{mach_port_t, mach_port_name_t, MACH_PORT_NULL};
    use self::mach::vm_types::{mach_vm_address_t, mach_vm_size_t};
    use self::mach::message::mach_msg_type_number_t;
    use std::io;
    use std::process::Child;
    use std::ptr;
    use std::slice;

    use super::{CopyAddress, TryIntoProcessHandle};

    #[allow(non_camel_case_types)]
    type vm_map_t = mach_port_t;
    #[allow(non_camel_case_types)]
    type vm_address_t = mach_vm_address_t;
    #[allow(non_camel_case_types)]
    type vm_size_t = mach_vm_size_t;

    /// On OS X a `Pid` is just a `libc::pid_t`.
    pub type Pid = pid_t;
    /// On OS X a `ProcessHandle` is a mach port.
    pub type ProcessHandle = mach_port_name_t;

    extern "C" {
        fn vm_read(target_task: vm_map_t,
                   address: vm_address_t,
                   size: vm_size_t,
                   data: &*mut u8,
                   data_size: *mut mach_msg_type_number_t)
                   -> kern_return_t;
    }

    /// A small wrapper around `task_for_pid`, which takes a pid and returns the mach port
    /// representing its task.
    fn task_for_pid(pid: pid_t) -> io::Result<mach_port_name_t> {
        let mut task: mach_port_name_t = MACH_PORT_NULL;

        unsafe {
            let result =
                mach::traps::task_for_pid(mach::traps::mach_task_self(), pid as c_int, &mut task);
            if result != KERN_SUCCESS {
                return Err(io::Error::last_os_error());
            }
        }

        Ok(task)
    }

    /// `Pid` can be turned into a `ProcessHandle` with `task_for_pid`.
    impl TryIntoProcessHandle for Pid {
        fn try_into_process_handle(&self) -> io::Result<ProcessHandle> {
            task_for_pid(*self)
        }
    }

    /// This `TryIntoProcessHandle` impl simply calls the `TryIntoProcessHandle` impl for `Pid`.
    ///
    /// Unfortunately spawning a process on OS X does not hand back a mach
    /// port by default (you have to jump through several hoops to get at it),
    /// so there's no simple implementation of `TryIntoProcessHandle` for
    /// `std::process::Child`. This implementation is just provided for symmetry
    /// with other platforms to make writing cross-platform code easier.
    ///
    /// Ideally we would provide an implementation of `std::process::Command::spawn`
    /// that jumped through those hoops and provided the task port.
    impl TryIntoProcessHandle for Child {
        fn try_into_process_handle(&self) -> io::Result<ProcessHandle> {
            self.id().try_into_process_handle()
        }
    }

    /// Use `vm_read` to read memory from another process on OS X.
    impl CopyAddress for ProcessHandle {
        fn copy_address(&self, addr: usize, buf: &mut [u8]) -> io::Result<()> {
            let page_addr = (addr as i64 & (-4096)) as mach_vm_address_t;
            let last_page_addr = ((addr as i64 + buf.len() as i64 + 4095) & (-4096)) as
                                 mach_vm_address_t;
            let page_size = last_page_addr as usize - page_addr as usize;

            let read_ptr: *mut u8 = ptr::null_mut();
            let mut read_len: mach_msg_type_number_t = 0;

            let result = unsafe {
                vm_read(*self,
                        page_addr as u64,
                        page_size as vm_size_t,
                        &read_ptr,
                        &mut read_len)
            };

            if result != KERN_SUCCESS {
                return Err(io::Error::last_os_error());
            }

            if read_len != page_size as u32 {
                panic!("Mismatched read sizes for `vm_read` (expected {}, got {})",
                       page_size,
                       read_len)
            }

            let read_buf = unsafe { slice::from_raw_parts(read_ptr, read_len as usize) };

            let offset = addr - page_addr as usize;
            let len = buf.len();
            buf.copy_from_slice(&read_buf[offset..(offset + len)]);

            Ok(())
        }
    }
}

#[cfg(windows)]
mod platform {
    extern crate winapi;
    extern crate kernel32;

    use std::io;
    use std::mem;
    use std::os::windows::io::{AsRawHandle, RawHandle};
    use std::process::Child;
    use std::ptr;

    use super::{CopyAddress, TryIntoProcessHandle};

    /// On Windows a `Pid` is a `DWORD`.
    pub type Pid = winapi::DWORD;
    /// On Windows a `ProcessHandle` is a `HANDLE`.
    pub type ProcessHandle = RawHandle;

    /// A `Pid` can be turned into a `ProcessHandle` with `OpenProcess`.
    impl TryIntoProcessHandle for winapi::DWORD {
        fn try_into_process_handle(&self) -> io::Result<ProcessHandle> {
            let handle = unsafe {
                kernel32::OpenProcess(winapi::winnt::PROCESS_VM_READ, winapi::FALSE, *self)
            };
            if handle == (0 as RawHandle) {
                Err(io::Error::last_os_error())
            } else {
                Ok(handle)
            }
        }
    }

    /// A `std::process::Child` has a `HANDLE` from calling `CreateProcess`.
    impl TryIntoProcessHandle for Child {
        fn try_into_process_handle(&self) -> io::Result<ProcessHandle> {
            Ok(self.as_raw_handle())
        }
    }

    /// Use `ReadProcessMemory` to read memory from another process on Windows.
    impl CopyAddress for ProcessHandle {
        fn copy_address(&self, addr: usize, buf: &mut [u8]) -> io::Result<()> {
            if buf.len() == 0 {
                return Ok(());
            }

            if unsafe {
                kernel32::ReadProcessMemory(*self,
                                            addr as winapi::LPVOID,
                                            buf.as_mut_ptr() as winapi::LPVOID,
                                            mem::size_of_val(buf) as winapi::SIZE_T,
                                            ptr::null_mut())
            } == winapi::FALSE {
                Err(io::Error::last_os_error())
            } else {
                Ok(())
            }
        }
    }
}

/// Copy `length` bytes of memory at `addr` from `source`.
///
/// This is just a convenient way to call `CopyAddress::copy_address` without
/// having to provide your own buffer.
pub fn copy_address<T>(addr: usize, length: usize, source: &T) -> io::Result<Vec<u8>>
    where T: CopyAddress
{
    debug!("copy_address: addr: {:x}", addr);

    let mut copy = vec![0; length];

    source.copy_address(addr, &mut copy)
        .map_err(|e| {
            warn!("copy_address failed for {:x}: {:?}", addr, e);
            e
        })
        .and(Ok(copy))
}

#[cfg(test)]
mod test {
    #[cfg(target_os="macos")]
    extern crate spawn_task_port;

    use super::*;
    use std::env;
    use std::io::{self, BufRead, BufReader};
    use std::path::PathBuf;
    use std::process::{Child, Command, Stdio};

    fn test_process_path() -> Option<PathBuf> {
        env::current_exe()
            .ok()
            .and_then(|p| {
                p.parent().map(|p| {
                    p.with_file_name("test")
                        .with_extension(env::consts::EXE_EXTENSION)
                })
            })
    }

    #[cfg(not(target_os="macos"))]
    fn spawn_with_handle(cmd: &mut Command) -> io::Result<(Child, ProcessHandle)> {
        let child = try!(cmd.spawn()
            .map_err(|e| {
                println!("Error spawning test process '{:?}': {:?}", cmd, e);
                e
            }));
        let handle = try!(child.try_into_process_handle());
        Ok((child, handle))
    }

    #[cfg(target_os="macos")]
    fn spawn_with_handle(cmd: &mut Command) -> io::Result<(Child, ProcessHandle)> {
        use self::spawn_task_port::CommandSpawnWithTask;
        cmd.spawn_get_task_port()
    }

    fn read_test_process(args: Option<&[&str]>) -> io::Result<Vec<u8>> {
        // Spawn a child process and attempt to read its memory.
        let path = test_process_path().unwrap();
        let mut cmd = Command::new(&path);
        {
            cmd.stdin(Stdio::piped())
                .stdout(Stdio::piped());
        }
        if let Some(a) = args {
            cmd.args(a);
        }
        let (mut child, handle) = try!(spawn_with_handle(&mut cmd));
        // The test program prints the address and size.
        // See `src/bin/test.rs` for its source.
        let reader = BufReader::new(child.stdout.take().unwrap());
        let line = reader.lines().next().unwrap().unwrap();
        let bits = line.split(' ').collect::<Vec<_>>();
        let addr = usize::from_str_radix(&bits[0][2..], 16).unwrap();
        let size = bits[1].parse::<usize>().unwrap();
        let mem = try!(copy_address(addr, size, &handle));
        try!(child.wait());
        Ok(mem)
    }

    #[test]
    fn test_read_small() {
        let mem = read_test_process(None).unwrap();
        assert_eq!(mem, (0..32u8).collect::<Vec<u8>>());
    }

    #[test]
    fn test_read_large() {
        // 5000 should be greater than a single page on most systems.
        const SIZE: usize = 5000;
        let arg = format!("{}", SIZE);
        let mem = read_test_process(Some(&[&arg])).unwrap();
        let expected =
            (0..SIZE).map(|v| (v % (u8::max_value() as usize + 1)) as u8).collect::<Vec<u8>>();
        assert_eq!(mem, expected);
    }
}
<commit_msg>Fix memory leak in OSX<commit_after>//! Read memory from another process' address space.
//!
//! This crate provides a trait—[`CopyAddress`](trait.CopyAddress.html),
//! and a helper function—[`copy_address`](fn.copy_address.html) that
//! allow reading memory from another process.
//!
//! Note: you may not always have permission to read memory from another
//! process! This may require `sudo` on some systems, and may fail even with
//! `sudo` on OS X. You are most likely to succeed if you are attempting to
//! read a process that you have spawned yourself.
//!
//! # Examples
//!
//! ```rust,no_run
//! # use std::io;
//! use read_process_memory::*;
//!
//! # fn foo(pid: Pid, address: usize, size: usize) -> io::Result<()> {
//! let handle = try!(pid.try_into_process_handle());
//! let bytes = try!(copy_address(address, size, &handle));
//! # Ok(())
//! # }
//! ```

#[macro_use]
extern crate log;
extern crate libc;

use std::io;

/// A trait that provides a method for reading memory from another process.
pub trait CopyAddress {
    /// Try to copy `buf.len()` bytes from `addr` in the process `self`, placing them in `buf`.
    fn copy_address(&self, addr: usize, buf: &mut [u8]) -> io::Result<()>;
}

/// A process ID.
pub use platform::Pid;
/// A handle to a running process. This is not a process ID on all platforms.
pub use platform::ProcessHandle;

/// Attempt to get a process handle for a running process.
///
/// This operation is not guaranteed to succeed. Specifically, on Windows
/// `OpenProcess` may fail, and on OS X `task_for_pid` will generally fail
/// unless run as root, and even then it may fail when called on certain
/// programs.
///
/// This should be dropped in favor of TryInto when that stabilizes:
/// https://github.com/rust-lang/rust/issues/33417
pub trait TryIntoProcessHandle {
    /// Attempt to get a `ProcessHandle` from `self`.
    fn try_into_process_handle(&self) -> io::Result<ProcessHandle>;
}

/// Trivial implementation of `TryIntoProcessHandle`.
///
/// A `ProcessHandle` is always usable.
impl TryIntoProcessHandle for ProcessHandle {
    fn try_into_process_handle(&self) -> io::Result<platform::ProcessHandle> {
        Ok(*self)
    }
}

#[cfg(target_os="linux")]
mod platform {
    use libc::{pid_t, c_void, iovec, process_vm_readv};
    use std::io;
    use std::process::Child;

    use super::{CopyAddress, TryIntoProcessHandle};

    /// On Linux a `Pid` is just a `libc::pid_t`.
    pub type Pid = pid_t;
    /// On Linux a `ProcessHandle` is just a `libc::pid_t`.
    pub type ProcessHandle = pid_t;

    /// A `process::Child` always has a pid, which is all we need on Linux.
    impl TryIntoProcessHandle for Child {
        fn try_into_process_handle(&self) -> io::Result<ProcessHandle> {
            Ok(self.id() as pid_t)
        }
    }

    impl CopyAddress for ProcessHandle {
        fn copy_address(&self, addr: usize, buf: &mut [u8]) -> io::Result<()> {
            let local_iov = iovec {
                iov_base: buf.as_mut_ptr() as *mut c_void,
                iov_len: buf.len(),
            };
            let remote_iov = iovec {
                iov_base: addr as *mut c_void,
                iov_len: buf.len(),
            };
            let result = unsafe { process_vm_readv(*self, &local_iov, 1, &remote_iov, 1, 0) };
            if result == -1 {
                Err(io::Error::last_os_error())
            } else {
                Ok(())
            }
        }
    }
}

#[cfg(target_os="macos")]
mod platform {
    extern crate mach;

    use libc::{pid_t, c_int};
    use self::mach::kern_return::{kern_return_t, KERN_SUCCESS};
    use self::mach::port::{mach_port_t, mach_port_name_t, MACH_PORT_NULL};
    use self::mach::vm_types::{mach_vm_address_t, mach_vm_size_t};
    use self::mach::message::mach_msg_type_number_t;
    use std::io;
    use std::process::Child;
    use std::ptr;
    use std::slice;

    use super::{CopyAddress, TryIntoProcessHandle};

    #[allow(non_camel_case_types)]
    type vm_map_t = mach_port_t;
    #[allow(non_camel_case_types)]
    type vm_address_t = mach_vm_address_t;
    #[allow(non_camel_case_types)]
    type vm_size_t = mach_vm_size_t;

    /// On OS X a `Pid` is just a `libc::pid_t`.
    pub type Pid = pid_t;
    /// On OS X a `ProcessHandle` is a mach port.
    pub type ProcessHandle = mach_port_name_t;

    extern "C" {
        fn vm_read(target_task: vm_map_t,
                   address: vm_address_t,
                   size: vm_size_t,
                   data: &*mut u8,
                   data_size: *mut mach_msg_type_number_t)
                   -> kern_return_t;

        fn vm_deallocate(target_task: vm_map_t,
                         address: vm_address_t,
                         size: vm_size_t) -> kern_return_t;

        fn mach_task_self() -> mach_port_t;
    }

    /// A small wrapper around `task_for_pid`, which takes a pid and returns the mach port
    /// representing its task.
    fn task_for_pid(pid: pid_t) -> io::Result<mach_port_name_t> {
        let mut task: mach_port_name_t = MACH_PORT_NULL;

        unsafe {
            let result =
                mach::traps::task_for_pid(mach::traps::mach_task_self(), pid as c_int, &mut task);
            if result != KERN_SUCCESS {
                return Err(io::Error::last_os_error());
            }
        }

        Ok(task)
    }

    /// `Pid` can be turned into a `ProcessHandle` with `task_for_pid`.
    impl TryIntoProcessHandle for Pid {
        fn try_into_process_handle(&self) -> io::Result<ProcessHandle> {
            task_for_pid(*self)
        }
    }

    /// This `TryIntoProcessHandle` impl simply calls the `TryIntoProcessHandle` impl for `Pid`.
    ///
    /// Unfortunately spawning a process on OS X does not hand back a mach
    /// port by default (you have to jump through several hoops to get at it),
    /// so there's no simple implementation of `TryIntoProcessHandle` for
    /// `std::process::Child`. This implementation is just provided for symmetry
    /// with other platforms to make writing cross-platform code easier.
    ///
    /// Ideally we would provide an implementation of `std::process::Command::spawn`
    /// that jumped through those hoops and provided the task port.
    impl TryIntoProcessHandle for Child {
        fn try_into_process_handle(&self) -> io::Result<ProcessHandle> {
            self.id().try_into_process_handle()
        }
    }

    /// Use `vm_read` to read memory from another process on OS X.
    impl CopyAddress for ProcessHandle {
        fn copy_address(&self, addr: usize, buf: &mut [u8]) -> io::Result<()> {
            let page_addr = (addr as i64 & (-4096)) as mach_vm_address_t;
            let last_page_addr = ((addr as i64 + buf.len() as i64 + 4095) & (-4096)) as
                                 mach_vm_address_t;
            let page_size = last_page_addr as usize - page_addr as usize;

            let read_ptr: *mut u8 = ptr::null_mut();
            let mut read_len: mach_msg_type_number_t = 0;

            let result = unsafe {
                vm_read(*self,
                        page_addr as u64,
                        page_size as vm_size_t,
                        &read_ptr,
                        &mut read_len)
            };

            if result != KERN_SUCCESS {
                return Err(io::Error::last_os_error());
            }

            if read_len != page_size as u32 {
                panic!("Mismatched read sizes for `vm_read` (expected {}, got {})",
                       page_size,
                       read_len)
            }

            let read_buf = unsafe { slice::from_raw_parts(read_ptr, read_len as usize) };

            let offset = addr - page_addr as usize;
            let len = buf.len();
            buf.copy_from_slice(&read_buf[offset..(offset + len)]);

            unsafe {
                vm_deallocate(mach_task_self(),
                              read_ptr as vm_address_t,
                              read_len as vm_size_t);
            }
            Ok(())
        }
    }
}

#[cfg(windows)]
mod platform {
    extern crate winapi;
    extern crate kernel32;

    use std::io;
    use std::mem;
    use std::os::windows::io::{AsRawHandle, RawHandle};
    use std::process::Child;
    use std::ptr;

    use super::{CopyAddress, TryIntoProcessHandle};

    /// On Windows a `Pid` is a `DWORD`.
    pub type Pid = winapi::DWORD;
    /// On Windows a `ProcessHandle` is a `HANDLE`.
    pub type ProcessHandle = RawHandle;

    /// A `Pid` can be turned into a `ProcessHandle` with `OpenProcess`.
    impl TryIntoProcessHandle for winapi::DWORD {
        fn try_into_process_handle(&self) -> io::Result<ProcessHandle> {
            let handle = unsafe {
                kernel32::OpenProcess(winapi::winnt::PROCESS_VM_READ, winapi::FALSE, *self)
            };
            if handle == (0 as RawHandle) {
                Err(io::Error::last_os_error())
            } else {
                Ok(handle)
            }
        }
    }

    /// A `std::process::Child` has a `HANDLE` from calling `CreateProcess`.
    impl TryIntoProcessHandle for Child {
        fn try_into_process_handle(&self) -> io::Result<ProcessHandle> {
            Ok(self.as_raw_handle())
        }
    }

    /// Use `ReadProcessMemory` to read memory from another process on Windows.
    impl CopyAddress for ProcessHandle {
        fn copy_address(&self, addr: usize, buf: &mut [u8]) -> io::Result<()> {
            if buf.len() == 0 {
                return Ok(());
            }

            if unsafe {
                kernel32::ReadProcessMemory(*self,
                                            addr as winapi::LPVOID,
                                            buf.as_mut_ptr() as winapi::LPVOID,
                                            mem::size_of_val(buf) as winapi::SIZE_T,
                                            ptr::null_mut())
            } == winapi::FALSE {
                Err(io::Error::last_os_error())
            } else {
                Ok(())
            }
        }
    }
}

/// Copy `length` bytes of memory at `addr` from `source`.
///
/// This is just a convenient way to call `CopyAddress::copy_address` without
/// having to provide your own buffer.
pub fn copy_address<T>(addr: usize, length: usize, source: &T) -> io::Result<Vec<u8>>
    where T: CopyAddress
{
    debug!("copy_address: addr: {:x}", addr);

    let mut copy = vec![0; length];

    source.copy_address(addr, &mut copy)
        .map_err(|e| {
            warn!("copy_address failed for {:x}: {:?}", addr, e);
            e
        })
        .and(Ok(copy))
}

#[cfg(test)]
mod test {
    #[cfg(target_os="macos")]
    extern crate spawn_task_port;

    use super::*;
    use std::env;
    use std::io::{self, BufRead, BufReader};
    use std::path::PathBuf;
    use std::process::{Child, Command, Stdio};

    fn test_process_path() -> Option<PathBuf> {
        env::current_exe()
            .ok()
            .and_then(|p| {
                p.parent().map(|p| {
                    p.with_file_name("test")
                        .with_extension(env::consts::EXE_EXTENSION)
                })
            })
    }

    #[cfg(not(target_os="macos"))]
    fn spawn_with_handle(cmd: &mut Command) -> io::Result<(Child, ProcessHandle)> {
        let child = try!(cmd.spawn()
            .map_err(|e| {
                println!("Error spawning test process '{:?}': {:?}", cmd, e);
                e
            }));
        let handle = try!(child.try_into_process_handle());
        Ok((child, handle))
    }

    #[cfg(target_os="macos")]
    fn spawn_with_handle(cmd: &mut Command) -> io::Result<(Child, ProcessHandle)> {
        use self::spawn_task_port::CommandSpawnWithTask;
        cmd.spawn_get_task_port()
    }

    fn read_test_process(args: Option<&[&str]>) -> io::Result<Vec<u8>> {
        // Spawn a child process and attempt to read its memory.
        let path = test_process_path().unwrap();
        let mut cmd = Command::new(&path);
        {
            cmd.stdin(Stdio::piped())
                .stdout(Stdio::piped());
        }
        if let Some(a) = args {
            cmd.args(a);
        }
        let (mut child, handle) = try!(spawn_with_handle(&mut cmd));
        // The test program prints the address and size.
        // See `src/bin/test.rs` for its source.
        let reader = BufReader::new(child.stdout.take().unwrap());
        let line = reader.lines().next().unwrap().unwrap();
        let bits = line.split(' ').collect::<Vec<_>>();
        let addr = usize::from_str_radix(&bits[0][2..], 16).unwrap();
        let size = bits[1].parse::<usize>().unwrap();
        let mem = try!(copy_address(addr, size, &handle));
        try!(child.wait());
        Ok(mem)
    }

    #[test]
    fn test_read_small() {
        let mem = read_test_process(None).unwrap();
        assert_eq!(mem, (0..32u8).collect::<Vec<u8>>());
    }

    #[test]
    fn test_read_large() {
        // 5000 should be greater than a single page on most systems.
        const SIZE: usize = 5000;
        let arg = format!("{}", SIZE);
        let mem = read_test_process(Some(&[&arg])).unwrap();
        let expected =
            (0..SIZE).map(|v| (v % (u8::max_value() as usize + 1)) as u8).collect::<Vec<u8>>();
        assert_eq!(mem, expected);
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 Corey Farwell
// Copyright 2015 Contributors of github.com/huonw/crates.io-graph
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::ascii::AsciiExt;
use std::collections::HashMap;
use std::fs;
use std::io::{BufRead, BufReader};
use std::path::PathBuf;

extern crate git2;
extern crate glob;
extern crate rustc_serialize;

static INDEX_GIT_URL: &'static str = "https://github.com/rust-lang/crates.io-index";

/// A single version of crate published to the index
#[derive(RustcDecodable)]
pub struct Version {
    pub name: String,
    pub vers: String,
    pub deps: Vec<Dependency>,
    pub cksum: String,
    pub features: HashMap<String, Vec<String>>,
    pub yanked: bool,
}

/// A single dependency of a specific crate version
#[derive(RustcDecodable)]
pub struct Dependency {
    pub name: String,
    pub req: String,
    pub features: Vec<String>,
    pub optional: bool,
    pub default_features: bool,
    pub target: Option<String>,
    pub kind: Option<String>
}

/// Constructed from `Index::crates`
pub struct Crates(CrateIndexPaths);

impl Iterator for Crates {
    type Item = Crate;
    fn next(&mut self) -> Option<Self::Item> {
        self.0.next().map(|p| Crate::new(&p))
    }
}

/// Constructed from `Index::crate_index_paths`
pub struct CrateIndexPaths(std::iter::Chain<glob::Paths, glob::Paths>);

impl CrateIndexPaths {
    fn new(path: PathBuf) -> CrateIndexPaths {
        let mut match_options = glob::MatchOptions::new();
        match_options.require_literal_leading_dot = true;

        let glob_pattern = format!("{}/*/*/*", path.to_str().unwrap());
        let index_paths1 = glob::glob_with(&glob_pattern, &match_options).unwrap();

        let glob_pattern = format!("{}/[12]/*", path.to_str().unwrap());
        let index_paths2 = glob::glob_with(&glob_pattern, &match_options).unwrap();

        CrateIndexPaths(index_paths1.chain(index_paths2))
    }
}

impl Iterator for CrateIndexPaths {
    type Item = PathBuf;
    fn next(&mut self)  -> Option<Self::Item> {
        self.0.next().map(|glob_result| glob_result.unwrap())
    }
}

pub struct Index {
    path: PathBuf,
}

impl Index {
    /// Construct a new Index supplying a path where the index lives or should live
    pub fn new(path: PathBuf) -> Index {
        Index{path: path}
    }

    /// Determines if *anything* exists at the path specified from the constructor
    pub fn exists(&self) -> bool {
        fs::metadata(&self.path).is_ok()
    }

    /// Clones the index to the path specified from the constructor
    pub fn clone(&self) -> Result<(), git2::Error> {
        let _ = try!(git2::Repository::clone(INDEX_GIT_URL, &self.path));
        Ok(())
    }

    pub fn crate_(&self, crate_name: &str) -> Option<Crate> {
        self.crate_index_paths()
            .find(|path| path.file_name().unwrap().to_str().unwrap().eq_ignore_ascii_case(crate_name))
            .map(|p| Crate::new(&p))
    }

    pub fn crates(&self) -> Crates {
        Crates(self.crate_index_paths())
    }

    /// Returns all the crate index file paths in the index
    pub fn crate_index_paths(&self) -> CrateIndexPaths {
        CrateIndexPaths::new(self.path.clone())  // TODO: remove this clone
    }

    /// Generates a map of dependencies where the keys are crate names and the values are vectors
    /// of crate names that are its dependencies
    pub fn dependency_map(&self) -> HashMap<String, Vec<String>> {
        let mut map = HashMap::new();
        for crate_ in self.crates() {
            let version = crate_.latest_version();
            let mut deps_names = version.deps.iter().map(|d| d.name.clone()).collect::<Vec<_>>();
            deps_names.sort_by(|a, b| a.cmp(b));
            deps_names.dedup();
            map.insert(version.name.clone(), deps_names);
        }

        map
    }
}

pub struct Crate {
    versions: Vec<Version>,
}

impl Crate {
    pub fn new(index_path: &PathBuf) -> Crate {
        let mut versions = vec![];
        let file = fs::File::open(&index_path).unwrap();
        for line in BufReader::new(file).lines() {
            let version: Version = rustc_serialize::json::decode(&line.unwrap()).unwrap();
            versions.push(version);
        }
        Crate {versions: versions}
    }

    pub fn latest_version(&self) -> &Version {
        &self.versions[self.versions.len() - 1]
    }
}

#[test]
fn test_dependencies() {
    let index = Index::new("_test".into());
    if !index.exists() {
        index.clone().unwrap();
    }
    let crate_ = index.crates().nth(0).unwrap();
    let version = crate_.latest_version();
    let _ = version.deps;
}
<commit_msg>Remove no longer necessary dependency_map method<commit_after>// Copyright 2015 Corey Farwell
// Copyright 2015 Contributors of github.com/huonw/crates.io-graph
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::ascii::AsciiExt;
use std::collections::HashMap;
use std::fs;
use std::io::{BufRead, BufReader};
use std::path::PathBuf;

extern crate git2;
extern crate glob;
extern crate rustc_serialize;

static INDEX_GIT_URL: &'static str = "https://github.com/rust-lang/crates.io-index";

/// A single version of crate published to the index
#[derive(RustcDecodable)]
pub struct Version {
    pub name: String,
    pub vers: String,
    pub deps: Vec<Dependency>,
    pub cksum: String,
    pub features: HashMap<String, Vec<String>>,
    pub yanked: bool,
}

/// A single dependency of a specific crate version
#[derive(RustcDecodable)]
pub struct Dependency {
    pub name: String,
    pub req: String,
    pub features: Vec<String>,
    pub optional: bool,
    pub default_features: bool,
    pub target: Option<String>,
    pub kind: Option<String>
}

/// Constructed from `Index::crates`
pub struct Crates(CrateIndexPaths);

impl Iterator for Crates {
    type Item = Crate;
    fn next(&mut self) -> Option<Self::Item> {
        self.0.next().map(|p| Crate::new(&p))
    }
}

/// Constructed from `Index::crate_index_paths`
pub struct CrateIndexPaths(std::iter::Chain<glob::Paths, glob::Paths>);

impl CrateIndexPaths {
    fn new(path: PathBuf) -> CrateIndexPaths {
        let mut match_options = glob::MatchOptions::new();
        match_options.require_literal_leading_dot = true;

        let glob_pattern = format!("{}/*/*/*", path.to_str().unwrap());
        let index_paths1 = glob::glob_with(&glob_pattern, &match_options).unwrap();

        let glob_pattern = format!("{}/[12]/*", path.to_str().unwrap());
        let index_paths2 = glob::glob_with(&glob_pattern, &match_options).unwrap();

        CrateIndexPaths(index_paths1.chain(index_paths2))
    }
}

impl Iterator for CrateIndexPaths {
    type Item = PathBuf;
    fn next(&mut self)  -> Option<Self::Item> {
        self.0.next().map(|glob_result| glob_result.unwrap())
    }
}

pub struct Index {
    path: PathBuf,
}

impl Index {
    /// Construct a new Index supplying a path where the index lives or should live
    pub fn new(path: PathBuf) -> Index {
        Index{path: path}
    }

    /// Determines if *anything* exists at the path specified from the constructor
    pub fn exists(&self) -> bool {
        fs::metadata(&self.path).is_ok()
    }

    /// Clones the index to the path specified from the constructor
    pub fn clone(&self) -> Result<(), git2::Error> {
        let _ = try!(git2::Repository::clone(INDEX_GIT_URL, &self.path));
        Ok(())
    }

    pub fn crate_(&self, crate_name: &str) -> Option<Crate> {
        self.crate_index_paths()
            .find(|path| path.file_name().unwrap().to_str().unwrap().eq_ignore_ascii_case(crate_name))
            .map(|p| Crate::new(&p))
    }

    pub fn crates(&self) -> Crates {
        Crates(self.crate_index_paths())
    }

    /// Returns all the crate index file paths in the index
    pub fn crate_index_paths(&self) -> CrateIndexPaths {
        CrateIndexPaths::new(self.path.clone())  // TODO: remove this clone
    }
}

pub struct Crate {
    versions: Vec<Version>,
}

impl Crate {
    pub fn new(index_path: &PathBuf) -> Crate {
        let mut versions = vec![];
        let file = fs::File::open(&index_path).unwrap();
        for line in BufReader::new(file).lines() {
            let version: Version = rustc_serialize::json::decode(&line.unwrap()).unwrap();
            versions.push(version);
        }
        Crate {versions: versions}
    }

    pub fn latest_version(&self) -> &Version {
        &self.versions[self.versions.len() - 1]
    }
}

#[test]
fn test_dependencies() {
    let index = Index::new("_test".into());
    if !index.exists() {
        index.clone().unwrap();
    }
    let crate_ = index.crates().nth(0).unwrap();
    let version = crate_.latest_version();
    let _ = version.deps;
}
<|endoftext|>


<commit_before>#![feature(iter_arith, zero_one)]

extern crate rand;
extern crate rayon;
extern crate fixedbitset;
#[macro_use]
extern crate log;
// extern crate cppn;
extern crate sorted_vec;
extern crate acyclic_network;

pub mod traits;
pub mod innovation;
mod selection;
pub mod alignment;
pub mod alignment_metric;
pub mod mutate;
pub mod fitness;
pub mod population;
pub mod prob;

pub mod gene;
pub mod gene_list;
pub mod crossover;

pub mod genomes;
<commit_msg>Cleanup<commit_after>#![feature(iter_arith, zero_one)]

extern crate rand;
extern crate rayon;
extern crate fixedbitset;
#[macro_use]
extern crate log;
extern crate sorted_vec;
extern crate acyclic_network;

pub mod traits;
pub mod innovation;
mod selection;
pub mod alignment;
pub mod alignment_metric;
pub mod mutate;
pub mod fitness;
pub mod population;
pub mod prob;
pub mod gene;
pub mod gene_list;
pub mod crossover;
pub mod genomes;
<|endoftext|>


<commit_before>//! # Gerber commands
//!
//! This module implements the basic building blocks of Gerber code. It
//! focusses on the low level types and does not do any semantic checking.
//!
//! For example, you can use an aperture without defining it. This will
//! generate syntactically valid but semantially invalid Gerber code, but this
//! module won't complain.

mod types;
mod attributes;
mod codegen;

pub use types::*;
pub use codegen::*;

#[cfg(test)]
mod test {
    use super::{GCode, InterpolationMode, QuadrantMode};
    use super::{MCode};
    use super::{DCode, Operation, Coordinates, CoordinateOffset};
    use super::GerberCode;

    #[test]
    fn test_to_code() {
        //! The to_code method of the GerberCode trait should generate strings.
        let comment = GCode::Comment("testcomment".to_string());
        assert_eq!(comment.to_code(), "G04 testcomment *".to_string());
    }

    #[test]
    fn test_vec_to_code() {
        //! A `Vec<T: GerberCode>` should also implement `GerberCode`.
        let mut v = Vec::new();
        v.push(GCode::Comment("comment 1".to_string()));
        v.push(GCode::Comment("another one".to_string()));
        assert_eq!(v.to_code(), "G04 comment 1 *\nG04 another one *".to_string());
    }

    #[test]
    fn test_interpolation_mode() {
        let mut commands = Vec::new();
        let c1 = GCode::InterpolationMode(InterpolationMode::Linear);
        let c2 = GCode::InterpolationMode(InterpolationMode::ClockwiseCircular);
        let c3 = GCode::InterpolationMode(InterpolationMode::CounterclockwiseCircular);
        commands.push(c1);
        commands.push(c2);
        commands.push(c3);
        assert_eq!(commands.to_code(), "G01*\nG02*\nG03*".to_string());
    }

    #[test]
    fn test_region_mode() {
        let mut commands = Vec::new();
        commands.push(GCode::RegionMode(true));
        commands.push(GCode::RegionMode(false));
        assert_eq!(commands.to_code(), "G36*\nG37*".to_string());
    }

    #[test]
    fn test_quadrant_mode() {
        let mut commands = Vec::new();
        commands.push(GCode::QuadrantMode(QuadrantMode::Single));
        commands.push(GCode::QuadrantMode(QuadrantMode::Multi));
        assert_eq!(commands.to_code(), "G74*\nG75*".to_string());
    }

    #[test]
    fn test_end_of_file() {
        let c = MCode::EndOfFile;
        assert_eq!(c.to_code(), "M02*".to_string());
    }

    #[test]
    fn test_coordinates() {
        macro_rules! assert_coords {
            ($x:expr, $y:expr, $result:expr) => {{
                assert_eq!(Coordinates { x: $x, y: $y }.to_code(), $result.to_string());
            }}
        }
        assert_coords!(Some(10), Some(20), "X10Y20");
        assert_coords!(None, None, ""); // TODO should we catch this?
        assert_coords!(Some(10), None, "X10");
        assert_coords!(None, Some(20), "Y20");
        assert_coords!(Some(0), Some(-400), "X0Y-400");
    }

    #[test]
    fn test_offset() {
        macro_rules! assert_coords {
            ($x:expr, $y:expr, $result:expr) => {{
                assert_eq!(CoordinateOffset { x: $x, y: $y }.to_code(), $result.to_string());
            }}
        }
        assert_coords!(Some(10), Some(20), "I10J20");
        assert_coords!(None, None, ""); // TODO should we catch this?
        assert_coords!(Some(10), None, "I10");
        assert_coords!(None, Some(20), "J20");
        assert_coords!(Some(0), Some(-400), "I0J-400");
    }

    #[test]
    fn test_operation_interpolate() {
        let c1 = Operation::Interpolate(
            Coordinates::new(100, 200),
            Some(CoordinateOffset::new(5, 10))
        );
        assert_eq!(c1.to_code(), "X100Y200I5J10D01*".to_string());
        let c2 = Operation::Interpolate(
            Coordinates::at_y(-200),
            None
        );
        assert_eq!(c2.to_code(), "Y-200D01*".to_string());
        let c3 = Operation::Interpolate(
            Coordinates::at_x(1),
            Some(CoordinateOffset::at_y(2))
        );
        assert_eq!(c3.to_code(), "X1J2D01*".to_string());
    }

    #[test]
    fn test_operation_move() {
        let c = Operation::Move(Coordinates::new(23, 42));
        assert_eq!(c.to_code(), "X23Y42D02*".to_string());
    }

    #[test]
    fn test_operation_flash() {
        let c = Operation::Flash(Coordinates::new(23, 42));
        assert_eq!(c.to_code(), "X23Y42D03*".to_string());
    }

    #[test]
    fn test_select_aperture() {
        let c1 = DCode::SelectAperture(10);
        assert_eq!(c1.to_code(), "D10*".to_string());
        let c2 = DCode::SelectAperture(2147483647);
        assert_eq!(c2.to_code(), "D2147483647*".to_string());
    }

}
<commit_msg>Expose attributes<commit_after>//! # Gerber commands
//!
//! This module implements the basic building blocks of Gerber code. It
//! focusses on the low level types and does not do any semantic checking.
//!
//! For example, you can use an aperture without defining it. This will
//! generate syntactically valid but semantially invalid Gerber code, but this
//! module won't complain.

mod types;
mod attributes;
mod codegen;

pub use types::*;
pub use attributes::*;
pub use codegen::*;

#[cfg(test)]
mod test {
    use super::{GCode, InterpolationMode, QuadrantMode};
    use super::{MCode};
    use super::{DCode, Operation, Coordinates, CoordinateOffset};
    use super::GerberCode;

    #[test]
    fn test_to_code() {
        //! The to_code method of the GerberCode trait should generate strings.
        let comment = GCode::Comment("testcomment".to_string());
        assert_eq!(comment.to_code(), "G04 testcomment *".to_string());
    }

    #[test]
    fn test_vec_to_code() {
        //! A `Vec<T: GerberCode>` should also implement `GerberCode`.
        let mut v = Vec::new();
        v.push(GCode::Comment("comment 1".to_string()));
        v.push(GCode::Comment("another one".to_string()));
        assert_eq!(v.to_code(), "G04 comment 1 *\nG04 another one *".to_string());
    }

    #[test]
    fn test_interpolation_mode() {
        let mut commands = Vec::new();
        let c1 = GCode::InterpolationMode(InterpolationMode::Linear);
        let c2 = GCode::InterpolationMode(InterpolationMode::ClockwiseCircular);
        let c3 = GCode::InterpolationMode(InterpolationMode::CounterclockwiseCircular);
        commands.push(c1);
        commands.push(c2);
        commands.push(c3);
        assert_eq!(commands.to_code(), "G01*\nG02*\nG03*".to_string());
    }

    #[test]
    fn test_region_mode() {
        let mut commands = Vec::new();
        commands.push(GCode::RegionMode(true));
        commands.push(GCode::RegionMode(false));
        assert_eq!(commands.to_code(), "G36*\nG37*".to_string());
    }

    #[test]
    fn test_quadrant_mode() {
        let mut commands = Vec::new();
        commands.push(GCode::QuadrantMode(QuadrantMode::Single));
        commands.push(GCode::QuadrantMode(QuadrantMode::Multi));
        assert_eq!(commands.to_code(), "G74*\nG75*".to_string());
    }

    #[test]
    fn test_end_of_file() {
        let c = MCode::EndOfFile;
        assert_eq!(c.to_code(), "M02*".to_string());
    }

    #[test]
    fn test_coordinates() {
        macro_rules! assert_coords {
            ($x:expr, $y:expr, $result:expr) => {{
                assert_eq!(Coordinates { x: $x, y: $y }.to_code(), $result.to_string());
            }}
        }
        assert_coords!(Some(10), Some(20), "X10Y20");
        assert_coords!(None, None, ""); // TODO should we catch this?
        assert_coords!(Some(10), None, "X10");
        assert_coords!(None, Some(20), "Y20");
        assert_coords!(Some(0), Some(-400), "X0Y-400");
    }

    #[test]
    fn test_offset() {
        macro_rules! assert_coords {
            ($x:expr, $y:expr, $result:expr) => {{
                assert_eq!(CoordinateOffset { x: $x, y: $y }.to_code(), $result.to_string());
            }}
        }
        assert_coords!(Some(10), Some(20), "I10J20");
        assert_coords!(None, None, ""); // TODO should we catch this?
        assert_coords!(Some(10), None, "I10");
        assert_coords!(None, Some(20), "J20");
        assert_coords!(Some(0), Some(-400), "I0J-400");
    }

    #[test]
    fn test_operation_interpolate() {
        let c1 = Operation::Interpolate(
            Coordinates::new(100, 200),
            Some(CoordinateOffset::new(5, 10))
        );
        assert_eq!(c1.to_code(), "X100Y200I5J10D01*".to_string());
        let c2 = Operation::Interpolate(
            Coordinates::at_y(-200),
            None
        );
        assert_eq!(c2.to_code(), "Y-200D01*".to_string());
        let c3 = Operation::Interpolate(
            Coordinates::at_x(1),
            Some(CoordinateOffset::at_y(2))
        );
        assert_eq!(c3.to_code(), "X1J2D01*".to_string());
    }

    #[test]
    fn test_operation_move() {
        let c = Operation::Move(Coordinates::new(23, 42));
        assert_eq!(c.to_code(), "X23Y42D02*".to_string());
    }

    #[test]
    fn test_operation_flash() {
        let c = Operation::Flash(Coordinates::new(23, 42));
        assert_eq!(c.to_code(), "X23Y42D03*".to_string());
    }

    #[test]
    fn test_select_aperture() {
        let c1 = DCode::SelectAperture(10);
        assert_eq!(c1.to_code(), "D10*".to_string());
        let c2 = DCode::SelectAperture(2147483647);
        assert_eq!(c2.to_code(), "D2147483647*".to_string());
    }

}
<|endoftext|>


<commit_before>#![deny(missing_docs)]

//! A GLFW window back-end for the Piston game engine.

extern crate glfw;
extern crate collections;
extern crate gl;
extern crate window;
extern crate shader_version;
extern crate input;
extern crate current;

// External crates.
use current::{ Get, Modifier };
use collections::RingBuf;
use glfw::Context;
use input::{
    keyboard,
    mouse,
    InputEvent,
};
use window::{
    Window,
    WindowSettings,
    ShouldClose, Size, PollEvent, SwapBuffers,
    CaptureCursor, DrawSize, Title, SetTitle,
    ExitOnEsc
};
use shader_version::opengl::OpenGL;

/// Contains stuff for game window.
pub struct GlfwWindow {
    /// The window.
    pub window: glfw::Window,
    /// Receives events from window.
    events: Receiver<(f64, glfw::WindowEvent)>,
    /// GLFW context.
    pub glfw: glfw::Glfw,
    event_queue: RingBuf<input::InputEvent>,
    // Used to compute relative mouse movement.
    last_mouse_pos: Option<(f64, f64)>,
    // The back-end does not remember the title.
    title: String,
    exit_on_esc: bool,
}

#[test]
fn test_glfw_window() {
    fn foo<T: Window>() {}

    foo::<GlfwWindow>();
}

impl GlfwWindow {
    /// Create a new game window from an existing GLFW window.
    pub fn from_pieces(win: glfw::Window, glfw: glfw::Glfw,
                       events: Receiver<(f64, glfw::WindowEvent)>,
                       exit_on_esc: bool) -> GlfwWindow {
        win.set_all_polling(true);
        win.make_current();
        let title = "<unknown window title, created from_pieces>";
        GlfwWindow {
            window: win,
            events: events,
            glfw: glfw,
            exit_on_esc: exit_on_esc,
            event_queue: RingBuf::new(),
            last_mouse_pos: None,
            title: title.to_string(),
        }
    }

    /// Creates a new game window for GLFW.
    pub fn new(opengl: OpenGL, settings: WindowSettings) -> GlfwWindow {
        use glfw::Context;

        // Initialize GLFW.
        let glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

        let (major, minor) = opengl.get_major_minor();

        // Make sure we have the right GL version.
        glfw.window_hint(glfw::ContextVersion(major as u32, minor as u32));
        glfw.window_hint(glfw::OpenglForwardCompat(true));
        glfw.window_hint(glfw::OpenglProfile(glfw::OpenGlProfileHint::Core));
        glfw.window_hint(glfw::Samples(settings.samples as u32));

        // Create GLFW window.
        let (window, events) = glfw.create_window(
            settings.size[0],
            settings.size[1],
            settings.title.as_slice(), glfw::Windowed
        ).expect("Failed to create GLFW window.");
        window.set_all_polling(true);
        window.make_current();

        // Load the OpenGL function pointers
        gl::load_with(|s| window.get_proc_address(s));

        GlfwWindow {
            window: window,
            events: events,
            glfw: glfw,
            event_queue: RingBuf::new(),
            last_mouse_pos: None,
            title: settings.title,
            exit_on_esc: settings.exit_on_esc,
        }
    }

    fn flush_messages(&mut self) {
        if self.event_queue.len() != 0 {
            return;
        }

        self.glfw.poll_events();
        for (_, event) in glfw::flush_messages(&self.events) {
            match event {
                glfw::WindowEvent::Key(glfw::Key::Escape, _, glfw::Press, _)
                if self.exit_on_esc => {
                    self.window.set_should_close(true);
                }
                glfw::WindowEvent::Char(ch) => {
                    self.event_queue.push_back(input::Text(ch.to_string()));
                }
                glfw::WindowEvent::Key(key, _, glfw::Press, _) => {
                    self.event_queue.push_back(
                        input::Press(input::Keyboard(glfw_map_key(key)))
                    );
                }
                glfw::WindowEvent::Key(key, _, glfw::Release, _) => {
                    self.event_queue.push_back(
                        input::Release(input::Keyboard(glfw_map_key(key)))
                    );
                }
                glfw::WindowEvent::MouseButton(button, glfw::Press, _) => {
                    self.event_queue.push_back(
                        input::Press(input::Mouse(glfw_map_mouse(button)))
                    );
                }
                glfw::WindowEvent::MouseButton(button, glfw::Release, _) => {
                    self.event_queue.push_back(
                        input::Release(input::Mouse(glfw_map_mouse(button)))
                    );
                }
                glfw::WindowEvent::CursorPos(x, y) => {
                    self.event_queue.push_back(input::Move(input::MouseCursor(x, y)));
                    match self.last_mouse_pos {
                        Some((lx, ly)) => {
                            self.event_queue.push_back(
                                input::Move(input::MouseRelative(x - lx, y - ly))
                            )
                        }
                        None => {}
                    };
                    self.last_mouse_pos = Some((x, y));
                }
                glfw::WindowEvent::Scroll(x, y) => {
                    self.event_queue.push_back(input::Move(input::MouseScroll(x, y)));
                }
                glfw::WindowEvent::Size(w, h) => {
                    self.event_queue.push_back(input::Resize(w as u32, h as u32));
                }
                glfw::WindowEvent::Focus(focus) => {
                    self.event_queue.push_back(input::Focus(focus));
                }
                _ => {}
            }
        }
    }
}

impl Get<Size> for GlfwWindow {
    fn get(&self) -> Size {
        let (w, h) = self.window.get_size();
        Size([w as u32, h as u32])
    }
}

impl Get<ShouldClose> for GlfwWindow {
    fn get(&self) -> ShouldClose {
        ShouldClose(self.window.should_close())
    }
}

impl PollEvent<InputEvent> for GlfwWindow {
    fn poll_event(&mut self) -> Option<input::InputEvent> {
        self.flush_messages();

        if self.event_queue.len() != 0 {
            self.event_queue.pop_front()
        } else {
            None
        }
    }
}

impl SwapBuffers for GlfwWindow {
    fn swap_buffers(&mut self) {
        use glfw::Context;

        self.window.swap_buffers();
    }
}

impl Modifier<GlfwWindow> for CaptureCursor {
    fn modify(self, window: &mut GlfwWindow) {
        let CaptureCursor(enabled) = self;
        if enabled {
            window.window.set_cursor_mode(glfw::CursorMode::Disabled)
        } else {
            window.window.set_cursor_mode(glfw::CursorMode::Normal);
            window.last_mouse_pos = None;
        }
    }
}

impl Modifier<GlfwWindow> for ShouldClose {
    fn modify(self, window: &mut GlfwWindow) {
        let ShouldClose(val) = self;
        window.window.set_should_close(val);
    }
}

impl Get<DrawSize> for GlfwWindow {
    fn get(&self) -> DrawSize {
        let (w, h) = self.window.get_framebuffer_size();
        DrawSize([w as u32, h as u32])
    }
}

impl Get<Title> for GlfwWindow {
    fn get(&self) -> Title {
        Title(self.title.clone())
    }
}

impl Modifier<GlfwWindow> for Title {
    fn modify(self, window: &mut GlfwWindow) {
        let Title(val) = self;
        window.window.set_title(val.as_slice())
    }
}

impl Get<ExitOnEsc> for GlfwWindow {
    fn get(&self) -> ExitOnEsc {
        ExitOnEsc(self.exit_on_esc)
    }
}

impl Modifier<GlfwWindow> for ExitOnEsc {
    fn modify(self, window: &mut GlfwWindow) {
        let ExitOnEsc(val) = self;
        window.exit_on_esc = val;
    }
}

fn glfw_map_key(keycode: glfw::Key) -> keyboard::Key {
    match keycode {
        glfw::Key::Num0 => keyboard::D0,
        glfw::Key::Num1 => keyboard::D1,
        glfw::Key::Num2 => keyboard::D2,
        glfw::Key::Num3 => keyboard::D3,
        glfw::Key::Num4 => keyboard::D4,
        glfw::Key::Num5 => keyboard::D5,
        glfw::Key::Num6 => keyboard::D6,
        glfw::Key::Num7 => keyboard::D7,
        glfw::Key::Num8 => keyboard::D8,
        glfw::Key::Num9 => keyboard::D9,
        glfw::Key::A => keyboard::A,
        glfw::Key::B => keyboard::B,
        glfw::Key::C => keyboard::C,
        glfw::Key::D => keyboard::D,
        glfw::Key::E => keyboard::E,
        glfw::Key::F => keyboard::F,
        glfw::Key::G => keyboard::G,
        glfw::Key::H => keyboard::H,
        glfw::Key::I => keyboard::I,
        glfw::Key::J => keyboard::J,
        glfw::Key::K => keyboard::K,
        glfw::Key::L => keyboard::L,
        glfw::Key::M => keyboard::M,
        glfw::Key::N => keyboard::N,
        glfw::Key::O => keyboard::O,
        glfw::Key::P => keyboard::P,
        glfw::Key::Q => keyboard::Q,
        glfw::Key::R => keyboard::R,
        glfw::Key::S => keyboard::S,
        glfw::Key::T => keyboard::T,
        glfw::Key::U => keyboard::U,
        glfw::Key::V => keyboard::V,
        glfw::Key::W => keyboard::W,
        glfw::Key::X => keyboard::X,
        glfw::Key::Y => keyboard::Y,
        glfw::Key::Z => keyboard::Z,
        glfw::Key::Apostrophe => keyboard::Unknown,
        glfw::Key::Backslash => keyboard::Backslash,
        glfw::Key::Backspace => keyboard::Backspace,
        glfw::Key::CapsLock => keyboard::CapsLock,
        glfw::Key::Delete => keyboard::Delete,
        glfw::Key::Comma => keyboard::Comma,
        glfw::Key::Down => keyboard::Down,
        glfw::Key::End => keyboard::End,
        glfw::Key::Enter => keyboard::Return,
        glfw::Key::Equal => keyboard::Equals,
        glfw::Key::Escape => keyboard::Escape,
        glfw::Key::F1 => keyboard::F1,
        glfw::Key::F2 => keyboard::F2,
        glfw::Key::F3 => keyboard::F3,
        glfw::Key::F4 => keyboard::F4,
        glfw::Key::F5 => keyboard::F5,
        glfw::Key::F6 => keyboard::F6,
        glfw::Key::F7 => keyboard::F7,
        glfw::Key::F8 => keyboard::F8,
        glfw::Key::F9 => keyboard::F9,
        glfw::Key::F10 => keyboard::F10,
        glfw::Key::F11 => keyboard::F11,
        glfw::Key::F12 => keyboard::F12,
        glfw::Key::F13 => keyboard::F13,
        glfw::Key::F14 => keyboard::F14,
        glfw::Key::F15 => keyboard::F15,
        glfw::Key::F16 => keyboard::F16,
        glfw::Key::F17 => keyboard::F17,
        glfw::Key::F18 => keyboard::F18,
        glfw::Key::F19 => keyboard::F19,
        glfw::Key::F20 => keyboard::F20,
        glfw::Key::F21 => keyboard::F21,
        glfw::Key::F22 => keyboard::F22,
        glfw::Key::F23 => keyboard::F23,
        glfw::Key::F24 => keyboard::F24,
        // Possibly next code.
        glfw::Key::F25 => keyboard::Unknown,
        glfw::Key::Kp0 => keyboard::NumPad0,
        glfw::Key::Kp1 => keyboard::NumPad1,
        glfw::Key::Kp2 => keyboard::NumPad2,
        glfw::Key::Kp3 => keyboard::NumPad3,
        glfw::Key::Kp4 => keyboard::NumPad4,
        glfw::Key::Kp5 => keyboard::NumPad5,
        glfw::Key::Kp6 => keyboard::NumPad6,
        glfw::Key::Kp7 => keyboard::NumPad7,
        glfw::Key::Kp8 => keyboard::NumPad8,
        glfw::Key::Kp9 => keyboard::NumPad9,
        glfw::Key::KpDecimal => keyboard::NumPadDecimal,
        glfw::Key::KpDivide => keyboard::NumPadDivide,
        glfw::Key::KpMultiply => keyboard::NumPadMultiply,
        glfw::Key::KpSubtract => keyboard::NumPadMinus,
        glfw::Key::KpAdd => keyboard::NumPadPlus,
        glfw::Key::KpEnter => keyboard::NumPadEnter,
        glfw::Key::KpEqual => keyboard::NumPadEquals,
        glfw::Key::LeftShift => keyboard::LShift,
        glfw::Key::LeftControl => keyboard::LCtrl,
        glfw::Key::LeftAlt => keyboard::LAlt,
        glfw::Key::LeftSuper => keyboard::LGui,
        glfw::Key::RightShift => keyboard::RShift,
        glfw::Key::RightControl => keyboard::RCtrl,
        glfw::Key::RightAlt => keyboard::RAlt,
        glfw::Key::RightSuper => keyboard::RGui,
        // Map to backslash?
        glfw::Key::GraveAccent => keyboard::Unknown,
        glfw::Key::Home => keyboard::Home,
        glfw::Key::Insert => keyboard::Insert,
        glfw::Key::Left => keyboard::Left,
        glfw::Key::LeftBracket => keyboard::LeftBracket,
        glfw::Key::Menu => keyboard::Menu,
        glfw::Key::Minus => keyboard::Minus,
        glfw::Key::NumLock => keyboard::NumLockClear,
        glfw::Key::PageDown => keyboard::PageDown,
        glfw::Key::PageUp => keyboard::PageUp,
        glfw::Key::Pause => keyboard::Pause,
        glfw::Key::Period => keyboard::Period,
        glfw::Key::PrintScreen => keyboard::PrintScreen,
        glfw::Key::Right => keyboard::Right,
        glfw::Key::RightBracket => keyboard::RightBracket,
        glfw::Key::ScrollLock => keyboard::ScrollLock,
        glfw::Key::Semicolon => keyboard::Semicolon,
        glfw::Key::Slash => keyboard::Slash,
        glfw::Key::Space => keyboard::Space,
        glfw::Key::Tab => keyboard::Tab,
        glfw::Key::Up => keyboard::Up,
        glfw::Key::World1 => keyboard::Unknown,
        glfw::Key::World2 => keyboard::Unknown,
        // _ => keyboard::Unknown,
    }
}

fn glfw_map_mouse(mouse_button: glfw::MouseButton) -> mouse::Button {
    match mouse_button {
        glfw::MouseButton::Button1 => mouse::Left,
        glfw::MouseButton::Button2 => mouse::Right,
        glfw::MouseButton::Button3 => mouse::Middle,
        glfw::MouseButton::Button4 => mouse::X1,
        glfw::MouseButton::Button5 => mouse::X2,
        glfw::MouseButton::Button6 => mouse::Button6,
        glfw::MouseButton::Button7 => mouse::Button7,
        glfw::MouseButton::Button8 => mouse::Button8,
    }
}
<commit_msg>Upgraded to latest Rust<commit_after>#![deny(missing_docs)]

//! A GLFW window back-end for the Piston game engine.

extern crate glfw;
extern crate collections;
extern crate gl;
extern crate window;
extern crate shader_version;
extern crate input;
extern crate current;

// External crates.
use current::{ Get, Modifier };
use collections::RingBuf;
use glfw::Context;
use input::{
    keyboard,
    mouse,
    Button,
    InputEvent,
    Motion,
};
use window::{
    Window,
    WindowSettings,
    ShouldClose, Size, PollEvent, SwapBuffers,
    CaptureCursor, DrawSize, Title, SetTitle,
    ExitOnEsc
};
use shader_version::opengl::OpenGL;

/// Contains stuff for game window.
pub struct GlfwWindow {
    /// The window.
    pub window: glfw::Window,
    /// Receives events from window.
    events: Receiver<(f64, glfw::WindowEvent)>,
    /// GLFW context.
    pub glfw: glfw::Glfw,
    event_queue: RingBuf<input::InputEvent>,
    // Used to compute relative mouse movement.
    last_mouse_pos: Option<(f64, f64)>,
    // The back-end does not remember the title.
    title: String,
    exit_on_esc: bool,
}

#[test]
fn test_glfw_window() {
    fn foo<T: Window>() {}

    foo::<GlfwWindow>();
}

impl GlfwWindow {
    /// Create a new game window from an existing GLFW window.
    pub fn from_pieces(win: glfw::Window, glfw: glfw::Glfw,
                       events: Receiver<(f64, glfw::WindowEvent)>,
                       exit_on_esc: bool) -> GlfwWindow {
        win.set_all_polling(true);
        win.make_current();
        let title = "<unknown window title, created from_pieces>";
        GlfwWindow {
            window: win,
            events: events,
            glfw: glfw,
            exit_on_esc: exit_on_esc,
            event_queue: RingBuf::new(),
            last_mouse_pos: None,
            title: title.to_string(),
        }
    }

    /// Creates a new game window for GLFW.
    pub fn new(opengl: OpenGL, settings: WindowSettings) -> GlfwWindow {
        use glfw::Context;

        // Initialize GLFW.
        let glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

        let (major, minor) = opengl.get_major_minor();

        // Make sure we have the right GL version.
        glfw.window_hint(glfw::WindowHint::ContextVersion(major as u32, minor as u32));
        glfw.window_hint(glfw::WindowHint::OpenglForwardCompat(true));
        glfw.window_hint(glfw::WindowHint::OpenglProfile(glfw::OpenGlProfileHint::Core));
        glfw.window_hint(glfw::WindowHint::Samples(settings.samples as u32));

        // Create GLFW window.
        let (window, events) = glfw.create_window(
            settings.size[0],
            settings.size[1],
            settings.title.as_slice(), glfw::WindowMode::Windowed
        ).expect("Failed to create GLFW window.");
        window.set_all_polling(true);
        window.make_current();

        // Load the OpenGL function pointers
        gl::load_with(|s| window.get_proc_address(s));

        GlfwWindow {
            window: window,
            events: events,
            glfw: glfw,
            event_queue: RingBuf::new(),
            last_mouse_pos: None,
            title: settings.title,
            exit_on_esc: settings.exit_on_esc,
        }
    }

    fn flush_messages(&mut self) {
        if self.event_queue.len() != 0 {
            return;
        }

        self.glfw.poll_events();
        for (_, event) in glfw::flush_messages(&self.events) {
            match event {
                glfw::WindowEvent::Key(glfw::Key::Escape, _, glfw::Action::Press, _)
                if self.exit_on_esc => {
                    self.window.set_should_close(true);
                }
                glfw::WindowEvent::Char(ch) => {
                    self.event_queue.push_back(InputEvent::Text(ch.to_string()));
                }
                glfw::WindowEvent::Key(key, _, glfw::Action::Press, _) => {
                    self.event_queue.push_back(
                        InputEvent::Press(Button::Keyboard(glfw_map_key(key)))
                    );
                }
                glfw::WindowEvent::Key(key, _, glfw::Action::Release, _) => {
                    self.event_queue.push_back(
                        InputEvent::Release(Button::Keyboard(glfw_map_key(key)))
                    );
                }
                glfw::WindowEvent::MouseButton(button, glfw::Action::Press, _) => {
                    self.event_queue.push_back(
                        InputEvent::Press(Button::Mouse(glfw_map_mouse(button)))
                    );
                }
                glfw::WindowEvent::MouseButton(button, glfw::Action::Release, _) => {
                    self.event_queue.push_back(
                        InputEvent::Release(Button::Mouse(glfw_map_mouse(button)))
                    );
                }
                glfw::WindowEvent::CursorPos(x, y) => {
                    self.event_queue.push_back(InputEvent::Move(Motion::MouseCursor(x, y)));
                    match self.last_mouse_pos {
                        Some((lx, ly)) => {
                            self.event_queue.push_back(
                                InputEvent::Move(Motion::MouseRelative(x - lx, y - ly))
                            )
                        }
                        None => {}
                    };
                    self.last_mouse_pos = Some((x, y));
                }
                glfw::WindowEvent::Scroll(x, y) => {
                    self.event_queue.push_back(InputEvent::Move(Motion::MouseScroll(x, y)));
                }
                glfw::WindowEvent::Size(w, h) => {
                    self.event_queue.push_back(InputEvent::Resize(w as u32, h as u32));
                }
                glfw::WindowEvent::Focus(focus) => {
                    self.event_queue.push_back(InputEvent::Focus(focus));
                }
                _ => {}
            }
        }
    }
}

impl Get<Size> for GlfwWindow {
    fn get(&self) -> Size {
        let (w, h) = self.window.get_size();
        Size([w as u32, h as u32])
    }
}

impl Get<ShouldClose> for GlfwWindow {
    fn get(&self) -> ShouldClose {
        ShouldClose(self.window.should_close())
    }
}

impl PollEvent<InputEvent> for GlfwWindow {
    fn poll_event(&mut self) -> Option<input::InputEvent> {
        self.flush_messages();

        if self.event_queue.len() != 0 {
            self.event_queue.pop_front()
        } else {
            None
        }
    }
}

impl SwapBuffers for GlfwWindow {
    fn swap_buffers(&mut self) {
        use glfw::Context;

        self.window.swap_buffers();
    }
}

impl Modifier<GlfwWindow> for CaptureCursor {
    fn modify(self, window: &mut GlfwWindow) {
        let CaptureCursor(enabled) = self;
        if enabled {
            window.window.set_cursor_mode(glfw::CursorMode::Disabled)
        } else {
            window.window.set_cursor_mode(glfw::CursorMode::Normal);
            window.last_mouse_pos = None;
        }
    }
}

impl Modifier<GlfwWindow> for ShouldClose {
    fn modify(self, window: &mut GlfwWindow) {
        let ShouldClose(val) = self;
        window.window.set_should_close(val);
    }
}

impl Get<DrawSize> for GlfwWindow {
    fn get(&self) -> DrawSize {
        let (w, h) = self.window.get_framebuffer_size();
        DrawSize([w as u32, h as u32])
    }
}

impl Get<Title> for GlfwWindow {
    fn get(&self) -> Title {
        Title(self.title.clone())
    }
}

impl Modifier<GlfwWindow> for Title {
    fn modify(self, window: &mut GlfwWindow) {
        let Title(val) = self;
        window.window.set_title(val.as_slice())
    }
}

impl Get<ExitOnEsc> for GlfwWindow {
    fn get(&self) -> ExitOnEsc {
        ExitOnEsc(self.exit_on_esc)
    }
}

impl Modifier<GlfwWindow> for ExitOnEsc {
    fn modify(self, window: &mut GlfwWindow) {
        let ExitOnEsc(val) = self;
        window.exit_on_esc = val;
    }
}

fn glfw_map_key(keycode: glfw::Key) -> keyboard::Key {
    use input::keyboard::Key;

    match keycode {
        glfw::Key::Num0 => Key::D0,
        glfw::Key::Num1 => Key::D1,
        glfw::Key::Num2 => Key::D2,
        glfw::Key::Num3 => Key::D3,
        glfw::Key::Num4 => Key::D4,
        glfw::Key::Num5 => Key::D5,
        glfw::Key::Num6 => Key::D6,
        glfw::Key::Num7 => Key::D7,
        glfw::Key::Num8 => Key::D8,
        glfw::Key::Num9 => Key::D9,
        glfw::Key::A => Key::A,
        glfw::Key::B => Key::B,
        glfw::Key::C => Key::C,
        glfw::Key::D => Key::D,
        glfw::Key::E => Key::E,
        glfw::Key::F => Key::F,
        glfw::Key::G => Key::G,
        glfw::Key::H => Key::H,
        glfw::Key::I => Key::I,
        glfw::Key::J => Key::J,
        glfw::Key::K => Key::K,
        glfw::Key::L => Key::L,
        glfw::Key::M => Key::M,
        glfw::Key::N => Key::N,
        glfw::Key::O => Key::O,
        glfw::Key::P => Key::P,
        glfw::Key::Q => Key::Q,
        glfw::Key::R => Key::R,
        glfw::Key::S => Key::S,
        glfw::Key::T => Key::T,
        glfw::Key::U => Key::U,
        glfw::Key::V => Key::V,
        glfw::Key::W => Key::W,
        glfw::Key::X => Key::X,
        glfw::Key::Y => Key::Y,
        glfw::Key::Z => Key::Z,
        glfw::Key::Apostrophe => Key::Unknown,
        glfw::Key::Backslash => Key::Backslash,
        glfw::Key::Backspace => Key::Backspace,
        glfw::Key::CapsLock => Key::CapsLock,
        glfw::Key::Delete => Key::Delete,
        glfw::Key::Comma => Key::Comma,
        glfw::Key::Down => Key::Down,
        glfw::Key::End => Key::End,
        glfw::Key::Enter => Key::Return,
        glfw::Key::Equal => Key::Equals,
        glfw::Key::Escape => Key::Escape,
        glfw::Key::F1 => Key::F1,
        glfw::Key::F2 => Key::F2,
        glfw::Key::F3 => Key::F3,
        glfw::Key::F4 => Key::F4,
        glfw::Key::F5 => Key::F5,
        glfw::Key::F6 => Key::F6,
        glfw::Key::F7 => Key::F7,
        glfw::Key::F8 => Key::F8,
        glfw::Key::F9 => Key::F9,
        glfw::Key::F10 => Key::F10,
        glfw::Key::F11 => Key::F11,
        glfw::Key::F12 => Key::F12,
        glfw::Key::F13 => Key::F13,
        glfw::Key::F14 => Key::F14,
        glfw::Key::F15 => Key::F15,
        glfw::Key::F16 => Key::F16,
        glfw::Key::F17 => Key::F17,
        glfw::Key::F18 => Key::F18,
        glfw::Key::F19 => Key::F19,
        glfw::Key::F20 => Key::F20,
        glfw::Key::F21 => Key::F21,
        glfw::Key::F22 => Key::F22,
        glfw::Key::F23 => Key::F23,
        glfw::Key::F24 => Key::F24,
        // Possibly next code.
        glfw::Key::F25 => Key::Unknown,
        glfw::Key::Kp0 => Key::NumPad0,
        glfw::Key::Kp1 => Key::NumPad1,
        glfw::Key::Kp2 => Key::NumPad2,
        glfw::Key::Kp3 => Key::NumPad3,
        glfw::Key::Kp4 => Key::NumPad4,
        glfw::Key::Kp5 => Key::NumPad5,
        glfw::Key::Kp6 => Key::NumPad6,
        glfw::Key::Kp7 => Key::NumPad7,
        glfw::Key::Kp8 => Key::NumPad8,
        glfw::Key::Kp9 => Key::NumPad9,
        glfw::Key::KpDecimal => Key::NumPadDecimal,
        glfw::Key::KpDivide => Key::NumPadDivide,
        glfw::Key::KpMultiply => Key::NumPadMultiply,
        glfw::Key::KpSubtract => Key::NumPadMinus,
        glfw::Key::KpAdd => Key::NumPadPlus,
        glfw::Key::KpEnter => Key::NumPadEnter,
        glfw::Key::KpEqual => Key::NumPadEquals,
        glfw::Key::LeftShift => Key::LShift,
        glfw::Key::LeftControl => Key::LCtrl,
        glfw::Key::LeftAlt => Key::LAlt,
        glfw::Key::LeftSuper => Key::LGui,
        glfw::Key::RightShift => Key::RShift,
        glfw::Key::RightControl => Key::RCtrl,
        glfw::Key::RightAlt => Key::RAlt,
        glfw::Key::RightSuper => Key::RGui,
        // Map to backslash?
        glfw::Key::GraveAccent => Key::Unknown,
        glfw::Key::Home => Key::Home,
        glfw::Key::Insert => Key::Insert,
        glfw::Key::Left => Key::Left,
        glfw::Key::LeftBracket => Key::LeftBracket,
        glfw::Key::Menu => Key::Menu,
        glfw::Key::Minus => Key::Minus,
        glfw::Key::NumLock => Key::NumLockClear,
        glfw::Key::PageDown => Key::PageDown,
        glfw::Key::PageUp => Key::PageUp,
        glfw::Key::Pause => Key::Pause,
        glfw::Key::Period => Key::Period,
        glfw::Key::PrintScreen => Key::PrintScreen,
        glfw::Key::Right => Key::Right,
        glfw::Key::RightBracket => Key::RightBracket,
        glfw::Key::ScrollLock => Key::ScrollLock,
        glfw::Key::Semicolon => Key::Semicolon,
        glfw::Key::Slash => Key::Slash,
        glfw::Key::Space => Key::Space,
        glfw::Key::Tab => Key::Tab,
        glfw::Key::Up => Key::Up,
        glfw::Key::World1 => Key::Unknown,
        glfw::Key::World2 => Key::Unknown,
        // _ => keyboard::Unknown,
    }
}

fn glfw_map_mouse(mouse_button: glfw::MouseButton) -> mouse::Button {
    use input::mouse::Button;

    match mouse_button {
        glfw::MouseButton::Button1 => Button::Left,
        glfw::MouseButton::Button2 => Button::Right,
        glfw::MouseButton::Button3 => Button::Middle,
        glfw::MouseButton::Button4 => Button::X1,
        glfw::MouseButton::Button5 => Button::X2,
        glfw::MouseButton::Button6 => Button::Button6,
        glfw::MouseButton::Button7 => Button::Button7,
        glfw::MouseButton::Button8 => Button::Button8,
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate bincode;
extern crate take_mut;

use std::io;
use std::error::Error;
use std::marker::PhantomData;
use std::cell;

#[derive(Debug)]
pub enum DecodingError {
    Corrupt(String),
    IoError(io::Error),
}

fn decode<O: serde::de::DeserializeOwned, R: io::Read+io::Seek>(reader: &mut R, offset: u64) -> Result<O, DecodingError> {
    reader.seek(io::SeekFrom::Start(offset)).map_err(|x| DecodingError::IoError(x))?;
    bincode::deserialize_from(    reader, bincode::Infinite)
    .map_err(|x| {
        match *x {
            bincode::ErrorKind::IoError(y) => DecodingError::IoError(y),
            _ => DecodingError::Corrupt(x.description().to_string()),
        }
    })
}

#[derive(Debug)]
pub enum EncodingError {
    Unknown(String),
    IoError(io::Error),
}

fn encode<O: serde::Serialize, W: io::Write+io::Seek>(writer: &mut W, obj: &O) -> Result<u64, EncodingError> {
    let offset = writer.seek(io::SeekFrom::End(0)).map_err(|x| EncodingError::IoError(x))?;
    bincode::serialize_into(writer, obj, bincode::Infinite)
    .map_err(|x| {
        match *x {
            bincode::ErrorKind::IoError(y) => EncodingError::IoError(y),
            _ => EncodingError::Unknown(x.description().to_string()),
        }
    }).map(|_| offset)
}

#[derive(Serialize, Deserialize, Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
enum NodeType {
    Root,
    Internal,
    Leaf
}

enum NodeRefInternal<K> {
    Unloaded(u64),
    Loaded(Box<Node<K>>),
}

struct NodeRef<K>(cell::UnsafeCell<NodeRefInternal<K>>);

// An on-disk representation, for space saving.
#[derive(Serialize, Deserialize)]
struct DiskNode<K> {
    node_type: NodeType,
    keys: Vec<K>,
    children: Vec<u64>,
}

struct Node<K> {
    node_type: NodeType,
    keys: Vec<K>,
    children: Vec<NodeRef<K>>,
    modified: bool,
}

impl<K: serde::de::DeserializeOwned> From<DiskNode<K>> for Node<K> {
    fn from(obj: DiskNode<K>) -> Node<K> {
        Node {
            node_type: obj.node_type,
            keys: obj.keys,
            children: obj.children.into_iter().map(|x| (NodeRef::from_offset(x))).collect(),
            modified: false,
        }
    }
}

impl<K: serde::de::DeserializeOwned> DiskNode<K> {
    fn load<R: io::Read+io::Seek>(reader: &mut R, offset: u64) -> Result<DiskNode<K>, DecodingError> {
        decode(reader, offset)
    }
}

fn load<K: serde::de::DeserializeOwned, R: io::Read+io::Seek>(reader: &mut R, offset: u64) -> Result<Node<K>, DecodingError> {
    Ok(DiskNode::<K>::load(reader, offset)?.into())
}

impl<K: serde::de::DeserializeOwned> NodeRef<K> {
    fn from_offset(offset: u64) -> NodeRef<K> {
        NodeRef(cell::UnsafeCell::new(NodeRefInternal::Unloaded(offset)))
    }

    fn load<R: io::Read+io::Seek>(&self, reader: &mut R) -> Result<(), DecodingError> {
        let internal = self.0.get();
        unsafe {
            if let NodeRefInternal::Unloaded(offset) = *internal {
                *internal = NodeRefInternal::Loaded(Box::new(load(reader, offset)?));
            }
        }
        Ok(())
    }

    fn get<R: io::Read+io::Seek>(&self, reader: &mut R) -> Result<&Node<K>, DecodingError> {
        self.load(reader)?;
        unsafe {
            Ok(match *self.0.get() {
                NodeRefInternal::Loaded(ref n) => n,
                _ => panic!("Nodes should be loaded."),
            })
        }
    }

    fn get_mut<R: io::Read+io::Seek>(&mut self, reader: &mut R) -> Result<&mut Node<K>, DecodingError> {
        self.load(reader)?;
        unsafe {
            Ok(match *self.0.get() {
                NodeRefInternal::Loaded(ref mut n) => {
                    n.modified = true;
                    n
                },
                _ => panic!("Node not loaded."),
            })
        }
    }

    fn offset_or_panic(&self, msg: &'static str) -> u64 {
        let internal = self.0.get();
        unsafe {
            match *internal {
                NodeRefInternal::Unloaded(offset) => offset,
                _ => panic!(msg),
            }
        }
    }
}

impl<K: serde::de::DeserializeOwned+Eq+Ord> Node<K> {
    fn find_offset_for<R: io::Read+io::Seek>(&self, reader: &mut R, key: &K) -> Result<Option<u64>, DecodingError> {
        if self.node_type == NodeType::Leaf {
            if self.children.len() == 0 { return Ok(None) } //empty tree.
            match self.keys.binary_search(key) {
                Ok(ind) => Ok(Some(self.children[ind].offset_or_panic("This is a leaf, but somehow has a loaded child."))),
                Err(_) => Ok(None),
            }
        }
        else {
            self.children[self.index_of(key)].get(reader)?.find_offset_for(reader, key)
        }
    }

    fn index_of(&self, key: &K) -> usize{
        assert!(self.node_type != NodeType::Leaf);
        let ind = self.keys.binary_search(key);
        // Explanation: this returns the index of the child to the right of the last key smaller than key.
        // In this implementation, before is <= and after is >.
        // Before is the index of the key, after is the index of the key+1.
        // The not found case of binary_search is the key+1.
        match ind {
            Ok(index) | Err(index) => index,
        }
    }
}

struct BPTree<'a, R: 'a, K, V> {
    root_reference: NodeRef<K>,
    backing_io: &'a mut R,
    _phantom: PhantomData<V>
}

impl<'a, R: io::Read+io::Seek, K: serde::de::DeserializeOwned+Eq+Ord, V> BPTree<'a, R, K, V> {
    pub fn contains(&mut self, key: &K) -> Result<bool, DecodingError> {
        Ok(self.offset_for(key)?.is_some())
    }

    pub fn offset_for(&mut self, key: &K) -> Result<Option<u64>, DecodingError> {
        self.root_reference.get(self.backing_io)?.find_offset_for(self.backing_io, key)
    }
}
<commit_msg>Implement Drop for NodeRef.<commit_after>#![allow(dead_code)]
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate bincode;
extern crate take_mut;

use std::io;
use std::error::Error;
use std::marker::PhantomData;
use std::cell;

#[derive(Debug)]
pub enum DecodingError {
    Corrupt(String),
    IoError(io::Error),
}

fn decode<O: serde::de::DeserializeOwned, R: io::Read+io::Seek>(reader: &mut R, offset: u64) -> Result<O, DecodingError> {
    reader.seek(io::SeekFrom::Start(offset)).map_err(|x| DecodingError::IoError(x))?;
    bincode::deserialize_from(    reader, bincode::Infinite)
    .map_err(|x| {
        match *x {
            bincode::ErrorKind::IoError(y) => DecodingError::IoError(y),
            _ => DecodingError::Corrupt(x.description().to_string()),
        }
    })
}

#[derive(Debug)]
pub enum EncodingError {
    Unknown(String),
    IoError(io::Error),
}

fn encode<O: serde::Serialize, W: io::Write+io::Seek>(writer: &mut W, obj: &O) -> Result<u64, EncodingError> {
    let offset = writer.seek(io::SeekFrom::End(0)).map_err(|x| EncodingError::IoError(x))?;
    bincode::serialize_into(writer, obj, bincode::Infinite)
    .map_err(|x| {
        match *x {
            bincode::ErrorKind::IoError(y) => EncodingError::IoError(y),
            _ => EncodingError::Unknown(x.description().to_string()),
        }
    }).map(|_| offset)
}

#[derive(Serialize, Deserialize, Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
enum NodeType {
    Root,
    Internal,
    Leaf
}

enum NodeRefInternal<K> {
    Unloaded(u64),
    Loaded(Box<Node<K>>),
}

struct NodeRef<K>(cell::UnsafeCell<NodeRefInternal<K>>);

// An on-disk representation, for space saving.
#[derive(Serialize, Deserialize)]
struct DiskNode<K> {
    node_type: NodeType,
    keys: Vec<K>,
    children: Vec<u64>,
}

struct Node<K> {
    node_type: NodeType,
    keys: Vec<K>,
    children: Vec<NodeRef<K>>,
    modified: bool,
}

impl<K: serde::de::DeserializeOwned> From<DiskNode<K>> for Node<K> {
    fn from(obj: DiskNode<K>) -> Node<K> {
        Node {
            node_type: obj.node_type,
            keys: obj.keys,
            children: obj.children.into_iter().map(|x| (NodeRef::from_offset(x))).collect(),
            modified: false,
        }
    }
}

impl<K: serde::de::DeserializeOwned> DiskNode<K> {
    fn load<R: io::Read+io::Seek>(reader: &mut R, offset: u64) -> Result<DiskNode<K>, DecodingError> {
        decode(reader, offset)
    }
}

fn load<K: serde::de::DeserializeOwned, R: io::Read+io::Seek>(reader: &mut R, offset: u64) -> Result<Node<K>, DecodingError> {
    Ok(DiskNode::<K>::load(reader, offset)?.into())
}

impl<K: serde::de::DeserializeOwned> NodeRef<K> {
    fn from_offset(offset: u64) -> NodeRef<K> {
        NodeRef(cell::UnsafeCell::new(NodeRefInternal::Unloaded(offset)))
    }

    fn load<R: io::Read+io::Seek>(&self, reader: &mut R) -> Result<(), DecodingError> {
        let internal = self.0.get();
        unsafe {
            if let NodeRefInternal::Unloaded(offset) = *internal {
                *internal = NodeRefInternal::Loaded(Box::new(load(reader, offset)?));
            }
        }
        Ok(())
    }

    fn get<R: io::Read+io::Seek>(&self, reader: &mut R) -> Result<&Node<K>, DecodingError> {
        self.load(reader)?;
        unsafe {
            Ok(match *self.0.get() {
                NodeRefInternal::Loaded(ref n) => n,
                _ => panic!("Nodes should be loaded."),
            })
        }
    }

    fn get_mut<R: io::Read+io::Seek>(&mut self, reader: &mut R) -> Result<&mut Node<K>, DecodingError> {
        self.load(reader)?;
        unsafe {
            Ok(match *self.0.get() {
                NodeRefInternal::Loaded(ref mut n) => {
                    n.modified = true;
                    n
                },
                _ => panic!("Node not loaded."),
            })
        }
    }

    fn offset_or_panic(&self, msg: &'static str) -> u64 {
        let internal = self.0.get();
        unsafe {
            match *internal {
                NodeRefInternal::Unloaded(offset) => offset,
                _ => panic!(msg),
            }
        }
    }
}

impl<K> Drop for NodeRef<K> {
    fn drop(&mut self) {
        unsafe { std::ptr::drop_in_place(self.0.get()); }
    }
}

impl<K: serde::de::DeserializeOwned+Eq+Ord> Node<K> {
    fn find_offset_for<R: io::Read+io::Seek>(&self, reader: &mut R, key: &K) -> Result<Option<u64>, DecodingError> {
        if self.node_type == NodeType::Leaf {
            if self.children.len() == 0 { return Ok(None) } //empty tree.
            match self.keys.binary_search(key) {
                Ok(ind) => Ok(Some(self.children[ind].offset_or_panic("This is a leaf, but somehow has a loaded child."))),
                Err(_) => Ok(None),
            }
        }
        else {
            self.children[self.index_of(key)].get(reader)?.find_offset_for(reader, key)
        }
    }

    fn index_of(&self, key: &K) -> usize{
        assert!(self.node_type != NodeType::Leaf);
        let ind = self.keys.binary_search(key);
        // Explanation: this returns the index of the child to the right of the last key smaller than key.
        // In this implementation, before is <= and after is >.
        // Before is the index of the key, after is the index of the key+1.
        // The not found case of binary_search is the key+1.
        match ind {
            Ok(index) | Err(index) => index,
        }
    }
}

struct BPTree<'a, R: 'a, K, V> {
    root_reference: NodeRef<K>,
    backing_io: &'a mut R,
    _phantom: PhantomData<V>
}

impl<'a, R: io::Read+io::Seek, K: serde::de::DeserializeOwned+Eq+Ord, V> BPTree<'a, R, K, V> {
    pub fn contains(&mut self, key: &K) -> Result<bool, DecodingError> {
        Ok(self.offset_for(key)?.is_some())
    }

    pub fn offset_for(&mut self, key: &K) -> Result<Option<u64>, DecodingError> {
        self.root_reference.get(self.backing_io)?.find_offset_for(self.backing_io, key)
    }
}
<|endoftext|>