<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 taskes a pid 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))
}

//TODO: make the tests work on OS X by sending task rights:
// http://www.foldr.org/~michaelw/log/computers/macosx/task-info-fun-with-mach
#[cfg(test)]
#[cfg(not(target_os="macos"))]
mod test {
    use super::*;
    use std::env;
    use std::io::{self, BufRead, BufReader};
    use std::path::PathBuf;
    use std::process::{Command, Stdio};

    fn test_process_path() -> io::Result<PathBuf> {
        env::current_exe().map(|p| {
            p.with_file_name("test")
                .with_extension(env::consts::EXE_EXTENSION)
        })
    }

    #[test]
    fn read_test_process() {
        // Spawn a child process and attempt to read its memory.
        let child = Command::new(test_process_path().unwrap())
            .stdout(Stdio::piped())
            .spawn().unwrap();
        let handle = child.try_into_process_handle().unwrap();
        // The test program prints the address and size.
        // See `src/bin/test.rs` for its source.
        let reader = BufReader::new(child.stdout.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 = copy_address(addr, size, &handle).unwrap();
        assert_eq!(mem, (0..32u8).collect::<Vec<u8>>());
    }
}
<commit_msg>find test binary in the right place<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;
    }

    /// A small wrapper around `task_for_pid`, which taskes a pid 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))
}

//TODO: make the tests work on OS X by sending task rights:
// http://www.foldr.org/~michaelw/log/computers/macosx/task-info-fun-with-mach
#[cfg(test)]
#[cfg(not(target_os="macos"))]
mod test {
    use super::*;
    use std::env;
    use std::io::{BufRead, BufReader};
    use std::path::PathBuf;
    use std::process::{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)))
    }

    #[test]
    fn read_test_process() {
        // Spawn a child process and attempt to read its memory.
        let child = Command::new(test_process_path().unwrap())
            .stdout(Stdio::piped())
            .spawn().unwrap();
        let handle = child.try_into_process_handle().unwrap();
        // The test program prints the address and size.
        // See `src/bin/test.rs` for its source.
        let reader = BufReader::new(child.stdout.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 = copy_address(addr, size, &handle).unwrap();
        assert_eq!(mem, (0..32u8).collect::<Vec<u8>>());
    }
}
<|endoftext|>


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

/*! Non-blocking access to stdin, stdout, and stderr.

This module provides bindings to the local event loop's TTY interface, using it
to offer synchronous but non-blocking versions of stdio. These handles can be
inspected for information about terminal dimensions or for related information
about the stream or terminal to which it is attached.

# Example

```rust
# #[allow(unused_must_use)];
use std::io;

let mut out = io::stdout();
out.write(bytes!("Hello, world!"));
```

*/

use container::Container;
use fmt;
use io::{Reader, Writer, IoResult, IoError, OtherIoError,
         standard_error, EndOfFile, LineBufferedWriter, BufferedReader};
use libc;
use mem::replace;
use option::{Option, Some, None};
use prelude::drop;
use result::{Ok, Err};
use rt::local::Local;
use rt::rtio::{DontClose, IoFactory, LocalIo, RtioFileStream, RtioTTY};
use rt::task::Task;
use str::StrSlice;
use vec::ImmutableVector;

// And so begins the tale of acquiring a uv handle to a stdio stream on all
// platforms in all situations. Our story begins by splitting the world into two
// categories, windows and unix. Then one day the creators of unix said let
// there be redirection! And henceforth there was redirection away from the
// console for standard I/O streams.
//
// After this day, the world split into four factions:
//
// 1. Unix with stdout on a terminal.
// 2. Unix with stdout redirected.
// 3. Windows with stdout on a terminal.
// 4. Windows with stdout redirected.
//
// Many years passed, and then one day the nation of libuv decided to unify this
// world. After months of toiling, uv created three ideas: TTY, Pipe, File.
// These three ideas propagated throughout the lands and the four great factions
// decided to settle among them.
//
// The groups of 1, 2, and 3 all worked very hard towards the idea of TTY. Upon
// doing so, they even enhanced themselves further then their Pipe/File
// brethren, becoming the dominant powers.
//
// The group of 4, however, decided to work independently. They abandoned the
// common TTY belief throughout, and even abandoned the fledgling Pipe belief.
// The members of the 4th faction decided to only align themselves with File.
//
// tl;dr; TTY works on everything but when windows stdout is redirected, in that
//        case pipe also doesn't work, but magically file does!
enum StdSource {
    TTY(~RtioTTY),
    File(~RtioFileStream),
}

fn src<T>(fd: libc::c_int, readable: bool, f: |StdSource| -> T) -> T {
    LocalIo::maybe_raise(|io| {
        Ok(match io.tty_open(fd, readable) {
            Ok(tty) => f(TTY(tty)),
            Err(_) => f(File(io.fs_from_raw_fd(fd, DontClose))),
        })
    }).unwrap()
}

/// Creates a new non-blocking handle to the stdin of the current process.
///
/// The returned handled is buffered by default with a `BufferedReader`. If
/// buffered access is not desired, the `stdin_raw` function is provided to
/// provided unbuffered access to stdin.
///
/// Care should be taken when creating multiple handles to the stdin of a
/// process. Beause this is a buffered reader by default, it's possible for
/// pending input to be unconsumed in one reader and unavailable to other
/// readers. It is recommended that only one handle at a time is created for the
/// stdin of a process.
///
/// See `stdout()` for more notes about this function.
pub fn stdin() -> BufferedReader<StdReader> {
    BufferedReader::new(stdin_raw())
}

/// Creates a new non-blocking handle to the stdin of the current process.
///
/// Unlike `stdin()`, the returned reader is *not* a buffered reader.
///
/// See `stdout()` for more notes about this function.
pub fn stdin_raw() -> StdReader {
    src(libc::STDIN_FILENO, true, |src| StdReader { inner: src })
}

/// Creates a line-buffered handle to the stdout of the current process.
///
/// Note that this is a fairly expensive operation in that at least one memory
/// allocation is performed. Additionally, this must be called from a runtime
/// task context because the stream returned will be a non-blocking object using
/// the local scheduler to perform the I/O.
///
/// Care should be taken when creating multiple handles to an output stream for
/// a single process. While usage is still safe, the output may be surprising if
/// no synchronization is performed to ensure a sane output.
pub fn stdout() -> LineBufferedWriter<StdWriter> {
    LineBufferedWriter::new(stdout_raw())
}

/// Creates an unbuffered handle to the stdout of the current process
///
/// See notes in `stdout()` for more information.
pub fn stdout_raw() -> StdWriter {
    src(libc::STDOUT_FILENO, false, |src| StdWriter { inner: src })
}

/// Creates a line-buffered handle to the stderr of the current process.
///
/// See `stdout()` for notes about this function.
pub fn stderr() -> LineBufferedWriter<StdWriter> {
    LineBufferedWriter::new(stderr_raw())
}

/// Creates an unbuffered handle to the stderr of the current process
///
/// See notes in `stdout()` for more information.
pub fn stderr_raw() -> StdWriter {
    src(libc::STDERR_FILENO, false, |src| StdWriter { inner: src })
}

fn reset_helper(w: ~Writer,
                f: |&mut Task, ~Writer| -> Option<~Writer>) -> Option<~Writer> {
    let mut t = Local::borrow(None::<Task>);
    // Be sure to flush any pending output from the writer
    match f(t.get(), w) {
        Some(mut w) => {
            drop(t);
            // FIXME: is failing right here?
            w.flush().unwrap();
            Some(w)
        }
        None => None
    }
}

/// Resets the task-local stdout handle to the specified writer
///
/// This will replace the current task's stdout handle, returning the old
/// handle. All future calls to `print` and friends will emit their output to
/// this specified handle.
///
/// Note that this does not need to be called for all new tasks; the default
/// output handle is to the process's stdout stream.
pub fn set_stdout(stdout: ~Writer) -> Option<~Writer> {
    reset_helper(stdout, |t, w| replace(&mut t.stdout, Some(w)))
}

/// Resets the task-local stderr handle to the specified writer
///
/// This will replace the current task's stderr handle, returning the old
/// handle. Currently, the stderr handle is used for printing failure messages
/// during task failure.
///
/// Note that this does not need to be called for all new tasks; the default
/// output handle is to the process's stderr stream.
pub fn set_stderr(stderr: ~Writer) -> Option<~Writer> {
    reset_helper(stderr, |t, w| replace(&mut t.stderr, Some(w)))
}

// Helper to access the local task's stdout handle
//
// Note that this is not a safe function to expose because you can create an
// aliased pointer very easily:
//
//  with_task_stdout(|io1| {
//      with_task_stdout(|io2| {
//          // io1 aliases io2
//      })
//  })
fn with_task_stdout(f: |&mut Writer| -> IoResult<()> ) {
    let task: Option<~Task> = Local::try_take();
    let result = match task {
        Some(mut task) => {
            // Printing may run arbitrary code, so ensure that the task is in
            // TLS to allow all std services. Note that this means a print while
            // printing won't use the task's normal stdout handle, but this is
            // necessary to ensure safety (no aliasing).
            let mut my_stdout = task.stdout.take();
            Local::put(task);

            if my_stdout.is_none() {
                my_stdout = Some(~stdout() as ~Writer);
            }
            let ret = f(*my_stdout.get_mut_ref());

            // Note that we need to be careful when putting the stdout handle
            // back into the task. If the handle was set to `Some` while
            // printing, then we can run aribitrary code when destroying the
            // previous handle. This means that the local task needs to be in
            // TLS while we do this.
            //
            // To protect against this, we do a little dance in which we
            // temporarily take the task, swap the handles, put the task in TLS,
            // and only then drop the previous handle.
            let mut t = Local::borrow(None::<Task>);
            let prev = replace(&mut t.get().stdout, my_stdout);
            drop(t);
            drop(prev);
            ret
        }

        None => {
            struct Stdout;
            impl Writer for Stdout {
                fn write(&mut self, data: &[u8]) -> IoResult<()> {
                    unsafe {
                        libc::write(libc::STDOUT_FILENO,
                                    data.as_ptr() as *libc::c_void,
                                    data.len() as libc::size_t);
                    }
                    Ok(()) // just ignore the results
                }
            }
            let mut io = Stdout;
            f(&mut io as &mut Writer)
        }
    };

    match result {
        Ok(()) => {}
        Err(e) => fail!("failed printing to stdout: {}", e),
    }
}

/// Flushes the local task's stdout handle.
///
/// By default, this stream is a line-buffering stream, so flushing may be
/// necessary to ensure that all output is printed to the screen (if there are
/// no newlines printed).
///
/// Note that logging macros do not use this stream. Using the logging macros
/// will emit output to stderr, and while they are line buffered the log
/// messages are always terminated in a newline (no need to flush).
pub fn flush() {
    with_task_stdout(|io| io.flush())
}

/// Prints a string to the stdout of the current process. No newline is emitted
/// after the string is printed.
pub fn print(s: &str) {
    with_task_stdout(|io| io.write(s.as_bytes()))
}

/// Prints a string as a line. to the stdout of the current process. A literal
/// `\n` character is printed to the console after the string.
pub fn println(s: &str) {
    with_task_stdout(|io| {
        io.write(s.as_bytes()).and_then(|()| io.write(['\n' as u8]))
    })
}

/// Similar to `print`, but takes a `fmt::Arguments` structure to be compatible
/// with the `format_args!` macro.
pub fn print_args(fmt: &fmt::Arguments) {
    with_task_stdout(|io| fmt::write(io, fmt))
}

/// Similar to `println`, but takes a `fmt::Arguments` structure to be
/// compatible with the `format_args!` macro.
pub fn println_args(fmt: &fmt::Arguments) {
    with_task_stdout(|io| fmt::writeln(io, fmt))
}

/// Representation of a reader of a standard input stream
pub struct StdReader {
    priv inner: StdSource
}

impl Reader for StdReader {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        let ret = match self.inner {
            TTY(ref mut tty) => tty.read(buf),
            File(ref mut file) => file.read(buf).map(|i| i as uint),
        };
        match ret {
            // When reading a piped stdin, libuv will return 0-length reads when
            // stdin reaches EOF. For pretty much all other streams it will
            // return an actual EOF error, but apparently for stdin it's a
            // little different. Hence, here we convert a 0 length read to an
            // end-of-file indicator so the caller knows to stop reading.
            Ok(0) => { Err(standard_error(EndOfFile)) }
            ret @ Ok(..) | ret @ Err(..) => ret,
        }
    }
}

/// Representation of a writer to a standard output stream
pub struct StdWriter {
    priv inner: StdSource
}

impl StdWriter {
    /// Gets the size of this output window, if possible. This is typically used
    /// when the writer is attached to something like a terminal, this is used
    /// to fetch the dimensions of the terminal.
    ///
    /// If successful, returns `Ok((width, height))`.
    ///
    /// # Error
    ///
    /// This function will return an error if the output stream is not actually
    /// connected to a TTY instance, or if querying the TTY instance fails.
    pub fn winsize(&mut self) -> IoResult<(int, int)> {
        match self.inner {
            TTY(ref mut tty) => tty.get_winsize(),
            File(..) => {
                Err(IoError {
                    kind: OtherIoError,
                    desc: "stream is not a tty",
                    detail: None,
                })
            }
        }
    }

    /// Controls whether this output stream is a "raw stream" or simply a normal
    /// stream.
    ///
    /// # Error
    ///
    /// This function will return an error if the output stream is not actually
    /// connected to a TTY instance, or if querying the TTY instance fails.
    pub fn set_raw(&mut self, raw: bool) -> IoResult<()> {
        match self.inner {
            TTY(ref mut tty) => tty.set_raw(raw),
            File(..) => {
                Err(IoError {
                    kind: OtherIoError,
                    desc: "stream is not a tty",
                    detail: None,
                })
            }
        }
    }

    /// Returns whether this stream is attached to a TTY instance or not.
    pub fn isatty(&self) -> bool {
        match self.inner {
            TTY(..) => true,
            File(..) => false,
        }
    }
}

impl Writer for StdWriter {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        match self.inner {
            TTY(ref mut tty) => tty.write(buf),
            File(ref mut file) => file.write(buf),
        }
    }
}

#[cfg(test)]
mod tests {
    iotest!(fn smoke() {
        // Just make sure we can acquire handles
        stdin();
        stdout();
        stderr();
    })

    iotest!(fn capture_stdout() {
        use io::{ChanReader, ChanWriter};

        let (tx, rx) = channel();
        let (mut r, w) = (ChanReader::new(rx), ChanWriter::new(tx));
        spawn(proc() {
            set_stdout(~w as ~Writer);
            println!("hello!");
        });
        assert_eq!(r.read_to_str().unwrap(), ~"hello!\n");
    })

    iotest!(fn capture_stderr() {
        use io::{ChanReader, ChanWriter};

        let (tx, rx) = channel();
        let (mut r, w) = (ChanReader::new(rx), ChanWriter::new(tx));
        spawn(proc() {
            set_stderr(~w as ~Writer);
            fail!("my special message");
        });
        let s = r.read_to_str().unwrap();
        assert!(s.contains("my special message"));
    })
}
<commit_msg>std: io: flush stdout on stdin read from tty<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*! Non-blocking access to stdin, stdout, and stderr.

This module provides bindings to the local event loop's TTY interface, using it
to offer synchronous but non-blocking versions of stdio. These handles can be
inspected for information about terminal dimensions or for related information
about the stream or terminal to which it is attached.

# Example

```rust
# #[allow(unused_must_use)];
use std::io;

let mut out = io::stdout();
out.write(bytes!("Hello, world!"));
```

*/

use container::Container;
use fmt;
use io::{Reader, Writer, IoResult, IoError, OtherIoError,
         standard_error, EndOfFile, LineBufferedWriter, BufferedReader};
use libc;
use mem::replace;
use option::{Option, Some, None};
use prelude::drop;
use result::{Ok, Err};
use rt::local::Local;
use rt::rtio::{DontClose, IoFactory, LocalIo, RtioFileStream, RtioTTY};
use rt::task::Task;
use str::StrSlice;
use vec::ImmutableVector;

// And so begins the tale of acquiring a uv handle to a stdio stream on all
// platforms in all situations. Our story begins by splitting the world into two
// categories, windows and unix. Then one day the creators of unix said let
// there be redirection! And henceforth there was redirection away from the
// console for standard I/O streams.
//
// After this day, the world split into four factions:
//
// 1. Unix with stdout on a terminal.
// 2. Unix with stdout redirected.
// 3. Windows with stdout on a terminal.
// 4. Windows with stdout redirected.
//
// Many years passed, and then one day the nation of libuv decided to unify this
// world. After months of toiling, uv created three ideas: TTY, Pipe, File.
// These three ideas propagated throughout the lands and the four great factions
// decided to settle among them.
//
// The groups of 1, 2, and 3 all worked very hard towards the idea of TTY. Upon
// doing so, they even enhanced themselves further then their Pipe/File
// brethren, becoming the dominant powers.
//
// The group of 4, however, decided to work independently. They abandoned the
// common TTY belief throughout, and even abandoned the fledgling Pipe belief.
// The members of the 4th faction decided to only align themselves with File.
//
// tl;dr; TTY works on everything but when windows stdout is redirected, in that
//        case pipe also doesn't work, but magically file does!
enum StdSource {
    TTY(~RtioTTY),
    File(~RtioFileStream),
}

fn src<T>(fd: libc::c_int, readable: bool, f: |StdSource| -> T) -> T {
    LocalIo::maybe_raise(|io| {
        Ok(match io.tty_open(fd, readable) {
            Ok(tty) => f(TTY(tty)),
            Err(_) => f(File(io.fs_from_raw_fd(fd, DontClose))),
        })
    }).unwrap()
}

/// Creates a new non-blocking handle to the stdin of the current process.
///
/// The returned handled is buffered by default with a `BufferedReader`. If
/// buffered access is not desired, the `stdin_raw` function is provided to
/// provided unbuffered access to stdin.
///
/// Care should be taken when creating multiple handles to the stdin of a
/// process. Beause this is a buffered reader by default, it's possible for
/// pending input to be unconsumed in one reader and unavailable to other
/// readers. It is recommended that only one handle at a time is created for the
/// stdin of a process.
///
/// See `stdout()` for more notes about this function.
pub fn stdin() -> BufferedReader<StdReader> {
    BufferedReader::new(stdin_raw())
}

/// Creates a new non-blocking handle to the stdin of the current process.
///
/// Unlike `stdin()`, the returned reader is *not* a buffered reader.
///
/// See `stdout()` for more notes about this function.
pub fn stdin_raw() -> StdReader {
    src(libc::STDIN_FILENO, true, |src| StdReader { inner: src })
}

/// Creates a line-buffered handle to the stdout of the current process.
///
/// Note that this is a fairly expensive operation in that at least one memory
/// allocation is performed. Additionally, this must be called from a runtime
/// task context because the stream returned will be a non-blocking object using
/// the local scheduler to perform the I/O.
///
/// Care should be taken when creating multiple handles to an output stream for
/// a single process. While usage is still safe, the output may be surprising if
/// no synchronization is performed to ensure a sane output.
pub fn stdout() -> LineBufferedWriter<StdWriter> {
    LineBufferedWriter::new(stdout_raw())
}

/// Creates an unbuffered handle to the stdout of the current process
///
/// See notes in `stdout()` for more information.
pub fn stdout_raw() -> StdWriter {
    src(libc::STDOUT_FILENO, false, |src| StdWriter { inner: src })
}

/// Creates a line-buffered handle to the stderr of the current process.
///
/// See `stdout()` for notes about this function.
pub fn stderr() -> LineBufferedWriter<StdWriter> {
    LineBufferedWriter::new(stderr_raw())
}

/// Creates an unbuffered handle to the stderr of the current process
///
/// See notes in `stdout()` for more information.
pub fn stderr_raw() -> StdWriter {
    src(libc::STDERR_FILENO, false, |src| StdWriter { inner: src })
}

fn reset_helper(w: ~Writer,
                f: |&mut Task, ~Writer| -> Option<~Writer>) -> Option<~Writer> {
    let mut t = Local::borrow(None::<Task>);
    // Be sure to flush any pending output from the writer
    match f(t.get(), w) {
        Some(mut w) => {
            drop(t);
            // FIXME: is failing right here?
            w.flush().unwrap();
            Some(w)
        }
        None => None
    }
}

/// Resets the task-local stdout handle to the specified writer
///
/// This will replace the current task's stdout handle, returning the old
/// handle. All future calls to `print` and friends will emit their output to
/// this specified handle.
///
/// Note that this does not need to be called for all new tasks; the default
/// output handle is to the process's stdout stream.
pub fn set_stdout(stdout: ~Writer) -> Option<~Writer> {
    reset_helper(stdout, |t, w| replace(&mut t.stdout, Some(w)))
}

/// Resets the task-local stderr handle to the specified writer
///
/// This will replace the current task's stderr handle, returning the old
/// handle. Currently, the stderr handle is used for printing failure messages
/// during task failure.
///
/// Note that this does not need to be called for all new tasks; the default
/// output handle is to the process's stderr stream.
pub fn set_stderr(stderr: ~Writer) -> Option<~Writer> {
    reset_helper(stderr, |t, w| replace(&mut t.stderr, Some(w)))
}

// Helper to access the local task's stdout handle
//
// Note that this is not a safe function to expose because you can create an
// aliased pointer very easily:
//
//  with_task_stdout(|io1| {
//      with_task_stdout(|io2| {
//          // io1 aliases io2
//      })
//  })
fn with_task_stdout(f: |&mut Writer| -> IoResult<()> ) {
    let task: Option<~Task> = Local::try_take();
    let result = match task {
        Some(mut task) => {
            // Printing may run arbitrary code, so ensure that the task is in
            // TLS to allow all std services. Note that this means a print while
            // printing won't use the task's normal stdout handle, but this is
            // necessary to ensure safety (no aliasing).
            let mut my_stdout = task.stdout.take();
            Local::put(task);

            if my_stdout.is_none() {
                my_stdout = Some(~stdout() as ~Writer);
            }
            let ret = f(*my_stdout.get_mut_ref());

            // Note that we need to be careful when putting the stdout handle
            // back into the task. If the handle was set to `Some` while
            // printing, then we can run aribitrary code when destroying the
            // previous handle. This means that the local task needs to be in
            // TLS while we do this.
            //
            // To protect against this, we do a little dance in which we
            // temporarily take the task, swap the handles, put the task in TLS,
            // and only then drop the previous handle.
            let mut t = Local::borrow(None::<Task>);
            let prev = replace(&mut t.get().stdout, my_stdout);
            drop(t);
            drop(prev);
            ret
        }

        None => {
            struct Stdout;
            impl Writer for Stdout {
                fn write(&mut self, data: &[u8]) -> IoResult<()> {
                    unsafe {
                        libc::write(libc::STDOUT_FILENO,
                                    data.as_ptr() as *libc::c_void,
                                    data.len() as libc::size_t);
                    }
                    Ok(()) // just ignore the results
                }
            }
            let mut io = Stdout;
            f(&mut io as &mut Writer)
        }
    };

    match result {
        Ok(()) => {}
        Err(e) => fail!("failed printing to stdout: {}", e),
    }
}

/// Flushes the local task's stdout handle.
///
/// By default, this stream is a line-buffering stream, so flushing may be
/// necessary to ensure that all output is printed to the screen (if there are
/// no newlines printed).
///
/// Note that logging macros do not use this stream. Using the logging macros
/// will emit output to stderr, and while they are line buffered the log
/// messages are always terminated in a newline (no need to flush).
pub fn flush() {
    with_task_stdout(|io| io.flush())
}

/// Prints a string to the stdout of the current process. No newline is emitted
/// after the string is printed.
pub fn print(s: &str) {
    with_task_stdout(|io| io.write(s.as_bytes()))
}

/// Prints a string as a line. to the stdout of the current process. A literal
/// `\n` character is printed to the console after the string.
pub fn println(s: &str) {
    with_task_stdout(|io| {
        io.write(s.as_bytes()).and_then(|()| io.write(['\n' as u8]))
    })
}

/// Similar to `print`, but takes a `fmt::Arguments` structure to be compatible
/// with the `format_args!` macro.
pub fn print_args(fmt: &fmt::Arguments) {
    with_task_stdout(|io| fmt::write(io, fmt))
}

/// Similar to `println`, but takes a `fmt::Arguments` structure to be
/// compatible with the `format_args!` macro.
pub fn println_args(fmt: &fmt::Arguments) {
    with_task_stdout(|io| fmt::writeln(io, fmt))
}

/// Representation of a reader of a standard input stream
pub struct StdReader {
    priv inner: StdSource
}

impl Reader for StdReader {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        let ret = match self.inner {
            TTY(ref mut tty) => {
                // Flush the task-local stdout so that weird issues like a
                // print!'d prompt not being shown until after the user hits
                // enter.
                flush();
                tty.read(buf)
            },
            File(ref mut file) => file.read(buf).map(|i| i as uint),
        };
        match ret {
            // When reading a piped stdin, libuv will return 0-length reads when
            // stdin reaches EOF. For pretty much all other streams it will
            // return an actual EOF error, but apparently for stdin it's a
            // little different. Hence, here we convert a 0 length read to an
            // end-of-file indicator so the caller knows to stop reading.
            Ok(0) => { Err(standard_error(EndOfFile)) }
            ret @ Ok(..) | ret @ Err(..) => ret,
        }
    }
}

/// Representation of a writer to a standard output stream
pub struct StdWriter {
    priv inner: StdSource
}

impl StdWriter {
    /// Gets the size of this output window, if possible. This is typically used
    /// when the writer is attached to something like a terminal, this is used
    /// to fetch the dimensions of the terminal.
    ///
    /// If successful, returns `Ok((width, height))`.
    ///
    /// # Error
    ///
    /// This function will return an error if the output stream is not actually
    /// connected to a TTY instance, or if querying the TTY instance fails.
    pub fn winsize(&mut self) -> IoResult<(int, int)> {
        match self.inner {
            TTY(ref mut tty) => tty.get_winsize(),
            File(..) => {
                Err(IoError {
                    kind: OtherIoError,
                    desc: "stream is not a tty",
                    detail: None,
                })
            }
        }
    }

    /// Controls whether this output stream is a "raw stream" or simply a normal
    /// stream.
    ///
    /// # Error
    ///
    /// This function will return an error if the output stream is not actually
    /// connected to a TTY instance, or if querying the TTY instance fails.
    pub fn set_raw(&mut self, raw: bool) -> IoResult<()> {
        match self.inner {
            TTY(ref mut tty) => tty.set_raw(raw),
            File(..) => {
                Err(IoError {
                    kind: OtherIoError,
                    desc: "stream is not a tty",
                    detail: None,
                })
            }
        }
    }

    /// Returns whether this stream is attached to a TTY instance or not.
    pub fn isatty(&self) -> bool {
        match self.inner {
            TTY(..) => true,
            File(..) => false,
        }
    }
}

impl Writer for StdWriter {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        match self.inner {
            TTY(ref mut tty) => tty.write(buf),
            File(ref mut file) => file.write(buf),
        }
    }
}

#[cfg(test)]
mod tests {
    iotest!(fn smoke() {
        // Just make sure we can acquire handles
        stdin();
        stdout();
        stderr();
    })

    iotest!(fn capture_stdout() {
        use io::{ChanReader, ChanWriter};

        let (tx, rx) = channel();
        let (mut r, w) = (ChanReader::new(rx), ChanWriter::new(tx));
        spawn(proc() {
            set_stdout(~w as ~Writer);
            println!("hello!");
        });
        assert_eq!(r.read_to_str().unwrap(), ~"hello!\n");
    })

    iotest!(fn capture_stderr() {
        use io::{ChanReader, ChanWriter};

        let (tx, rx) = channel();
        let (mut r, w) = (ChanReader::new(rx), ChanWriter::new(tx));
        spawn(proc() {
            set_stderr(~w as ~Writer);
            fail!("my special message");
        });
        let s = r.read_to_str().unwrap();
        assert!(s.contains("my special message"));
    })
}
<|endoftext|>


<commit_before>mod STM {
    use std::result::Result as Either;
    use std::mem::{transmute, forget, uninitialized};
    use std::ptr::swap;
    /// We cannot make a real monad, so this is going to be a fake linear type a la Clean.
    pub struct Result(Either);

    impl Result {
        pub fn ret(a: A) -> Result {
            Result(Either::Ok(a))
        }

        pub fn abort() -> Result {
            Result(Either::Err(()))
        }

        /// just don't look
        pub fn spec_move(mut self) -> Either {
            unsafe {
                let mut x = uninitialized();
                swap(&mut x, transmute(&mut self));
                forget(self);
                x
            }
        }

        pub fn bind(self, f : F) -> Result where F : FnOnce(A) -> Result {
            Result(self.spec_move().and_then(|x| f(x).spec_move()))
        }
    }

    impl Drop for Result {
        // Best we can do absent a true linear type
        fn drop(&mut self) {
            panic!()
        }
    }

    trait Stm {
        /// A hook for transaction-local state
        type LocalState;

        fn run(&self, F) -> A
            where F: FnMut(&mut Self::LocalState) -> Result,
                  Self::LocalState: StmHelper;

        fn or_else(&self, F, G) -> Result
            where F: FnMut(&mut Self::LocalState) -> Result,
                  G: FnMut(&mut Self::LocalState) -> Result,
                  Self::LocalState: StmHelper;
    }

    trait StmHelper {
        /// A wrapper around an object whose access is mediated by the STM implementation
        type TVar;

        /// Read/Write need to return Result
        fn read(&mut self, Self::TVar) -> A;

        fn write(&mut self, Self::TVar, A);
    }
}
mod NoRec {
    use std::sync::atomic::{AtomicUsize, Ordering};
    use std::vec::Vec;
    use std::collections::HashMap;
    use std::cell::UnsafeCell;
    use std::marker::PhantomData;
    use STM;

    struct GlobalState {
        version : AtomicUsize
    }

    #[derive(Hash, Eq, PartialEq, Debug, Clone)]
    /// Lies... Lies
    struct TVarAddr<'a, 'b : 'a>(*mut (), PhantomData<&'a TVar<'b, ()>>);

<<<<<<< HEAD
    struct LocalState<'v, 'g : 'v> {
        /// the norec paper has the reads stored as a list of <address, value> pairs. For us it
        /// would probably be better to have versioned TVars. That way we always have a fast
        /// comparison operation and avoid doing extra dynamic dispatch when validating reads.
        reads : Vec<(TVarAddr<'v, 'g>, usize)>,

        /// for writes we will probably have to cast unsafely to get this to work. TVars just hold
        /// arbitrary types and we only have one table.
        /// XXX: gross
        writes : HashMap<TVarAddr<'v, 'g>, Box<[u8]>>,

        /// STM environment we are using
        global : &'g GlobalState,

        /// last version at which our view of the global state was valid
        snapshot : usize
    }

    impl<'v, 'g : 'v> LocalState<'v, 'g> {
        /*
         * while (true)
         * time = global lock
         * if ((time&1)!=0)
         *  continue
         * for each (addr, val) in reads
         *      if (∗addr != val)
         *          TXAbort() // abort will longjmp if (time == global lock)
         * return time
         */
        fn validate(&mut self, glob : &'g GlobalState) -> STM::Result<()> {
            loop {
                let time = glob.version.load(Ordering::SeqCst);
            }
            STM::Result::abort()
        }
    }

    struct TVar<'a,A> {
        version : AtomicUsize,
        val : UnsafeCell,
        global : &'a GlobalState
    }

    impl<'a, A> TVar<'a, A> {
        unsafe fn getVal(&self) -> &mut A {
            &mut *self.val.get()
        }
    }
}

#[test]
fn it_works() {
}
<commit_msg>added validate function<commit_after>mod STM {
    use std::result::Result as Either;
    use std::mem::{transmute, forget, uninitialized};
    use std::ptr::swap;
    /// We cannot make a real monad, so this is going to be a fake linear type a la Clean.
    pub struct Result(Either);

    impl Result {
        pub fn ret(a: A) -> Result {
            Result(Either::Ok(a))
        }

        pub fn abort() -> Result {
            Result(Either::Err(()))
        }

        /// just don't look
        pub fn spec_move(mut self) -> Either {
            unsafe {
                let mut x = uninitialized();
                swap(&mut x, transmute(&mut self));
                forget(self);
                x
            }
        }

        pub fn bind(self, f : F) -> Result where F : FnOnce(A) -> Result {
            Result(self.spec_move().and_then(|x| f(x).spec_move()))
        }
    }

    impl Drop for Result {
        // Best we can do absent a true linear type
        fn drop(&mut self) {
            panic!()
        }
    }

    trait Stm {
        /// A hook for transaction-local state
        type LocalState;

        fn run(&self, F) -> A
            where F: FnMut(&mut Self::LocalState) -> Result,
                  Self::LocalState: StmHelper;

        fn or_else(&self, F, G) -> Result
            where F: FnMut(&mut Self::LocalState) -> Result,
                  G: FnMut(&mut Self::LocalState) -> Result,
                  Self::LocalState: StmHelper;
    }

    trait StmHelper {
        /// A wrapper around an object whose access is mediated by the STM implementation
        type TVar;

        /// Read/Write need to return Result
        fn read(&mut self, Self::TVar) -> A;

        fn write(&mut self, Self::TVar, A);
    }
}
mod NoRec {
    use std::sync::atomic::{AtomicUsize, Ordering};
    use std::vec::Vec;
    use std::collections::HashMap;
    use std::cell::UnsafeCell;
    use std::marker::PhantomData;
    use std::mem::{transmute, forget, uninitialized};
    use STM;

    struct GlobalState {
        version : AtomicUsize
    }

    #[derive(Hash, Eq, PartialEq, Debug, Clone)]
    /// Lies... Lies
    struct TVarAddr<'a, 'b : 'a>(*mut TVar<'b, ()>, PhantomData<&'a TVar<'b, ()>>);

    struct LocalState<'v, 'g : 'v> {
        /// the norec paper has the reads stored as a list of <address, value> pairs. For us it
        /// would probably be better to have versioned TVars. That way we always have a fast
        /// comparison operation and avoid doing extra dynamic dispatch when validating reads.
        reads : Vec<(TVarAddr<'v, 'g>, usize)>,

        /// for writes we will probably have to cast unsafely to get this to work. TVars just hold
        /// arbitrary types and we only have one table.
        /// XXX: gross
        writes : HashMap<TVarAddr<'v, 'g>, Box<[u8]>>,

        /// STM environment we are using
        global : &'g GlobalState,

        /// last version at which our view of the global state was valid
        snapshot : usize
    }

    impl<'v, 'g : 'v> LocalState<'v, 'g> {
        /*
         * while (true)
         * time = global lock
         * if ((time&1)!=0)
         *  continue
         * for each (addr, val) in reads
         *      if (∗addr != val)
         *          TXAbort() // abort will longjmp if (time == global lock)
         * return time
         */
        fn validate(&mut self, glob : &'g GlobalState) -> STM::Result<()> {
            loop {
                let time = glob.version.load(Ordering::SeqCst);
                if (time & 1) == 0 {
                    continue;
                }
                for &(ref addr, ref version) in self.reads.iter() {
                    unsafe {
                        let v = addr.0.clone();
                        if (*v).version.load(Ordering::SeqCst) != *version {
                            return STM::Result::abort();
                        }
                    }
                }
                return STM::Result::ret(());
            }
        }
    }

    struct TVar<'a,A> {
        version : AtomicUsize,
        val : UnsafeCell,
        global : &'a GlobalState
    }

    impl<'a, A> TVar<'a, A> {
        unsafe fn get_val(&self) -> &mut A {
            &mut *self.val.get()
        }
    }
}

#[test]
fn it_works() {
}
<|endoftext|>


<commit_before>//! Space API definitions and serialization.
//!
//! This crate contains all data-related definitions that are present in the Space API
//! (http://spaceapi.net/). It also handles serializing that data to JSON by implementing the
//! [`ToJson`](http://doc.rust-lang.org/rustc-serialize/rustc_serialize/json/trait.ToJson.html)
//! trait for all structs.
//!
//! # Examples
//!
//! You can create a new ``Status`` instance by using the ``new()`` constructor method. To serialize
//! this to [``Json``](http://doc.rust-lang.org/rustc-serialize/rustc_serialize/json/enum.Json.html), use
//! the [`ToJson`](http://doc.rust-lang.org/rustc-serialize/rustc_serialize/json/trait.ToJson.html)
//! trait implementation. You can then create a string from the resulting object.
//!
//!     # extern crate rustc_serialize;
//!     # extern crate spaceapi;
//!     # use spaceapi::{Status, Location, Contact};
//!     # use spaceapi::optional::Optional;
//!     use rustc_serialize::json::ToJson;
//!
//!     # fn main() {
//!     let status = Status::new(
//!         "coredump".to_string(),
//!         "https://www.coredump.ch/logo.png".to_string(),
//!         "https://www.coredump.ch/".to_string(),
//!         Location {
//!             address: Optional::Value("Spinnereistrasse 2, 8640 Rapperswil, Switzerland".to_string()),
//!             lat: 47.22936,
//!             lon: 8.82949,
//!         },
//!         Contact {
//!             irc: Optional::Value("irc://freenode.net/#coredump".to_string()),
//!             twitter: Optional::Value("@coredump_ch".to_string()),
//!             foursquare: Optional::Value("525c20e5498e875d8231b1e5".to_string()),
//!             email: Optional::Value("danilo@coredump.ch".to_string()),
//!         },
//!         vec![
//!             "email".to_string(),
//!             "twitter".to_string(),
//!         ],
//!     );
//!
//!     let jsonstatus = status.to_json();
//!     let stringstatus = jsonstatus.to_string();
//!     # }

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

pub mod optional;
pub mod sensors;
mod status;
pub use status::*;

<commit_msg>Add information about supported Space API version<commit_after>//! Space API definitions and serialization.
//!
//! This crate contains all data-related definitions that are present in the Space API
//! (http://spaceapi.net/). It also handles serializing that data to JSON by implementing the
//! [`ToJson`](http://doc.rust-lang.org/rustc-serialize/rustc_serialize/json/trait.ToJson.html)
//! trait for all structs.
//!
//! The currently supported Space API version is 0.13. It is not yet fully implemented.
//!
//! # Examples
//!
//! You can create a new ``Status`` instance by using the ``new()`` constructor method. To serialize
//! this to [``Json``](http://doc.rust-lang.org/rustc-serialize/rustc_serialize/json/enum.Json.html), use
//! the [`ToJson`](http://doc.rust-lang.org/rustc-serialize/rustc_serialize/json/trait.ToJson.html)
//! trait implementation. You can then create a string from the resulting object.
//!
//!     # extern crate rustc_serialize;
//!     # extern crate spaceapi;
//!     # use spaceapi::{Status, Location, Contact};
//!     # use spaceapi::optional::Optional;
//!     use rustc_serialize::json::ToJson;
//!
//!     # fn main() {
//!     let status = Status::new(
//!         "coredump".to_string(),
//!         "https://www.coredump.ch/logo.png".to_string(),
//!         "https://www.coredump.ch/".to_string(),
//!         Location {
//!             address: Optional::Value("Spinnereistrasse 2, 8640 Rapperswil, Switzerland".to_string()),
//!             lat: 47.22936,
//!             lon: 8.82949,
//!         },
//!         Contact {
//!             irc: Optional::Value("irc://freenode.net/#coredump".to_string()),
//!             twitter: Optional::Value("@coredump_ch".to_string()),
//!             foursquare: Optional::Value("525c20e5498e875d8231b1e5".to_string()),
//!             email: Optional::Value("danilo@coredump.ch".to_string()),
//!         },
//!         vec![
//!             "email".to_string(),
//!             "twitter".to_string(),
//!         ],
//!     );
//!
//!     let jsonstatus = status.to_json();
//!     let stringstatus = jsonstatus.to_string();
//!     # }

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

pub mod optional;
pub mod sensors;
mod status;
pub use status::*;
<|endoftext|>


<commit_before>//! libc - Raw FFI bindings to platforms' system libraries
//!
//! [Documentation for other platforms][pd].
//!
//! [pd]: https://rust-lang.github.io/libc/#platform-specific-documentation
#![crate_name = "libc"]
#![crate_type = "rlib"]
#![allow(
    renamed_and_removed_lints, // Keep this order.
    unknown_lints, // Keep this order.
    bad_style,
    overflowing_literals,
    improper_ctypes,
    // This lint is renamed but we run CI for old stable rustc so should be here.
    redundant_semicolon,
    redundant_semicolons
)]
#![cfg_attr(libc_deny_warnings, deny(warnings))]
// Attributes needed when building as part of the standard library
#![cfg_attr(feature = "rustc-dep-of-std", feature(link_cfg, no_core))]
#![cfg_attr(libc_thread_local, feature(thread_local))]
// Enable extra lints:
#![cfg_attr(feature = "extra_traits", deny(missing_debug_implementations))]
#![deny(missing_copy_implementations, safe_packed_borrows)]
#![cfg_attr(not(feature = "rustc-dep-of-std"), no_std)]
#![cfg_attr(feature = "rustc-dep-of-std", no_core)]
#![cfg_attr(
    any(feature = "rustc-dep-of-std", target_os = "redox"),
    feature(static_nobundle, native_link_modifiers, native_link_modifiers_bundle)
)]
#![cfg_attr(libc_const_extern_fn, feature(const_extern_fn))]

#[macro_use]
mod macros;

cfg_if! {
    if #[cfg(feature = "rustc-dep-of-std")] {
        extern crate rustc_std_workspace_core as core;
        #[allow(unused_imports)]
        use core::iter;
        #[allow(unused_imports)]
        use core::ops;
        #[allow(unused_imports)]
        use core::option;
    }
}

cfg_if! {
    if #[cfg(libc_priv_mod_use)] {
        #[cfg(libc_core_cvoid)]
        #[allow(unused_imports)]
        use core::ffi;
        #[allow(unused_imports)]
        use core::fmt;
        #[allow(unused_imports)]
        use core::hash;
        #[allow(unused_imports)]
        use core::num;
        #[allow(unused_imports)]
        use core::mem;
        #[doc(hidden)]
        #[allow(unused_imports)]
        use core::clone::Clone;
        #[doc(hidden)]
        #[allow(unused_imports)]
        use core::marker::{Copy, Send, Sync};
        #[doc(hidden)]
        #[allow(unused_imports)]
        use core::option::Option;
    } else {
        #[doc(hidden)]
        #[allow(unused_imports)]
        pub use core::fmt;
        #[doc(hidden)]
        #[allow(unused_imports)]
        pub use core::hash;
        #[doc(hidden)]
        #[allow(unused_imports)]
        pub use core::num;
        #[doc(hidden)]
        #[allow(unused_imports)]
        pub use core::mem;
        #[doc(hidden)]
        #[allow(unused_imports)]
        pub use core::clone::Clone;
        #[doc(hidden)]
        #[allow(unused_imports)]
        pub use core::marker::{Copy, Send, Sync};
        #[doc(hidden)]
        #[allow(unused_imports)]
        pub use core::option::Option;
    }
}

cfg_if! {
    if #[cfg(windows)] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod windows;
        pub use windows::*;
    } else if #[cfg(target_os = "fuchsia")] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod fuchsia;
        pub use fuchsia::*;
    } else if #[cfg(target_os = "switch")] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod switch;
        pub use switch::*;
    } else if #[cfg(target_os = "psp")] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod psp;
        pub use psp::*;
    } else if #[cfg(target_os = "vxworks")] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod vxworks;
        pub use vxworks::*;
    } else if #[cfg(target_os = "solid_asp3")] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod solid;
        pub use solid::*;
    } else if #[cfg(unix)] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod unix;
        pub use unix::*;
    } else if #[cfg(target_os = "hermit")] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod hermit;
        pub use hermit::*;
    } else if #[cfg(all(target_env = "sgx", target_vendor = "fortanix"))] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod sgx;
        pub use sgx::*;
    } else if #[cfg(any(target_env = "wasi", target_os = "wasi"))] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod wasi;
        pub use wasi::*;
    } else {
        // non-supported targets: empty...
    }
}
<commit_msg>Auto merge of #2728 - redox-os:redox-stable, r=Amanieu<commit_after>//! libc - Raw FFI bindings to platforms' system libraries
//!
//! [Documentation for other platforms][pd].
//!
//! [pd]: https://rust-lang.github.io/libc/#platform-specific-documentation
#![crate_name = "libc"]
#![crate_type = "rlib"]
#![allow(
    renamed_and_removed_lints, // Keep this order.
    unknown_lints, // Keep this order.
    bad_style,
    overflowing_literals,
    improper_ctypes,
    // This lint is renamed but we run CI for old stable rustc so should be here.
    redundant_semicolon,
    redundant_semicolons
)]
#![cfg_attr(libc_deny_warnings, deny(warnings))]
// Attributes needed when building as part of the standard library
#![cfg_attr(feature = "rustc-dep-of-std", feature(link_cfg, no_core))]
#![cfg_attr(libc_thread_local, feature(thread_local))]
// Enable extra lints:
#![cfg_attr(feature = "extra_traits", deny(missing_debug_implementations))]
#![deny(missing_copy_implementations, safe_packed_borrows)]
#![cfg_attr(not(feature = "rustc-dep-of-std"), no_std)]
#![cfg_attr(feature = "rustc-dep-of-std", no_core)]
#![cfg_attr(
    feature = "rustc-dep-of-std",
    feature(static_nobundle, native_link_modifiers, native_link_modifiers_bundle)
)]
#![cfg_attr(libc_const_extern_fn, feature(const_extern_fn))]

#[macro_use]
mod macros;

cfg_if! {
    if #[cfg(feature = "rustc-dep-of-std")] {
        extern crate rustc_std_workspace_core as core;
        #[allow(unused_imports)]
        use core::iter;
        #[allow(unused_imports)]
        use core::ops;
        #[allow(unused_imports)]
        use core::option;
    }
}

cfg_if! {
    if #[cfg(libc_priv_mod_use)] {
        #[cfg(libc_core_cvoid)]
        #[allow(unused_imports)]
        use core::ffi;
        #[allow(unused_imports)]
        use core::fmt;
        #[allow(unused_imports)]
        use core::hash;
        #[allow(unused_imports)]
        use core::num;
        #[allow(unused_imports)]
        use core::mem;
        #[doc(hidden)]
        #[allow(unused_imports)]
        use core::clone::Clone;
        #[doc(hidden)]
        #[allow(unused_imports)]
        use core::marker::{Copy, Send, Sync};
        #[doc(hidden)]
        #[allow(unused_imports)]
        use core::option::Option;
    } else {
        #[doc(hidden)]
        #[allow(unused_imports)]
        pub use core::fmt;
        #[doc(hidden)]
        #[allow(unused_imports)]
        pub use core::hash;
        #[doc(hidden)]
        #[allow(unused_imports)]
        pub use core::num;
        #[doc(hidden)]
        #[allow(unused_imports)]
        pub use core::mem;
        #[doc(hidden)]
        #[allow(unused_imports)]
        pub use core::clone::Clone;
        #[doc(hidden)]
        #[allow(unused_imports)]
        pub use core::marker::{Copy, Send, Sync};
        #[doc(hidden)]
        #[allow(unused_imports)]
        pub use core::option::Option;
    }
}

cfg_if! {
    if #[cfg(windows)] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod windows;
        pub use windows::*;
    } else if #[cfg(target_os = "fuchsia")] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod fuchsia;
        pub use fuchsia::*;
    } else if #[cfg(target_os = "switch")] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod switch;
        pub use switch::*;
    } else if #[cfg(target_os = "psp")] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod psp;
        pub use psp::*;
    } else if #[cfg(target_os = "vxworks")] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod vxworks;
        pub use vxworks::*;
    } else if #[cfg(target_os = "solid_asp3")] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod solid;
        pub use solid::*;
    } else if #[cfg(unix)] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod unix;
        pub use unix::*;
    } else if #[cfg(target_os = "hermit")] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod hermit;
        pub use hermit::*;
    } else if #[cfg(all(target_env = "sgx", target_vendor = "fortanix"))] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod sgx;
        pub use sgx::*;
    } else if #[cfg(any(target_env = "wasi", target_os = "wasi"))] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod wasi;
        pub use wasi::*;
    } else {
        // non-supported targets: empty...
    }
}
<|endoftext|>


<commit_before>/*!
Simple persistent generic HashMap/Key-value store, using file locking to limit
writing between threads.

This is in a beta state at the moment.

Basic usage:

```
extern crate typedb;

use typedb::{ KV, Value };

fn main() {
    let mut test_store = KV::<String, Value>::new("./basic.cab").unwrap();

    let _ = test_store.insert("key".to_string(), Value::String("value".to_string()));
    println!("{:?}", test_store.get(&"key".to_string()));
    let _ = test_store.remove(&"key".to_string());
}
```

Usage with user defined Key and Value types:

```
#[macro_use]
extern crate typedb;
#[macro_use]
extern crate serde_derive;

use typedb::KV;

key!(MyKey:
    String(String),
    Int(i32),
);

value!(MyValue:
    String(String),
    Int(i32),
);

fn main() {
    let mut test_store = KV::<MyKey, MyValue>::new("./types.cab").unwrap();

    let _ = test_store.insert(MyKey::Int(1i32), MyValue::String("value".to_string()));
    println!("{:?}", test_store.get(&MyKey::Int(1i32)));
    let _ = test_store.remove(&MyKey::Int(1i32));
}
```

*/

#![deny(missing_docs)]

extern crate bincode;
#[macro_use]
extern crate log;
extern crate persy;
extern crate serde;
#[macro_use]
extern crate serde_derive;

/// Macros for simplifying custom key and value types definition
pub mod macros;

use std::collections::HashMap;
use std::hash::Hash;
use std::io::ErrorKind;

use bincode::{deserialize, serialize};
use serde::ser::Serialize;
use serde::de::Deserialize;

use persy::{Config, PRes, Persy, PersyError};

/// A default value type to use with KV
#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
pub enum Value {
    /// Cab default Value type for strings
    String(String),
    /// Cab default Value type for intergers
    Int(i32),
    /// Cab default Value type for floats
    Float(f32),
    /// Cab default Value type for a sub map
    Map(HashMap<String, Value>),
    /// Cab default Value type for list
    List(Vec<Value>),
}

/// Type alias for results from KV
type KVResult = PRes<bool>;

/// Type alias for PersyError
type KVError = PersyError;

/// The type that represents the key-value store
pub struct KV<K, V> {
    cab: HashMap<K, V>,
    persy: Persy,
}

impl<K, V> KV<K, V>
where
    K: Clone + Serialize + for<'kde> Deserialize<'kde> + Eq + Hash,
    V: Clone + Serialize + for<'vde> Deserialize<'vde>,
{
    /// Creates a new instance of the KV store
    pub fn new(p: &'static str) -> Result<KV<K, V>, PersyError> {
        // create the KV instance
        match Persy::create(p) {
            Ok(o) => o,
            Err(PersyError::IO(ref e)) if e.kind() == ErrorKind::AlreadyExists => (),
            Err(e) => return Err(e),
        }
        let persy = Persy::open(p, Config::new())?;

        // if the segment doesn't exist create
        if !persy.exists_segment("tdb")? {
            let mut tx = persy.begin()?;
            persy.create_segment(&mut tx, "tdb")?;
            let prepared = persy.prepare_commit(tx)?;
            persy.commit(prepared)?;
        }

        let mut store = KV {
            cab: HashMap::new(),
            persy,
        };

        store.load_from_persist()?;

        Ok(store)
    }

    /// Inserta a key, value pair into the key-value store
    pub fn insert(&mut self, key: K, value: V) -> KVResult {
        // make sure mem version up to date
        self.load_from_persist()?;
        // insert into the HashMap
        self.cab.insert(key, value);
        // persist
        self.write_to_persist()
    }

    /// Get the value from a key
    pub fn get(&mut self, key: &K) -> Result<Option<V>, KVError> {
        // make sure mem version up to date
        self.load_from_persist()?;
        // get the value from the cab
        match self.cab.get(&key) {
            Some(v) => Ok(Some((*v).clone())),
            None => Ok(None),
        }
    }

    /// Removes a key and associated value from the key-value Store
    pub fn remove(&mut self, key: &K) -> KVResult {
        // make sure mem version up to date
        self.load_from_persist()?;
        // remove from the HashMap
        self.cab.remove(&key);
        // persist
        self.write_to_persist()
    }

    /// get all the keys contained in the KV Store
    pub fn keys(&mut self) -> Result<Vec<K>, KVError> {
        // make sure mem version up to date
        self.load_from_persist()?;
        // create a vec from the cabs keys
        Ok(self.cab.keys().map(|k| k.clone()).collect())
    }

    /// Writes the key-value Store to file
    fn write_to_persist(&mut self) -> KVResult {
        // attempt to write to the cab
        let mut tx = self.persy.begin()?;

        // serialize the cab as a u8 vec
        let byte_vec: Vec<u8> = match serialize(&mut self.cab) {
            Ok(bv) => bv,
            Err(e) => {
                error!("serialize: {}", e);
                return Err(PersyError::Err("Couldn't encode".to_string()));
            }
        };

        self.persy.insert_record(&mut tx, "tdb", &byte_vec)?;

        let prepared = self.persy.prepare_commit(tx)?;
        self.persy.commit(prepared)?;

        Ok(true)
    }

    /// Loads key-value store from file
    fn load_from_persist(&mut self) -> KVResult {
        if self.persy.exists_segment("tdb")? {
            for rec in self.persy.scan_records("tdb")? {
                let byte_vec = rec.content;
                // deserialize u8 vec back into HashMap
                match deserialize(byte_vec.as_slice()) {
                    Ok(f) => {
                        // assign read HashMap back to self
                        self.cab = f;
                    }
                    Err(e) => {
                        error!("{}", e);
                        return Err(PersyError::Err("Couldn't decode cab".to_string()));
                    }
                };
            }
        }

        Ok(true)
    }
}
<commit_msg>Switch to using cloned instead of map to clone the iterator contents<commit_after>/*!
Simple persistent generic HashMap/Key-value store, using file locking to limit
writing between threads.

This is in a beta state at the moment.

Basic usage:

```
extern crate typedb;

use typedb::{ KV, Value };

fn main() {
    let mut test_store = KV::<String, Value>::new("./basic.cab").unwrap();

    let _ = test_store.insert("key".to_string(), Value::String("value".to_string()));
    println!("{:?}", test_store.get(&"key".to_string()));
    let _ = test_store.remove(&"key".to_string());
}
```

Usage with user defined Key and Value types:

```
#[macro_use]
extern crate typedb;
#[macro_use]
extern crate serde_derive;

use typedb::KV;

key!(MyKey:
    String(String),
    Int(i32),
);

value!(MyValue:
    String(String),
    Int(i32),
);

fn main() {
    let mut test_store = KV::<MyKey, MyValue>::new("./types.cab").unwrap();

    let _ = test_store.insert(MyKey::Int(1i32), MyValue::String("value".to_string()));
    println!("{:?}", test_store.get(&MyKey::Int(1i32)));
    let _ = test_store.remove(&MyKey::Int(1i32));
}
```

*/

#![deny(missing_docs)]

extern crate bincode;
#[macro_use]
extern crate log;
extern crate persy;
extern crate serde;
#[macro_use]
extern crate serde_derive;

/// Macros for simplifying custom key and value types definition
pub mod macros;

use std::collections::HashMap;
use std::hash::Hash;
use std::io::ErrorKind;

use bincode::{deserialize, serialize};
use serde::ser::Serialize;
use serde::de::Deserialize;

use persy::{Config, PRes, Persy, PersyError};

/// A default value type to use with KV
#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
pub enum Value {
    /// Cab default Value type for strings
    String(String),
    /// Cab default Value type for intergers
    Int(i32),
    /// Cab default Value type for floats
    Float(f32),
    /// Cab default Value type for a sub map
    Map(HashMap<String, Value>),
    /// Cab default Value type for list
    List(Vec<Value>),
}

/// Type alias for results from KV
type KVResult = PRes<bool>;

/// Type alias for PersyError
type KVError = PersyError;

/// The type that represents the key-value store
pub struct KV<K, V> {
    cab: HashMap<K, V>,
    persy: Persy,
}

impl<K, V> KV<K, V>
where
    K: Clone + Serialize + for<'kde> Deserialize<'kde> + Eq + Hash,
    V: Clone + Serialize + for<'vde> Deserialize<'vde>,
{
    /// Creates a new instance of the KV store
    pub fn new(p: &'static str) -> Result<KV<K, V>, PersyError> {
        // create the KV instance
        match Persy::create(p) {
            Ok(o) => o,
            Err(PersyError::IO(ref e)) if e.kind() == ErrorKind::AlreadyExists => (),
            Err(e) => return Err(e),
        }
        let persy = Persy::open(p, Config::new())?;

        // if the segment doesn't exist create
        if !persy.exists_segment("tdb")? {
            let mut tx = persy.begin()?;
            persy.create_segment(&mut tx, "tdb")?;
            let prepared = persy.prepare_commit(tx)?;
            persy.commit(prepared)?;
        }

        let mut store = KV {
            cab: HashMap::new(),
            persy,
        };

        store.load_from_persist()?;

        Ok(store)
    }

    /// Inserta a key, value pair into the key-value store
    pub fn insert(&mut self, key: K, value: V) -> KVResult {
        // make sure mem version up to date
        self.load_from_persist()?;
        // insert into the HashMap
        self.cab.insert(key, value);
        // persist
        self.write_to_persist()
    }

    /// Get the value from a key
    pub fn get(&mut self, key: &K) -> Result<Option<V>, KVError> {
        // make sure mem version up to date
        self.load_from_persist()?;
        // get the value from the cab
        match self.cab.get(&key) {
            Some(v) => Ok(Some((*v).clone())),
            None => Ok(None),
        }
    }

    /// Removes a key and associated value from the key-value Store
    pub fn remove(&mut self, key: &K) -> KVResult {
        // make sure mem version up to date
        self.load_from_persist()?;
        // remove from the HashMap
        self.cab.remove(&key);
        // persist
        self.write_to_persist()
    }

    /// get all the keys contained in the KV Store
    pub fn keys(&mut self) -> Result<Vec<K>, KVError> {
        // make sure mem version up to date
        self.load_from_persist()?;
        // create a vec from the cabs keys
        Ok(self.cab.keys().cloned().collect())
    }

    /// Writes the key-value Store to file
    fn write_to_persist(&mut self) -> KVResult {
        // attempt to write to the cab
        let mut tx = self.persy.begin()?;

        // serialize the cab as a u8 vec
        let byte_vec: Vec<u8> = match serialize(&mut self.cab) {
            Ok(bv) => bv,
            Err(e) => {
                error!("serialize: {}", e);
                return Err(PersyError::Err("Couldn't encode".to_string()));
            }
        };

        self.persy.insert_record(&mut tx, "tdb", &byte_vec)?;

        let prepared = self.persy.prepare_commit(tx)?;
        self.persy.commit(prepared)?;

        Ok(true)
    }

    /// Loads key-value store from file
    fn load_from_persist(&mut self) -> KVResult {
        if self.persy.exists_segment("tdb")? {
            for rec in self.persy.scan_records("tdb")? {
                let byte_vec = rec.content;
                // deserialize u8 vec back into HashMap
                match deserialize(byte_vec.as_slice()) {
                    Ok(f) => {
                        // assign read HashMap back to self
                        self.cab = f;
                    }
                    Err(e) => {
                        error!("{}", e);
                        return Err(PersyError::Err("Couldn't decode cab".to_string()));
                    }
                };
            }
        }

        Ok(true)
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

mod task1 {
	fn sum_multiples_3_or_5_below(below: u64) -> u64 {
		let mut s = 0;
		for i in 1..below {
			if i % 5 == 0 || i % 3 == 0 {
				s += i;
			}
		}
		s
	}

	#[test]
	fn test() {
		assert_eq!(sum_multiples_3_or_5_below(1000), 233168);
	}
}

mod task2 {
	fn sum_even_fibs_below(below: u64) -> u64 {
		let mut s = 0;
		let mut v1;
		let mut v2 = 1;
		let mut val = 1;
		while val <= below {
			if val % 2 == 0 {
				s += val;
			}
			v1 = v2;
			v2 = val;
			val = v1 + v2;
		}
		s
	}

	#[test]
	fn test() {
		assert_eq!(sum_even_fibs_below(4000000), 4613732);
	}
}

mod task3 {
	pub fn factorize(num: u64) -> Vec<u64> {
		let mut n = num;
		let mut factor = 2u64;
		let mut factors = vec![];
		while n > 1 && factor.pow(2) <= n {
			while n % factor == 0 {
				factors.push(factor);
				n /= factor;
			}
			factor += 1;
		}
		factors.push(n);
		factors
	}

	fn largest_factor(num: u64) -> u64 {
		*factorize(num).iter().max().unwrap()
	}

	#[test]
	fn test() {
		assert_eq!(largest_factor(600851475143), 6857);
	}
}

mod task4 {
	fn is_palindrome(num: u64) -> bool {
		let s = num.to_string().into_bytes();
		let l = s.len();
		for i in 0..l/2 {
			if s[i] != s[l - i - 1] {
				return false;
			}
		}
		true
	}

	fn largest_palindrome_product(digits: u32) -> u64 {
		let min = 10u64.pow(digits - 1);
		let max = 10u64.pow(digits) - 1;
		let mut res = vec![];
		for i in (min..max).rev() {
			for j in (min..max).rev() {
				if is_palindrome(i * j) {
					res.push(i * j);
				}
			}
		}
		*res.iter().max().unwrap()
	}

	#[test]
	fn test() {
		assert_eq!(largest_palindrome_product(3), 906609);
	}
}

mod task5 {
	use std::cmp::max;
	use std::collections::HashMap;
	use task3;

	fn factorize_map(num: u64) -> HashMap<u64, u64> {
		let mut map = HashMap::new();
		for f in task3::factorize(num) {
			let counter = map.entry(f).or_insert(0);
			*counter += 1;
		}
		map
	}

	fn smallest_multimle_of_all_up_to(num: u64) -> u64 {
		let mut all_map: HashMap<u64, u32> = HashMap::new();
		for i in (2..(num + 1)).rev() {
			for (k, v) in &factorize_map(i) {
				let counter = all_map.entry(*k).or_insert(*v as u32);
				*counter = max(*v as u32, *counter);
			}
		}
		let mut res = 1u64;
		for (k, v) in &all_map {
			res *= k.pow(*v);
		}
		res
	}

	#[test]
	fn test() {
		assert_eq!(smallest_multimle_of_all_up_to(20), 232792560);
	}
}

mod task6 {
	fn square_sum_minus_sum_squares_up_to(num: u64) -> u64 {
		let mut s = 0u64;
		let mut ss = 0u64;
		for x in 1..(num + 1) {
			s += x.pow(2);
			ss += x;
		}
		ss.pow(2) - s
	}

	#[test]
	fn test() {
		assert_eq!(square_sum_minus_sum_squares_up_to(100), 25164150);
	}
}

mod task7 {
	struct EratosfenPrimeGenerator {
		primes: Vec<u64>,
		current: u64,
		inc: u64,
	}

	impl EratosfenPrimeGenerator {
		fn new() -> EratosfenPrimeGenerator {
			EratosfenPrimeGenerator{
				primes: Vec::new(),
				current: 2,
				inc: 1,
			}
		}
	}

	impl Iterator for EratosfenPrimeGenerator {
		type Item = u64;

		fn next(&mut self) -> Option<Self::Item> {
			let res = self.current;
			loop {
				self.current += self.inc;
				self.inc = 2;
				if !self.primes.iter().any(|p| self.current % p == 0) {
					self.primes.push(self.current);
					break;
				}
			}
			Some(res)
		}
	}

	fn nth_prime(num: usize) -> u64 {
		EratosfenPrimeGenerator::new().nth(num).unwrap()
	}

	fn nth_prime_from_one(num: usize) -> u64 {
		nth_prime(num - 1)
	}

	#[test]
	fn test() {
		assert_eq!(nth_prime_from_one(10001), 104743);
	}
}

mod task8 {
	use std::cmp::max;

	fn largest_seq_product_of_n_digits(seq: &str, num: usize) -> u64 {
		let mut digits = seq.to_string().into_bytes();
		for d in &mut digits {
			*d -= '0' as u8;
		}

		let mut max_product = 1;
		for v in digits.iter().take(num) {
			max_product *= *v as u64;
		}

		for (i, _) in digits.iter().enumerate().skip(num) {
			let mut product = 1;
			for n in 0..num {
				product *= digits[i - n] as u64;
			}
			max_product = max(max_product, product);
		}
		max_product
	}

	#[test]
	fn test() {
		assert_eq!(
			largest_seq_product_of_n_digits(
				"7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450",
				13
			),
			23514624000
		);
	}
}
<commit_msg>solved task 9<commit_after>#![allow(dead_code)]

mod task1 {
	fn sum_multiples_3_or_5_below(below: u64) -> u64 {
		let mut s = 0;
		for i in 1..below {
			if i % 5 == 0 || i % 3 == 0 {
				s += i;
			}
		}
		s
	}

	#[test]
	fn test() {
		assert_eq!(sum_multiples_3_or_5_below(1000), 233168);
	}
}

mod task2 {
	fn sum_even_fibs_below(below: u64) -> u64 {
		let mut s = 0;
		let mut v1;
		let mut v2 = 1;
		let mut val = 1;
		while val <= below {
			if val % 2 == 0 {
				s += val;
			}
			v1 = v2;
			v2 = val;
			val = v1 + v2;
		}
		s
	}

	#[test]
	fn test() {
		assert_eq!(sum_even_fibs_below(4000000), 4613732);
	}
}

mod task3 {
	pub fn factorize(num: u64) -> Vec<u64> {
		let mut n = num;
		let mut factor = 2u64;
		let mut factors = vec![];
		while n > 1 && factor.pow(2) <= n {
			while n % factor == 0 {
				factors.push(factor);
				n /= factor;
			}
			factor += 1;
		}
		factors.push(n);
		factors
	}

	fn largest_factor(num: u64) -> u64 {
		*factorize(num).iter().max().unwrap()
	}

	#[test]
	fn test() {
		assert_eq!(largest_factor(600851475143), 6857);
	}
}

mod task4 {
	fn is_palindrome(num: u64) -> bool {
		let s = num.to_string().into_bytes();
		let l = s.len();
		for i in 0..l/2 {
			if s[i] != s[l - i - 1] {
				return false;
			}
		}
		true
	}

	fn largest_palindrome_product(digits: u32) -> u64 {
		let min = 10u64.pow(digits - 1);
		let max = 10u64.pow(digits) - 1;
		let mut res = vec![];
		for i in (min..max).rev() {
			for j in (min..max).rev() {
				if is_palindrome(i * j) {
					res.push(i * j);
				}
			}
		}
		*res.iter().max().unwrap()
	}

	#[test]
	fn test() {
		assert_eq!(largest_palindrome_product(3), 906609);
	}
}

mod task5 {
	use std::cmp::max;
	use std::collections::HashMap;
	use task3;

	fn factorize_map(num: u64) -> HashMap<u64, u64> {
		let mut map = HashMap::new();
		for f in task3::factorize(num) {
			let counter = map.entry(f).or_insert(0);
			*counter += 1;
		}
		map
	}

	fn smallest_multimle_of_all_up_to(num: u64) -> u64 {
		let mut all_map: HashMap<u64, u32> = HashMap::new();
		for i in (2..(num + 1)).rev() {
			for (k, v) in &factorize_map(i) {
				let counter = all_map.entry(*k).or_insert(*v as u32);
				*counter = max(*v as u32, *counter);
			}
		}
		let mut res = 1u64;
		for (k, v) in &all_map {
			res *= k.pow(*v);
		}
		res
	}

	#[test]
	fn test() {
		assert_eq!(smallest_multimle_of_all_up_to(20), 232792560);
	}
}

mod task6 {
	fn square_sum_minus_sum_squares_up_to(num: u64) -> u64 {
		let mut s = 0u64;
		let mut ss = 0u64;
		for x in 1..(num + 1) {
			s += x.pow(2);
			ss += x;
		}
		ss.pow(2) - s
	}

	#[test]
	fn test() {
		assert_eq!(square_sum_minus_sum_squares_up_to(100), 25164150);
	}
}

mod task7 {
	struct EratosfenPrimeGenerator {
		primes: Vec<u64>,
		current: u64,
		inc: u64,
	}

	impl EratosfenPrimeGenerator {
		fn new() -> EratosfenPrimeGenerator {
			EratosfenPrimeGenerator{
				primes: Vec::new(),
				current: 2,
				inc: 1,
			}
		}
	}

	impl Iterator for EratosfenPrimeGenerator {
		type Item = u64;

		fn next(&mut self) -> Option<Self::Item> {
			let res = self.current;
			loop {
				self.current += self.inc;
				self.inc = 2;
				if !self.primes.iter().any(|p| self.current % p == 0) {
					self.primes.push(self.current);
					break;
				}
			}
			Some(res)
		}
	}

	fn nth_prime(num: usize) -> u64 {
		EratosfenPrimeGenerator::new().nth(num).unwrap()
	}

	fn nth_prime_from_one(num: usize) -> u64 {
		nth_prime(num - 1)
	}

	#[test]
	fn test() {
		assert_eq!(nth_prime_from_one(10001), 104743);
	}
}

mod task8 {
	use std::cmp::max;

	fn largest_seq_product_of_n_digits(seq: &str, num: usize) -> u64 {
		let mut digits = seq.to_string().into_bytes();
		for d in &mut digits {
			*d -= '0' as u8;
		}

		let mut max_product = 1;
		for v in digits.iter().take(num) {
			max_product *= *v as u64;
		}

		for (i, _) in digits.iter().enumerate().skip(num) {
			let mut product = 1;
			for n in 0..num {
				product *= digits[i - n] as u64;
			}
			max_product = max(max_product, product);
		}
		max_product
	}

	#[test]
	fn test() {
		assert_eq!(
			largest_seq_product_of_n_digits(
				"7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450",
				13
			),
			23514624000
		);
	}
}

mod task9 {
	fn product_pithagorean_triples_when_sum_is_1000() -> u64 {
		for a in 1..999 {
			for b in 1..(999 - a) {
				let sum = a + b;
				let val = a*a + b*b;
				for c in 1..999 { // will only make some iterations, so no need to optimize
					if val == c * c && sum + c == 1000  {
						return a * b * c;
					}
				}
			}
		}
		unreachable!();
	}

	#[test]
	fn test() {
		assert_eq!(product_pithagorean_triples_when_sum_is_1000(), 31875000);
	}
}
<|endoftext|>