<commit_before>//! An SDL2 backend for [Glium](https://github.com/tomaka/glium) - a high-level
//! OpenGL wrapper for the Rust language.
//!
//! # Example
//! ```no_run
//! # #[macro_use] extern crate glium;
//! # extern crate glium_sdl2;
//! # extern crate sdl2;
//! # fn main() {
//! use glium_sdl2::DisplayBuild;
//!
//! let mut sdl_context = sdl2::init().video().unwrap();
//!
//! let display = sdl_context.window("My window", 800, 600)
//!     .resizable()
//!     .build_glium()
//!     .unwrap();
//!
//! let mut running = true;
//!
//! while running {
//!     let mut target = display.draw();
//!     // do drawing here...
//!     target.finish();
//!
//!     // Event loop: includes all windows
//!
//!     for event in sdl_context.event_pump().poll_iter() {
//!         use sdl2::event::Event;
//!
//!         match event {
//!             Event::Quit { .. } => {
//!                 running = false;
//!             },
//!             _ => ()
//!         }
//!     }
//! }
//! # }
//! ```

extern crate libc;

extern crate glium;
extern crate sdl2;

use std::mem;
use std::cell::UnsafeCell;
use std::ops::Deref;
use std::rc::Rc;

use glium::backend::{Backend, Context, Facade};
use sdl2::Sdl;
use sdl2::SdlResult;

pub type Display = SDL2Facade;

/// Facade implementation for an SDL2 window.
pub struct SDL2Facade {
    // contains everything related to the current context and its state
    context: Rc<Context>,

    backend: Rc<SDL2WindowBackend>,
}

impl Facade for SDL2Facade {
    fn get_context(&self) -> &Rc<Context> { &self.context }
}

impl Deref for SDL2Facade {
    type Target = Context;

    fn deref(&self) -> &Context { &self.context }
}

impl SDL2Facade {
    /// Get the SDL Window ID.
    pub fn window_id(&self) -> u32 {
        self.backend.window().get_id()
    }

    /// Accesses the Window properties, such as the position, size and title of a Window.
    pub fn properties<'a>(&'a mut self, sdl: &'a Sdl) -> sdl2::video::WindowProperties<'a> {
        self.backend.window_mut().properties(sdl)
    }

    /// Immutably accesses the Window properties, such as the position, size and title of a Window.
    pub fn properties_getters(&self) -> sdl2::video::WindowPropertiesGetters {
        self.backend.window().properties_getters()
    }

    /// Start drawing on the backbuffer.
    ///
    /// This function returns a `Frame`, which can be used to draw on it.
    /// When the `Frame` is destroyed, the buffers are swapped.
    ///
    /// Note that destroying a `Frame` is immediate, even if vsync is enabled.
    pub fn draw(&self) -> glium::Frame {
        glium::Frame::new(self.context.clone(), self.backend.get_framebuffer_dimensions())
    }
}

/// An object that can build a facade object.
///
/// This trait is different from `glium::DisplayBuild` because Rust doesn't allow trait
/// implementations on types from external crates, unless the trait is in the same crate as the impl.
pub trait DisplayBuild {
    /// Build a context and a facade to draw on it.
    fn build_glium(self) -> Result<SDL2Facade, glium::GliumCreationError<String>>;

    /// Build a context and a facade to draw on it
    ///
    /// This function does the same as `build_glium`, except that the resulting context will assume
    /// that the current OpenGL context will never change.
    unsafe fn build_glium_unchecked(self) -> Result<SDL2Facade, glium::GliumCreationError<String>>;
}

impl<'a> DisplayBuild for &'a mut sdl2::video::WindowBuilder {
    fn build_glium(self) -> Result<SDL2Facade, glium::GliumCreationError<String>> {
        let backend = Rc::new(try!(SDL2WindowBackend::new(self)));
        let context = try!(unsafe { Context::new(backend.clone(), true) });

        let display = SDL2Facade {
            context: context,
            backend: backend
        };

        Ok(display)
    }

    unsafe fn build_glium_unchecked(self) -> Result<SDL2Facade, glium::GliumCreationError<String>> {
        let backend = Rc::new(try!(SDL2WindowBackend::new(self)));
        let context = try!(Context::new(backend.clone(), false));

        let display = SDL2Facade {
            context: context,
            backend: backend
        };

        Ok(display)
    }
}

pub struct SDL2WindowBackend {
    window: UnsafeCell<sdl2::video::Window>,
    context: sdl2::video::GLContext
}

impl SDL2WindowBackend {
    fn window(&self) -> &sdl2::video::Window {
        let ptr = self.window.get();
        unsafe { mem::transmute(ptr) }
    }

    fn window_mut(&self) -> &mut sdl2::video::Window {
        let ptr = self.window.get();
        unsafe { mem::transmute(ptr) }
    }

    pub fn new(window_builder: &mut sdl2::video::WindowBuilder) -> SdlResult<SDL2WindowBackend> {
        let window = try!(window_builder.opengl().build());
        let context = try!(window.gl_create_context());

        Ok(SDL2WindowBackend {
            window: UnsafeCell::new(window),
            context: context
        })
    }
}

unsafe impl Backend for SDL2WindowBackend {
    fn swap_buffers(&self) {
        self.window().gl_swap_window();
    }

    unsafe fn get_proc_address(&self, symbol: &str) -> *const libc::c_void {
        // Assumes the appropriate context for the window has been set before this call.

        sdl2::video::gl_get_proc_address(symbol)
    }

    fn get_framebuffer_dimensions(&self) -> (u32, u32) {
        let (width, height) = self.window().properties_getters().get_drawable_size();
        (width as u32, height as u32)
    }

    fn is_current(&self) -> bool {
        self.context.is_current()
    }

    unsafe fn make_current(&self) {
        self.window().gl_make_current(&self.context).unwrap()
    }
}
<commit_msg>Add a Clone impl to SDL2Facade<commit_after>//! An SDL2 backend for [Glium](https://github.com/tomaka/glium) - a high-level
//! OpenGL wrapper for the Rust language.
//!
//! # Example
//! ```no_run
//! # #[macro_use] extern crate glium;
//! # extern crate glium_sdl2;
//! # extern crate sdl2;
//! # fn main() {
//! use glium_sdl2::DisplayBuild;
//!
//! let mut sdl_context = sdl2::init().video().unwrap();
//!
//! let display = sdl_context.window("My window", 800, 600)
//!     .resizable()
//!     .build_glium()
//!     .unwrap();
//!
//! let mut running = true;
//!
//! while running {
//!     let mut target = display.draw();
//!     // do drawing here...
//!     target.finish();
//!
//!     // Event loop: includes all windows
//!
//!     for event in sdl_context.event_pump().poll_iter() {
//!         use sdl2::event::Event;
//!
//!         match event {
//!             Event::Quit { .. } => {
//!                 running = false;
//!             },
//!             _ => ()
//!         }
//!     }
//! }
//! # }
//! ```

extern crate libc;

extern crate glium;
extern crate sdl2;

use std::mem;
use std::cell::UnsafeCell;
use std::ops::Deref;
use std::rc::Rc;

use glium::backend::{Backend, Context, Facade};
use sdl2::Sdl;
use sdl2::SdlResult;

pub type Display = SDL2Facade;

/// Facade implementation for an SDL2 window.
#[derive(Clone)]
pub struct SDL2Facade {
    // contains everything related to the current context and its state
    context: Rc<Context>,

    backend: Rc<SDL2WindowBackend>,
}

impl Facade for SDL2Facade {
    fn get_context(&self) -> &Rc<Context> { &self.context }
}

impl Deref for SDL2Facade {
    type Target = Context;

    fn deref(&self) -> &Context { &self.context }
}

impl SDL2Facade {
    /// Get the SDL Window ID.
    pub fn window_id(&self) -> u32 {
        self.backend.window().get_id()
    }

    /// Accesses the Window properties, such as the position, size and title of a Window.
    pub fn properties<'a>(&'a mut self, sdl: &'a Sdl) -> sdl2::video::WindowProperties<'a> {
        self.backend.window_mut().properties(sdl)
    }

    /// Immutably accesses the Window properties, such as the position, size and title of a Window.
    pub fn properties_getters(&self) -> sdl2::video::WindowPropertiesGetters {
        self.backend.window().properties_getters()
    }

    /// Start drawing on the backbuffer.
    ///
    /// This function returns a `Frame`, which can be used to draw on it.
    /// When the `Frame` is destroyed, the buffers are swapped.
    ///
    /// Note that destroying a `Frame` is immediate, even if vsync is enabled.
    pub fn draw(&self) -> glium::Frame {
        glium::Frame::new(self.context.clone(), self.backend.get_framebuffer_dimensions())
    }
}

/// An object that can build a facade object.
///
/// This trait is different from `glium::DisplayBuild` because Rust doesn't allow trait
/// implementations on types from external crates, unless the trait is in the same crate as the impl.
pub trait DisplayBuild {
    /// Build a context and a facade to draw on it.
    fn build_glium(self) -> Result<SDL2Facade, glium::GliumCreationError<String>>;

    /// Build a context and a facade to draw on it
    ///
    /// This function does the same as `build_glium`, except that the resulting context will assume
    /// that the current OpenGL context will never change.
    unsafe fn build_glium_unchecked(self) -> Result<SDL2Facade, glium::GliumCreationError<String>>;
}

impl<'a> DisplayBuild for &'a mut sdl2::video::WindowBuilder {
    fn build_glium(self) -> Result<SDL2Facade, glium::GliumCreationError<String>> {
        let backend = Rc::new(try!(SDL2WindowBackend::new(self)));
        let context = try!(unsafe { Context::new(backend.clone(), true) });

        let display = SDL2Facade {
            context: context,
            backend: backend
        };

        Ok(display)
    }

    unsafe fn build_glium_unchecked(self) -> Result<SDL2Facade, glium::GliumCreationError<String>> {
        let backend = Rc::new(try!(SDL2WindowBackend::new(self)));
        let context = try!(Context::new(backend.clone(), false));

        let display = SDL2Facade {
            context: context,
            backend: backend
        };

        Ok(display)
    }
}

pub struct SDL2WindowBackend {
    window: UnsafeCell<sdl2::video::Window>,
    context: sdl2::video::GLContext
}

impl SDL2WindowBackend {
    fn window(&self) -> &sdl2::video::Window {
        let ptr = self.window.get();
        unsafe { mem::transmute(ptr) }
    }

    fn window_mut(&self) -> &mut sdl2::video::Window {
        let ptr = self.window.get();
        unsafe { mem::transmute(ptr) }
    }

    pub fn new(window_builder: &mut sdl2::video::WindowBuilder) -> SdlResult<SDL2WindowBackend> {
        let window = try!(window_builder.opengl().build());
        let context = try!(window.gl_create_context());

        Ok(SDL2WindowBackend {
            window: UnsafeCell::new(window),
            context: context
        })
    }
}

unsafe impl Backend for SDL2WindowBackend {
    fn swap_buffers(&self) {
        self.window().gl_swap_window();
    }

    unsafe fn get_proc_address(&self, symbol: &str) -> *const libc::c_void {
        // Assumes the appropriate context for the window has been set before this call.

        sdl2::video::gl_get_proc_address(symbol)
    }

    fn get_framebuffer_dimensions(&self) -> (u32, u32) {
        let (width, height) = self.window().properties_getters().get_drawable_size();
        (width as u32, height as u32)
    }

    fn is_current(&self) -> bool {
        self.context.is_current()
    }

    unsafe fn make_current(&self) {
        self.window().gl_make_current(&self.context).unwrap()
    }
}
<|endoftext|>


<commit_before>//! Replaces the deprecated functionality of std::os::num_cpus.
#![cfg_attr(test, deny(warnings))]
#![deny(missing_docs)]
#![allow(non_snake_case)]

#[cfg(not(windows))]
extern crate libc;

/// Returns the number of CPUs of the current machine.
#[inline]
pub fn get() -> usize {
    get_num_cpus()
}

#[cfg(windows)]
fn get_num_cpus() -> usize {
    #[repr(C)]
    struct SYSTEM_INFO {
        wProcessorArchitecture: u16,
        wReserved: u16,
        dwPageSize: u32,
        lpMinimumApplicationAddress: *mut u8,
        lpMaximumApplicationAddress: *mut u8,
        dwActiveProcessorMask: *mut u8,
        dwNumberOfProcessors: u32,
        dwProcessorType: u32,
        dwAllocationGranularity: u32,
        wProcessorLevel: u16,
        wProcessorRevision: u16,
    }

    extern "system" {
        fn GetSystemInfo(lpSystemInfo: *mut SYSTEM_INFO);
    }

    unsafe {
        let mut sysinfo: SYSTEM_INFO = std::mem::uninitialized();
        GetSystemInfo(&mut sysinfo);
        sysinfo.dwNumberOfProcessors as usize
    }
}

#[cfg(
    any(
        target_os = "freebsd",
        target_os = "dragonfly",
        target_os = "bitrig",
        target_os = "openbsd",
        target_os = "netbsd"
    )
)]
fn get_num_cpus() -> usize {
    use libc::{c_int, c_uint};
    use libc::sysctl;
    use std::ptr;

    //XXX: uplift to libc?
    const CTL_HW: c_int = 6;
    const HW_AVAILCPU: c_int = 25;
    const HW_NCPU: c_int = 3;

    let mut cpus: c_uint = 0;
    let mut CPUS_SIZE = ::std::mem::size_of::<c_uint>();
    let mut mib: [c_int; 4] = [CTL_HW, HW_AVAILCPU, 0, 0];

    unsafe {
        sysctl(mib.as_mut_ptr(), 2,
               &mut cpus as *mut _ as *mut _, &mut CPUS_SIZE as *mut _ as *mut _,
               ptr::null_mut(), 0);
    }

    if cpus < 1 {
        mib[1] = HW_NCPU;
        unsafe {
            sysctl(mib.as_mut_ptr(), 2,
                   &mut cpus as *mut _ as *mut _, &mut CPUS_SIZE as *mut _ as *mut _,
                   ptr::null_mut(), 0);
        }
        if cpus < 1 {
            cpus = 1;
        }
    }

    cpus as usize
}

#[cfg(
    any(
        target_os = "linux",
        target_os = "nacl",
        target_os = "macos",
        target_os = "ios"
    )
)]
fn get_num_cpus() -> usize {
    unsafe {
        libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as usize
    }
}

#[cfg(target_os= "android")]
fn get_num_cpus() -> usize {
    //to-do: replace with libc::_SC_NPROCESSORS_ONLN once available
    unsafe {
        libc::sysconf(97) as usize
    }
}

#[test]
fn lower_bound() {
    assert!(get() > 0);
}

#[test]
fn upper_bound() {
    assert!(get() < 236_451);
}
<commit_msg>Move android back to normal unix definitions<commit_after>//! Replaces the deprecated functionality of std::os::num_cpus.
#![cfg_attr(test, deny(warnings))]
#![deny(missing_docs)]
#![allow(non_snake_case)]

#[cfg(not(windows))]
extern crate libc;

/// Returns the number of CPUs of the current machine.
#[inline]
pub fn get() -> usize {
    get_num_cpus()
}

#[cfg(windows)]
fn get_num_cpus() -> usize {
    #[repr(C)]
    struct SYSTEM_INFO {
        wProcessorArchitecture: u16,
        wReserved: u16,
        dwPageSize: u32,
        lpMinimumApplicationAddress: *mut u8,
        lpMaximumApplicationAddress: *mut u8,
        dwActiveProcessorMask: *mut u8,
        dwNumberOfProcessors: u32,
        dwProcessorType: u32,
        dwAllocationGranularity: u32,
        wProcessorLevel: u16,
        wProcessorRevision: u16,
    }

    extern "system" {
        fn GetSystemInfo(lpSystemInfo: *mut SYSTEM_INFO);
    }

    unsafe {
        let mut sysinfo: SYSTEM_INFO = std::mem::uninitialized();
        GetSystemInfo(&mut sysinfo);
        sysinfo.dwNumberOfProcessors as usize
    }
}

#[cfg(
    any(
        target_os = "freebsd",
        target_os = "dragonfly",
        target_os = "bitrig",
        target_os = "openbsd",
        target_os = "netbsd"
    )
)]
fn get_num_cpus() -> usize {
    use libc::{c_int, c_uint};
    use libc::sysctl;
    use std::ptr;

    //XXX: uplift to libc?
    const CTL_HW: c_int = 6;
    const HW_AVAILCPU: c_int = 25;
    const HW_NCPU: c_int = 3;

    let mut cpus: c_uint = 0;
    let mut CPUS_SIZE = ::std::mem::size_of::<c_uint>();
    let mut mib: [c_int; 4] = [CTL_HW, HW_AVAILCPU, 0, 0];

    unsafe {
        sysctl(mib.as_mut_ptr(), 2,
               &mut cpus as *mut _ as *mut _, &mut CPUS_SIZE as *mut _ as *mut _,
               ptr::null_mut(), 0);
    }

    if cpus < 1 {
        mib[1] = HW_NCPU;
        unsafe {
            sysctl(mib.as_mut_ptr(), 2,
                   &mut cpus as *mut _ as *mut _, &mut CPUS_SIZE as *mut _ as *mut _,
                   ptr::null_mut(), 0);
        }
        if cpus < 1 {
            cpus = 1;
        }
    }

    cpus as usize
}

#[cfg(
    any(
        target_os = "linux",
        target_os = "nacl",
        target_os = "macos",
        target_os = "ios",
        target_os = "android",
    )
)]
fn get_num_cpus() -> usize {
    unsafe {
        libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as usize
    }
}

#[test]
fn lower_bound() {
    assert!(get() > 0);
}

#[test]
fn upper_bound() {
    assert!(get() < 236_451);
}
<|endoftext|>


<commit_before>// Inspired by http://python-gitlab.readthedocs.io/en/stable/

#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]

#![cfg_attr(feature = "serde_derive", feature(proc_macro))]

#[cfg(feature = "serde_derive")]
#[macro_use]
extern crate serde_derive;

extern crate serde;
extern crate serde_json;
extern crate serde_urlencoded;

#[cfg(feature = "serde_derive")]
include!("serde_types.in.rs");

#[cfg(feature = "serde_codegen")]
include!(concat!(env!("OUT_DIR"), "/serde_types.rs"));

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

pub mod gitlab;
// pub mod groups;
pub mod projects;
pub mod issues;
pub mod merge_requests;

// Re-export those structs
pub use gitlab::Pagination;
pub use gitlab::GitLab;
// pub use projects::Project;

trait BuildQuery {
    fn build_query(&self) -> String;
}

#[cfg(test)]
mod tests {
    // use gitlab::GitLab;
    // use hyper;

    // #[test]
    // fn unauthorized() {
    //     let gl = GitLab::new("http", "gitlab.com", 80, "XXXXXXXXXXXXX");
    //     println!("gl: {:?}", gl);
    //     assert_eq!(gl.attempt_connection().unwrap().status,
    //                hyper::status::StatusCode::Unauthorized);
    // }
}
<commit_msg>Disable `doc_markdown` clippy lint since GitLab's doc triggers it all over the place<commit_after>// Inspired by http://python-gitlab.readthedocs.io/en/stable/

#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]
#![cfg_attr(feature="cargo-clippy", allow(doc_markdown))]

#![cfg_attr(feature = "serde_derive", feature(proc_macro))]

#[cfg(feature = "serde_derive")]
#[macro_use]
extern crate serde_derive;

extern crate serde;
extern crate serde_json;
extern crate serde_urlencoded;

#[cfg(feature = "serde_derive")]
include!("serde_types.in.rs");

#[cfg(feature = "serde_codegen")]
include!(concat!(env!("OUT_DIR"), "/serde_types.rs"));

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

pub mod gitlab;
// pub mod groups;
pub mod projects;
pub mod issues;
pub mod merge_requests;

// Re-export those structs
pub use gitlab::Pagination;
pub use gitlab::GitLab;
// pub use projects::Project;

trait BuildQuery {
    fn build_query(&self) -> String;
}

#[cfg(test)]
mod tests {
    // use gitlab::GitLab;
    // use hyper;

    // #[test]
    // fn unauthorized() {
    //     let gl = GitLab::new("http", "gitlab.com", 80, "XXXXXXXXXXXXX");
    //     println!("gl: {:?}", gl);
    //     assert_eq!(gl.attempt_connection().unwrap().status,
    //                hyper::status::StatusCode::Unauthorized);
    // }
}
<|endoftext|>


<commit_before>/// Initializes the logging submodule.
///
/// This function should be called only once at the beginning of the process
/// startup.
pub fn init(args: &crate::args::Args) {
    let mut logger = MultiLog::new();
    if args.log_to_stdout {
        logger.push(WriterLog::new(std::io::stdout()));
    }
    if let Some(ref path) = args.log_to_file {
        let file = std::fs::OpenOptions::new()
            .append(true)
            .open(path)
            .expect("failed to open the log file");

        logger.push(WriterLog::new(file));
    }

    log::set_boxed_logger(Box::new(logger))
        .expect("failed to initialize logger");

    log::set_max_level(args.verbosity);
}

/// A wrapper for logging to multiple destinations.
struct MultiLog {
    /// A list of all registered loggers.
    loggers: Vec<Box<dyn log::Log>>,
}

impl MultiLog {

    /// Creates a new wrapper with no registered loggers.
    fn new() -> MultiLog {
        MultiLog {
            loggers: Vec::new(),
        }
    }

    /// Registers a new destination to log to.
    fn push<L: log::Log + 'static>(&mut self, logger: L) {
        self.loggers.push(Box::new(logger));
    }
}

impl log::Log for MultiLog {

    fn enabled(&self, metadata: &log::Metadata) -> bool {
        self.loggers.iter().any(|logger| logger.enabled(metadata))
    }

    fn log(&self, record: &log::Record) {
        for log in &self.loggers {
            log.log(record);
        }
    }

    fn flush(&self) {
        for logger in &self.loggers {
            logger.flush();
        }
    }
}

/// A simple logger implementation for logging to writable streams (e.g. files).
struct WriterLog<W: std::io::Write + Send + Sync> {
    writer: std::sync::Mutex<W>,
}

impl<W: std::io::Write + Send + Sync> WriterLog<W> {

    /// Create a new logger for the given writable stream.
    fn new(writer: W) -> WriterLog<W> {
        WriterLog { writer: std::sync::Mutex::new(writer) }
    }
}

impl<W: std::io::Write + Send + Sync> log::Log for WriterLog<W> {

    fn enabled(&self, _metadata: &log::Metadata) -> bool {
        true
    }

    fn log(&self, record: &log::Record) {
        if !self.enabled(record.metadata()) {
            return;
        }

        let now = std::time::SystemTime::now();

        // We consider failures to write to the log stream critical. Otherwise,
        // if there is some other issue with the system it is not possible to
        // properly communicate it. Thus, we panic on all write errors.
        let mut writer = self.writer.lock()
            .expect("failed to acquire log output stream lock");

        || -> Result<(), std::io::Error> {
            write! {
                writer,
                "[{level} {timestamp} ",
                level = record.level(),
                timestamp = humantime::format_rfc3339_nanos(now)
            }?;
            match record.file() {
                Some(file) => write!(writer, "{file}")?,
                None => write!(writer, "<unknown>")?,
            }
            match record.line() {
                Some(line) => write!(writer, ":{line}]")?,
                None => write!(writer, ":<unknown>]")?,
            }

            write!(writer, " {}\n", record.args())?;

            Ok(())
        }().expect("failed to write to the log output stream")
    }

    fn flush(&self) {
        // Similarly to write errors, we also panic on flush errors as there is
        // nothing we can do otherwise.
        self.writer
            .lock()
            .expect("failed to acquire log output stream lock")
            .flush()
            .expect("failed to flush the log output stream");
    }
}
<commit_msg>Add missing license header to the `log` module.<commit_after>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

/// Initializes the logging submodule.
///
/// This function should be called only once at the beginning of the process
/// startup.
pub fn init(args: &crate::args::Args) {
    let mut logger = MultiLog::new();
    if args.log_to_stdout {
        logger.push(WriterLog::new(std::io::stdout()));
    }
    if let Some(ref path) = args.log_to_file {
        let file = std::fs::OpenOptions::new()
            .append(true)
            .open(path)
            .expect("failed to open the log file");

        logger.push(WriterLog::new(file));
    }

    log::set_boxed_logger(Box::new(logger))
        .expect("failed to initialize logger");

    log::set_max_level(args.verbosity);
}

/// A wrapper for logging to multiple destinations.
struct MultiLog {
    /// A list of all registered loggers.
    loggers: Vec<Box<dyn log::Log>>,
}

impl MultiLog {

    /// Creates a new wrapper with no registered loggers.
    fn new() -> MultiLog {
        MultiLog {
            loggers: Vec::new(),
        }
    }

    /// Registers a new destination to log to.
    fn push<L: log::Log + 'static>(&mut self, logger: L) {
        self.loggers.push(Box::new(logger));
    }
}

impl log::Log for MultiLog {

    fn enabled(&self, metadata: &log::Metadata) -> bool {
        self.loggers.iter().any(|logger| logger.enabled(metadata))
    }

    fn log(&self, record: &log::Record) {
        for log in &self.loggers {
            log.log(record);
        }
    }

    fn flush(&self) {
        for logger in &self.loggers {
            logger.flush();
        }
    }
}

/// A simple logger implementation for logging to writable streams (e.g. files).
struct WriterLog<W: std::io::Write + Send + Sync> {
    writer: std::sync::Mutex<W>,
}

impl<W: std::io::Write + Send + Sync> WriterLog<W> {

    /// Create a new logger for the given writable stream.
    fn new(writer: W) -> WriterLog<W> {
        WriterLog { writer: std::sync::Mutex::new(writer) }
    }
}

impl<W: std::io::Write + Send + Sync> log::Log for WriterLog<W> {

    fn enabled(&self, _metadata: &log::Metadata) -> bool {
        true
    }

    fn log(&self, record: &log::Record) {
        if !self.enabled(record.metadata()) {
            return;
        }

        let now = std::time::SystemTime::now();

        // We consider failures to write to the log stream critical. Otherwise,
        // if there is some other issue with the system it is not possible to
        // properly communicate it. Thus, we panic on all write errors.
        let mut writer = self.writer.lock()
            .expect("failed to acquire log output stream lock");

        || -> Result<(), std::io::Error> {
            write! {
                writer,
                "[{level} {timestamp} ",
                level = record.level(),
                timestamp = humantime::format_rfc3339_nanos(now)
            }?;
            match record.file() {
                Some(file) => write!(writer, "{file}")?,
                None => write!(writer, "<unknown>")?,
            }
            match record.line() {
                Some(line) => write!(writer, ":{line}]")?,
                None => write!(writer, ":<unknown>]")?,
            }

            write!(writer, " {}\n", record.args())?;

            Ok(())
        }().expect("failed to write to the log output stream")
    }

    fn flush(&self) {
        // Similarly to write errors, we also panic on flush errors as there is
        // nothing we can do otherwise.
        self.writer
            .lock()
            .expect("failed to acquire log output stream lock")
            .flush()
            .expect("failed to flush the log output stream");
    }
}
<|endoftext|>


<commit_before>use super::*;

use proc_macro2::{TokenNode, TokenTree, TokenStream, Delimiter};

#[cfg(feature = "extra-traits")]
use std::hash::{Hash, Hasher};

ast_struct! {
    /// Represents a macro invocation. The Path indicates which macro
    /// is being invoked, and the vector of token-trees contains the source
    /// of the macro invocation.
    pub struct Macro #manual_extra_traits {
        pub path: Path,
        pub bang_token: Token![!],
        pub tokens: TokenTree,
    }
}

#[cfg(feature = "extra-traits")]
impl Eq for Macro {}

#[cfg(feature = "extra-traits")]
impl PartialEq for Macro {
    fn eq(&self, other: &Self) -> bool {
        self.path == other.path
            && self.bang_token == other.bang_token
            && TokenTreeHelper(&self.tokens) == TokenTreeHelper(&other.tokens)
    }
}

#[cfg(feature = "extra-traits")]
impl Hash for Macro {
    fn hash<H>(&self, state: &mut H)
        where H: Hasher
    {
        self.path.hash(state);
        self.bang_token.hash(state);
        TokenTreeHelper(&self.tokens).hash(state);
    }
}

impl Macro {
    pub fn is_braced(&self) -> bool {
        is_braced(&self.tokens)
    }
}

pub fn is_braced(tt: &TokenTree) -> bool {
    match tt.kind {
        TokenNode::Group(Delimiter::Brace, _) => true,
        _ => false,
    }
}

#[cfg(feature = "extra-traits")]
pub struct TokenTreeHelper<'a>(pub &'a TokenTree);

#[cfg(feature = "extra-traits")]
impl<'a> PartialEq for TokenTreeHelper<'a> {
    fn eq(&self, other: &Self) -> bool {
        use proc_macro2::Spacing;

        match (&self.0.kind, &other.0.kind) {
            (&TokenNode::Group(d1, ref s1), &TokenNode::Group(d2, ref s2)) => {
                match (d1, d2) {
                    (Delimiter::Parenthesis, Delimiter::Parenthesis) |
                    (Delimiter::Brace, Delimiter::Brace) |
                    (Delimiter::Bracket, Delimiter::Bracket) |
                    (Delimiter::None, Delimiter::None) => {}
                    _ => return false,
                }

                let s1 = s1.clone().into_iter();
                let mut s2 = s2.clone().into_iter();

                for item1 in s1 {
                    let item2 = match s2.next() {
                        Some(item) => item,
                        None => return false,
                    };
                    if TokenTreeHelper(&item1) != TokenTreeHelper(&item2) {
                        return false
                    }
                }
                s2.next().is_none()
            }
            (&TokenNode::Op(o1, k1), &TokenNode::Op(o2, k2)) => {
                o1 == o2 && match (k1, k2) {
                    (Spacing::Alone, Spacing::Alone) |
                    (Spacing::Joint, Spacing::Joint) => true,
                    _ => false,
                }
            }
            (&TokenNode::Literal(ref l1), &TokenNode::Literal(ref l2)) => {
                l1.to_string() == l2.to_string()
            }
            (&TokenNode::Term(ref s1), &TokenNode::Term(ref s2)) => {
                s1.as_str() == s2.as_str()
            }
            _ => false,
        }
    }
}

#[cfg(feature = "extra-traits")]
impl<'a> Hash for TokenTreeHelper<'a> {
    fn hash<H: Hasher>(&self, h: &mut H) {
        use proc_macro2::Spacing;

        match self.0.kind {
            TokenNode::Group(delim, ref stream) => {
                0u8.hash(h);
                match delim {
                    Delimiter::Parenthesis => 0u8.hash(h),
                    Delimiter::Brace => 1u8.hash(h),
                    Delimiter::Bracket => 2u8.hash(h),
                    Delimiter::None => 3u8.hash(h),
                }

                for item in stream.clone() {
                    TokenTreeHelper(&item).hash(h);
                }
                0xffu8.hash(h); // terminator w/ a variant we don't normally hash
            }
            TokenNode::Op(op, kind) => {
                1u8.hash(h);
                op.hash(h);
                match kind {
                    Spacing::Alone => 0u8.hash(h),
                    Spacing::Joint => 1u8.hash(h),
                }
            }
            TokenNode::Literal(ref lit) => (2u8, lit.to_string()).hash(h),
            TokenNode::Term(ref word) => (3u8, word.as_str()).hash(h),
        }
    }
}

#[cfg(feature = "extra-traits")]
pub struct TokenStreamHelper<'a>(pub &'a TokenStream);

#[cfg(feature = "extra-traits")]
impl<'a> PartialEq for TokenStreamHelper<'a> {
    fn eq(&self, other: &Self) -> bool {
        let left = self.0.clone().into_iter().collect::<Vec<_>>();
        let right = other.0.clone().into_iter().collect::<Vec<_>>();
        if left.len() != right.len() {
            return false;
        }
        for (a, b) in left.into_iter().zip(right) {
            if TokenTreeHelper(&a) != TokenTreeHelper(&b) {
                return false;
            }
        }
        true
    }
}

#[cfg(feature = "extra-traits")]
impl<'a> Hash for TokenStreamHelper<'a> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        let tts = self.0.clone().into_iter().collect::<Vec<_>>();
        tts.len().hash(state);
        for tt in tts {
            TokenTreeHelper(&tt).hash(state);
        }
    }
}

#[cfg(feature = "parsing")]
pub mod parsing {
    use super::*;

    use proc_macro2::{TokenNode, TokenTree};
    use synom::Synom;
    use cursor::Cursor;
    use {PResult, parse_error};

    impl Synom for Macro {
        named!(parse -> Self, do_parse!(
            what: syn!(Path) >>
            bang: punct!(!) >>
            body: call!(parse_tt_delimited) >>
            (Macro {
                path: what,
                bang_token: bang,
                tokens: body,
            })
        ));
    }

    pub fn parse_tt_delimited(input: Cursor) -> PResult<TokenTree> {
        match input.token_tree() {
            Some((rest, token @ TokenTree { kind: TokenNode::Group(..), .. })) => {
                Ok((rest, token))
            }
            _ => parse_error(),
        }
    }
}

#[cfg(feature = "printing")]
mod printing {
    use super::*;
    use quote::{Tokens, ToTokens};

    impl ToTokens for Macro {
        fn to_tokens(&self, tokens: &mut Tokens) {
            self.path.to_tokens(tokens);
            self.bang_token.to_tokens(tokens);
            self.tokens.to_tokens(tokens);
        }
    }
}
<commit_msg>Fix unused import when compiling without extra-traits<commit_after>use super::*;

use proc_macro2::{TokenNode, TokenTree, Delimiter};

#[cfg(feature = "extra-traits")]
use proc_macro2::TokenStream;
#[cfg(feature = "extra-traits")]
use std::hash::{Hash, Hasher};

ast_struct! {
    /// Represents a macro invocation. The Path indicates which macro
    /// is being invoked, and the vector of token-trees contains the source
    /// of the macro invocation.
    pub struct Macro #manual_extra_traits {
        pub path: Path,
        pub bang_token: Token![!],
        pub tokens: TokenTree,
    }
}

#[cfg(feature = "extra-traits")]
impl Eq for Macro {}

#[cfg(feature = "extra-traits")]
impl PartialEq for Macro {
    fn eq(&self, other: &Self) -> bool {
        self.path == other.path
            && self.bang_token == other.bang_token
            && TokenTreeHelper(&self.tokens) == TokenTreeHelper(&other.tokens)
    }
}

#[cfg(feature = "extra-traits")]
impl Hash for Macro {
    fn hash<H>(&self, state: &mut H)
        where H: Hasher
    {
        self.path.hash(state);
        self.bang_token.hash(state);
        TokenTreeHelper(&self.tokens).hash(state);
    }
}

impl Macro {
    pub fn is_braced(&self) -> bool {
        is_braced(&self.tokens)
    }
}

pub fn is_braced(tt: &TokenTree) -> bool {
    match tt.kind {
        TokenNode::Group(Delimiter::Brace, _) => true,
        _ => false,
    }
}

#[cfg(feature = "extra-traits")]
pub struct TokenTreeHelper<'a>(pub &'a TokenTree);

#[cfg(feature = "extra-traits")]
impl<'a> PartialEq for TokenTreeHelper<'a> {
    fn eq(&self, other: &Self) -> bool {
        use proc_macro2::Spacing;

        match (&self.0.kind, &other.0.kind) {
            (&TokenNode::Group(d1, ref s1), &TokenNode::Group(d2, ref s2)) => {
                match (d1, d2) {
                    (Delimiter::Parenthesis, Delimiter::Parenthesis) |
                    (Delimiter::Brace, Delimiter::Brace) |
                    (Delimiter::Bracket, Delimiter::Bracket) |
                    (Delimiter::None, Delimiter::None) => {}
                    _ => return false,
                }

                let s1 = s1.clone().into_iter();
                let mut s2 = s2.clone().into_iter();

                for item1 in s1 {
                    let item2 = match s2.next() {
                        Some(item) => item,
                        None => return false,
                    };
                    if TokenTreeHelper(&item1) != TokenTreeHelper(&item2) {
                        return false
                    }
                }
                s2.next().is_none()
            }
            (&TokenNode::Op(o1, k1), &TokenNode::Op(o2, k2)) => {
                o1 == o2 && match (k1, k2) {
                    (Spacing::Alone, Spacing::Alone) |
                    (Spacing::Joint, Spacing::Joint) => true,
                    _ => false,
                }
            }
            (&TokenNode::Literal(ref l1), &TokenNode::Literal(ref l2)) => {
                l1.to_string() == l2.to_string()
            }
            (&TokenNode::Term(ref s1), &TokenNode::Term(ref s2)) => {
                s1.as_str() == s2.as_str()
            }
            _ => false,
        }
    }
}

#[cfg(feature = "extra-traits")]
impl<'a> Hash for TokenTreeHelper<'a> {
    fn hash<H: Hasher>(&self, h: &mut H) {
        use proc_macro2::Spacing;

        match self.0.kind {
            TokenNode::Group(delim, ref stream) => {
                0u8.hash(h);
                match delim {
                    Delimiter::Parenthesis => 0u8.hash(h),
                    Delimiter::Brace => 1u8.hash(h),
                    Delimiter::Bracket => 2u8.hash(h),
                    Delimiter::None => 3u8.hash(h),
                }

                for item in stream.clone() {
                    TokenTreeHelper(&item).hash(h);
                }
                0xffu8.hash(h); // terminator w/ a variant we don't normally hash
            }
            TokenNode::Op(op, kind) => {
                1u8.hash(h);
                op.hash(h);
                match kind {
                    Spacing::Alone => 0u8.hash(h),
                    Spacing::Joint => 1u8.hash(h),
                }
            }
            TokenNode::Literal(ref lit) => (2u8, lit.to_string()).hash(h),
            TokenNode::Term(ref word) => (3u8, word.as_str()).hash(h),
        }
    }
}

#[cfg(feature = "extra-traits")]
pub struct TokenStreamHelper<'a>(pub &'a TokenStream);

#[cfg(feature = "extra-traits")]
impl<'a> PartialEq for TokenStreamHelper<'a> {
    fn eq(&self, other: &Self) -> bool {
        let left = self.0.clone().into_iter().collect::<Vec<_>>();
        let right = other.0.clone().into_iter().collect::<Vec<_>>();
        if left.len() != right.len() {
            return false;
        }
        for (a, b) in left.into_iter().zip(right) {
            if TokenTreeHelper(&a) != TokenTreeHelper(&b) {
                return false;
            }
        }
        true
    }
}

#[cfg(feature = "extra-traits")]
impl<'a> Hash for TokenStreamHelper<'a> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        let tts = self.0.clone().into_iter().collect::<Vec<_>>();
        tts.len().hash(state);
        for tt in tts {
            TokenTreeHelper(&tt).hash(state);
        }
    }
}

#[cfg(feature = "parsing")]
pub mod parsing {
    use super::*;

    use proc_macro2::{TokenNode, TokenTree};
    use synom::Synom;
    use cursor::Cursor;
    use {PResult, parse_error};

    impl Synom for Macro {
        named!(parse -> Self, do_parse!(
            what: syn!(Path) >>
            bang: punct!(!) >>
            body: call!(parse_tt_delimited) >>
            (Macro {
                path: what,
                bang_token: bang,
                tokens: body,
            })
        ));
    }

    pub fn parse_tt_delimited(input: Cursor) -> PResult<TokenTree> {
        match input.token_tree() {
            Some((rest, token @ TokenTree { kind: TokenNode::Group(..), .. })) => {
                Ok((rest, token))
            }
            _ => parse_error(),
        }
    }
}

#[cfg(feature = "printing")]
mod printing {
    use super::*;
    use quote::{Tokens, ToTokens};

    impl ToTokens for Macro {
        fn to_tokens(&self, tokens: &mut Tokens) {
            self.path.to_tokens(tokens);
            self.bang_token.to_tokens(tokens);
            self.tokens.to_tokens(tokens);
        }
    }
}
<|endoftext|>


<commit_before>use serial::Serial;
use timer::Timer;
use keypad::Keypad;
use gpu::GPU;
use sound::Sound;

static WRAM_SIZE: uint = 0x8000;
static ZRAM_SIZE: uint = 0x7F;

#[deriving(Eq)]
enum DMAType {
	NoDMA,
	GDMA,
	HDMA,
}

pub struct MMU {
	priv wram: ~[u8, ..WRAM_SIZE],
	priv zram: ~[u8, ..ZRAM_SIZE],
	priv hdma: [u8, ..4],
	inte: u8,
	intf: u8,
	serial: Serial,
	timer: Timer,
	keypad: Keypad,
	gpu: GPU,
	sound: Sound,
	priv hdma_status: DMAType,
	priv hdma_src: u16,
	priv hdma_dst: u16,
	priv hdma_len: u8,
	priv wrambank: u8,
	priv mbc: ~::mbc::MBC,
	priv gbmode: ::gbmode::GbMode,
	priv gbspeed: ::gbmode::GbSpeed,
	priv speed_switch_req: bool,
}

impl MMU {
	pub fn new(romname: &str) -> MMU {
		let mut res = MMU {
			wram: ~([0, ..WRAM_SIZE]),
			zram: ~([0, ..ZRAM_SIZE]),
			hdma: [0, ..4],
			wrambank: 1,
			inte: 0,
			intf: 0,
			serial: Serial::new(),
			timer: Timer::new(),
			keypad: Keypad::new(),
			gpu: GPU::new(),
			sound: Sound::new(),
			mbc: ::mbc::get_mbc(&Path::new(romname)),
			gbmode: ::gbmode::Classic,
			gbspeed: ::gbmode::Single,
			speed_switch_req: false,
			hdma_src: 0,
			hdma_dst: 0,
			hdma_status: NoDMA,
			hdma_len: 0xFF,
		};
		if res.rb(0x0143) == 0xC0 {
			fail!("This game does not work in Classic mode");
		}
		res.set_initial();
		return res
	}

	pub fn new_cgb(romname: &str) -> MMU {
		let mut res = MMU {
			wram: ~([0,.. WRAM_SIZE]),
			zram: ~([0,.. ZRAM_SIZE]),
			wrambank: 1,
			hdma: [0,.. 4],
			inte: 0,
			intf: 0,
			serial: Serial::new(),
			timer: Timer::new(),
			keypad: Keypad::new(),
			gpu: GPU::new_cgb(),
			sound: Sound::new(),
			mbc: ::mbc::get_mbc(&Path::new(romname)),
			gbmode: ::gbmode::Color,
			gbspeed: ::gbmode::Single,
			speed_switch_req: false,
			hdma_src: 0,
			hdma_dst: 0,
			hdma_status: NoDMA,
			hdma_len: 0xFF,
		};
		res.determine_mode();
		res.set_initial();
		return res;
	}

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

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

	pub fn get_mode(&self) -> ::gbmode::GbMode {
		self.gbmode
	}

	pub fn cycle(&mut self, cputicks: uint) -> uint {
		let dma_ticks = self.perform_vramdma();

		let gputicks =
			if self.gbspeed == ::gbmode::Single { cputicks }
			else { cputicks / 2 }
		+ dma_ticks;

		self.timer.cycle(cputicks + dma_ticks);
		self.intf |= self.timer.interrupt;
		self.timer.interrupt = 0;

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

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

		return gputicks;
	}

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

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

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

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

	pub fn switch_speed(&mut self) {
		if self.speed_switch_req {
			info!("Switching speed");
			if self.gbspeed == ::gbmode::Double {
				self.gbspeed = ::gbmode::Single;
			} else {
				self.gbspeed = ::gbmode::Double;
			}
		}
		self.speed_switch_req = false;
	}

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

	fn hdma_read(&self, a: u16) -> u8 {
		match a {
			0xFF51 .. 0xFF54 => { self.hdma[a - 0xFF51] },
			0xFF55 => self.hdma_len | if self.hdma_status == NoDMA { 0x80 } else { 0 },
			_ => fail!(),
		}
	}

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

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

				self.hdma_status =
					if v & 0x80 == 0x80 { HDMA }
					else { GDMA };
			},
			_ => fail!(),
		};
	}

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

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

		self.perform_vramdma_row();

		return 0x10 * 2;
	}

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

		self.hdma_status = NoDMA;
		return len * 0x10 * 2;
	}

	fn perform_vramdma_row(&mut self) {
		for j in range(0u16, 0x10) {
			let b: u8 = self.rb(self.hdma_src + j);
			self.gpu.wb(self.hdma_dst + j, b);
		}
		self.hdma_src += 0x10;
		self.hdma_dst += 0x10;
		self.hdma_len -= 1;
	}
}
<commit_msg>Updated speed switch code<commit_after>use serial::Serial;
use timer::Timer;
use keypad::Keypad;
use gpu::GPU;
use sound::Sound;

static WRAM_SIZE: uint = 0x8000;
static ZRAM_SIZE: uint = 0x7F;

#[deriving(Eq)]
enum DMAType {
	NoDMA,
	GDMA,
	HDMA,
}

pub struct MMU {
	priv wram: ~[u8, ..WRAM_SIZE],
	priv zram: ~[u8, ..ZRAM_SIZE],
	priv hdma: [u8, ..4],
	inte: u8,
	intf: u8,
	serial: Serial,
	timer: Timer,
	keypad: Keypad,
	gpu: GPU,
	sound: Sound,
	priv hdma_status: DMAType,
	priv hdma_src: u16,
	priv hdma_dst: u16,
	priv hdma_len: u8,
	priv wrambank: u8,
	priv mbc: ~::mbc::MBC,
	priv gbmode: ::gbmode::GbMode,
	priv gbspeed: ::gbmode::GbSpeed,
	priv speed_switch_req: bool,
}

impl MMU {
	pub fn new(romname: &str) -> MMU {
		let mut res = MMU {
			wram: ~([0, ..WRAM_SIZE]),
			zram: ~([0, ..ZRAM_SIZE]),
			hdma: [0, ..4],
			wrambank: 1,
			inte: 0,
			intf: 0,
			serial: Serial::new(),
			timer: Timer::new(),
			keypad: Keypad::new(),
			gpu: GPU::new(),
			sound: Sound::new(),
			mbc: ::mbc::get_mbc(&Path::new(romname)),
			gbmode: ::gbmode::Classic,
			gbspeed: ::gbmode::Single,
			speed_switch_req: false,
			hdma_src: 0,
			hdma_dst: 0,
			hdma_status: NoDMA,
			hdma_len: 0xFF,
		};
		if res.rb(0x0143) == 0xC0 {
			fail!("This game does not work in Classic mode");
		}
		res.set_initial();
		return res
	}

	pub fn new_cgb(romname: &str) -> MMU {
		let mut res = MMU {
			wram: ~([0,.. WRAM_SIZE]),
			zram: ~([0,.. ZRAM_SIZE]),
			wrambank: 1,
			hdma: [0,.. 4],
			inte: 0,
			intf: 0,
			serial: Serial::new(),
			timer: Timer::new(),
			keypad: Keypad::new(),
			gpu: GPU::new_cgb(),
			sound: Sound::new(),
			mbc: ::mbc::get_mbc(&Path::new(romname)),
			gbmode: ::gbmode::Color,
			gbspeed: ::gbmode::Single,
			speed_switch_req: false,
			hdma_src: 0,
			hdma_dst: 0,
			hdma_status: NoDMA,
			hdma_len: 0xFF,
		};
		res.determine_mode();
		res.set_initial();
		return res;
	}

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

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

	pub fn get_mode(&self) -> ::gbmode::GbMode {
		self.gbmode
	}

	pub fn cycle(&mut self, cputicks: uint) -> uint {
		let ticks = cputicks + self.perform_vramdma();

		let gputicks = ticks /
			if self.gbspeed == ::gbmode::Single { 1 }
			else { 2 };

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

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

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

		return gputicks;
	}

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

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

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

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

	pub fn switch_speed(&mut self) {
		if self.speed_switch_req {
			info!("Switching speed");
			if self.gbspeed == ::gbmode::Double {
				self.gbspeed = ::gbmode::Single;
			} else {
				self.gbspeed = ::gbmode::Double;
			}
		}
		self.speed_switch_req = false;
	}

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

	fn hdma_read(&self, a: u16) -> u8 {
		match a {
			0xFF51 .. 0xFF54 => { self.hdma[a - 0xFF51] },
			0xFF55 => self.hdma_len | if self.hdma_status == NoDMA { 0x80 } else { 0 },
			_ => fail!(),
		}
	}

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

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

				self.hdma_status =
					if v & 0x80 == 0x80 { HDMA }
					else { GDMA };
			},
			_ => fail!(),
		};
	}

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

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

		self.perform_vramdma_row();

		return 0x10 * (if self.gbspeed == ::gbmode::Single { 4 } else { 2 });
	}

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

		self.hdma_status = NoDMA;
		return len * 0x10 * 2;
	}

	fn perform_vramdma_row(&mut self) {
		for j in range(0u16, 0x10) {
			let b: u8 = self.rb(self.hdma_src + j);
			self.gpu.wb(self.hdma_dst + j, b);
		}
		self.hdma_src += 0x10;
		self.hdma_dst += 0x10;
		self.hdma_len -= 1;
	}
}
<|endoftext|>


<commit_before>#![feature(globs,macro_rules)]
#![desc = "Omnomnom incremental byte parser"]
#![license = "MIT"]

extern crate collections;

use std::fmt::Show;
use std::io::fs::File;
use std::io::{IoResult, IoErrorKind};
use self::IResult::*;
use self::ProducerState::*;
use std::kinds::Sized;

pub type Err = uint;
type IResultClosure<'a,I,O> = |I|:'a -> IResult<I,O>;

//type IResultClosure<'a,I,O> = |I|:'a -> IResult<'a,I,O>;
//type IResultClosure<'a,I,O> = Fn<I, IResult<'a,I,O>>;
#[deriving(Show,PartialEq,Eq)]
pub enum IResult<I,O> {
  Done(I,O),
  Error(Err),
  //Incomplete(IResultClosure<'a,I,O>)
  //Incomplete(|I|:'a -> IResult<'a,I,O>)
  //Incomplete(fn(I) -> IResult<'a,I,O>)
}

pub trait Mapper<O,N> for Sized? {
  fn flat_map(& self, f: |O| -> IResult<O,N>) -> IResult<O,N>;
  fn map_opt(& self, f: |O| -> Option<N>) -> IResult<O,N>;
}

impl<'a,R,S,T> Mapper<&'a[S], T> for IResult<R,&'a [S]> {
  fn flat_map(&self, f: |&'a[S]| -> IResult<&'a[S],T>) -> IResult<&'a[S],T> {
    match self {
      &Error(ref e) => Error(*e),
      //&Incomplete(ref cl) => Incomplete(f), //Incomplete(|input:I| { cl(input).map(f) })
      &Done(_, ref o) => f(*o)
    }
  }

  fn map_opt(&self, f: |&'a[S]| -> Option<T>) -> IResult<&'a[S],T> {
    match self {
      &Error(ref e) => Error(*e),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done(_, ref o) => match f(*o) {
        Some(output) => Done(*o, output),
        None         => Error(0)
      }
    }
  }
}

impl<R,T> Mapper<(), T> for IResult<R,()> {
  fn flat_map(&self, f: |()| -> IResult<(),T>) -> IResult<(),T> {
    match self {
      &Error(ref e) => Error(*e),
      //&Incomplete(ref cl) => Incomplete(f), //Incomplete(|input:I| { cl(input).map(f) })
      &Done(_, _) => f(())
    }
  }

  fn map_opt(&self, f: |()| -> Option<T>) -> IResult<(),T> {
    match self {
      &Error(ref e) => Error(*e),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done(_, __) => match f(()) {
        Some(output) => Done((), output),
        None         => Error(0)
      }
    }
  }
}

pub fn print<T: Show>(input: T) -> IResult<T, ()> {
  println!("{}", input);
  Done(input, ())
}

pub fn begin<'a>(input: &'a [u8]) -> IResult<(), &'a [u8]> {
  Done((), input)
}

#[macro_export]
macro_rules! tag(
  ($name:ident $inp:expr) => (
    fn $name(i:&[u8]) -> IResult<&[u8], &[u8]>{
      if i.len() >= $inp.len() && i.slice(0, $inp.len()) == $inp {
        Done(i.slice_from($inp.len()), i.slice(0, 0))
      } else {
        Error(0)
      }
    }
  )
)

macro_rules! c (
  ($name:ident<$i:ty,$o:ty>($f1:expr, $f2:expr)) => (
    fn $name(input:$i) -> IResult<$i, $o>{
      match $f1(input) {
        Error(e)  => Error(e),
        Done(i,_) => $f2(i)
      }
    }
  );
)

macro_rules! chain (
  ($name:ident<$i:ty,$o:ty>, $assemble:expr, $($rest:tt)*) => (
    fn $name(i:$i) -> IResult<$i,$o>{
      chaining_parser!(i, $assemble, $($rest)*)
    }
  );
)

macro_rules! chaining_parser (
  ($i:expr, $assemble:expr, $field:ident : $e:expr, $($rest:tt)*) => (
    match $e($i) {
      Error(e)  => Error(e),
      Done(i,o) => {
        let $field = o;
        chaining_parser!(i, $assemble, $($rest)*)
      }
    }
  );

  ($i:expr, $assemble:expr, ) => (
    Done($i, $assemble())
  )
)

#[deriving(Show,PartialEq,Eq)]
pub enum ProducerState<O> {
  Eof(O),
  Continue,
  Data(O),
  ProducerError(Err),
}

type IResultStarterClosure<'a,I,T,O> = |IResult<(),I>|:'a -> IResult<T,O>;

pub struct FileProducer {
  size: uint,
  file: File
}

impl FileProducer {
  pub fn new(filename: &str, buffer_size: uint) -> IoResult<FileProducer> {
    File::open(&Path::new(filename)).map(|f| { FileProducer {size: buffer_size, file: f} })
  }

  fn produce(&mut self) -> ProducerState<Vec<u8>> {
    let mut v = Vec::with_capacity(self.size);
    match self.file.push(self.size, &mut v) {
      Err(e) => {
        match e.kind {
          IoErrorKind::NoProgress => Continue,
          IoErrorKind::EndOfFile  => Eof(v),
          _          => ProducerError(0)
        }
      },
      Ok(i)  => {
        println!("read {} bytes", i);
        Data(v)
      }
    }
  }
/*}

impl Producer for FileProducer {
*/
  pub fn push<'y,O>(&mut self, f: |IResult<(),&[u8]>| -> IResult<&'y[u8],O>) {
    loop {
      if self.file.eof() {
        println!("end");
        break;
      }
      let state = self.produce();
      let mut acc: Vec<u8> = Vec::new();
      match state {
        ProducerError(e)  => println!("error: {}", e),
        Continue => {},
        Data(v) => {
          let mut v2 = Vec::new();
          v2.push_all(acc.as_slice());
          v2.push_all(v.as_slice());
          let p = Done((), v2.as_slice());
          match f(p) {
          //match f(begin(v2.as_slice())) {
            Error(e)      => println!("error, stopping: {}", e),
            //Incomplete(_) => println!("incomplete, continue"),
            Done(_, _)    => {
              //println!("end, done");
              acc.clear();
            }
          }
        },
        Eof(v) => {
          println!("GOT EOF");
          let mut v3 = Vec::new();
          v3.push_all(acc.as_slice());
          v3.push_all(v.as_slice());
          let p = Done((), v3.as_slice());
          match f(p) {
          //match f(begin(v2.as_slice())) {
            Error(e)      => println!("error, stopping: {}", e),
            //Incomplete(_) => println!("incomplete, continue"),
            Done(_, _)    => {
              println!("end, done");
              acc.clear();
            }
          };
          break;
        }
      }
      //v2.clear();
    }
    println!("end push");
  }
}

pub struct MemProducer<'x> {
  buffer: &'x [u8],
  chunk_size: uint,
  length: uint,
  index: uint
}

impl<'x> MemProducer<'x> {
  pub fn new(buffer: &'x[u8], chunk_size: uint) -> MemProducer {
    MemProducer {
      buffer:     buffer,
      chunk_size: chunk_size,
      length:     buffer.len(),
      index:      0
    }
  }

  fn produce(&mut self) -> ProducerState<&'x[u8]> {
    if self.index + self.chunk_size < self.length {
      println!("self.index + {} < self.length", self.chunk_size);
      let new_index = self.index+self.chunk_size;
      let res = Data(self.buffer.slice(self.index, new_index));
      self.index = new_index;
      res
    } else if self.index < self.length {
      println!("self.index < self.length - 1");
      let res = Eof(self.buffer.slice(self.index, self.length));
      self.index = self.length;
      res
    } else {
      ProducerError(0)
    }
  }

  /*
}

impl<'x> Producer for MemProducer<'x> {
*/
  fn push<'b,O>(&mut self, f: |IResult<(),&'b[u8]>| -> IResult<&'b[u8],O>) {
    loop {
      let state = self.produce();
      match state {
        ProducerError(e)  => {println!("error: {}", e);break;},
        Continue => {println!("continue should not happen");break;},
        Data(v) => {
          let p = Done((), v);
          match f(p) {
            Error(e)      => println!("error, stopping: {}", e),
            Done(_, _)    => {
              println!("data, done");
            }
          }
        },
        Eof(v) => {
          let p = Done((), v);
          match f(p) {
            Error(e)      => println!("error, stopping: {}", e),
            Done(_, _)    => {
              println!("eof, done");
            }
          }
          break;
        }
      }
    }
  }
}

#[test]
fn flat_map_fn_test() {
  Done((),()).flat_map(print);
}

#[test]
fn flat_map_closure_test() {
  Done((),()).flat_map(|data| { println!("data: {}", data); Done(data,())});
  //assert_eq!(decoded.number, 10);
}

#[test]
fn t1() {
  let v1:Vec<u8> = vec![1,2,3];
  let v2:Vec<u8> = vec![4,5,6];
  let d = Done(v1.as_slice(), v2.as_slice());
  let res = d.flat_map(print);
  assert_eq!(res, Done(v2.as_slice(), ()));
}

#[test]
fn mem_producer_test() {
  let mut p = MemProducer::new("abcdefgh".as_bytes(), 4);
  assert_eq!(p.produce(), Data("abcd".as_bytes()));
}

#[test]
fn mem_producer_test_2() {
  let mut p = MemProducer::new("abcdefgh".as_bytes(), 8);
  p.push(|par| par.flat_map(print));
  let mut iterations: uint = 0;
  let mut p = MemProducer::new("abcdefghi".as_bytes(), 4);
  p.push(|par| {iterations = iterations + 1; par.flat_map(print)});
  assert_eq!(iterations, 3);
}

#[test]
fn file_test() {
  FileProducer::new("links.txt", 20).map(|producer: FileProducer| {
    let mut p = producer;
    //p.push(|par| {println!("parsed file: {}", par); par});
    p.push(|par| par.flat_map(print));
  });
}

#[test]
fn tag_test() {
  FileProducer::new("links.txt", 20).map(|producer: FileProducer| {
    let mut p = producer;
    tag!(f "https://".as_bytes());
    p.push(|par| par.flat_map(f).flat_map(print));
  });
}

#[test]
fn chain_and_ignore_test() {
  tag!(x "abcd".as_bytes());
  fn retInt(i:&[u8]) -> IResult<&[u8], int> { Done(i,1) };
  c!(y<&[u8], int>(x, retInt));
  let r = Done((), "abcd".as_bytes()).flat_map(y);
  assert_eq!(r, Done("".as_bytes(), 1));
}

#[deriving(PartialEq,Eq,Show)]
struct B {
  a: int,
  b: int
}

#[test]
fn chain_test() {
  tag!(x "abcd".as_bytes());
  fn tempRetInt1(i:&[u8]) -> IResult<&[u8], int> { Done(i,1) };
  c!(retInt1<&[u8],int>(x, tempRetInt1));
  fn retInt2(i:&[u8]) -> IResult<&[u8], int> { Done(i,2) };
  chain!(f<&[u8],B>, ||{B{a: aa, b: bb}}, aa: retInt1, bb: retInt2,);
  let r = Done((), "abcde".as_bytes()).flat_map(f);
  assert_eq!(r, Done("e".as_bytes(), B{a: 1, b: 2}));
}

/* FIXME: this makes rustc weep
fn pr(par: IResult<(),&[u8]>) -> IResult<&[u8], ()> {
  Error(0)
}

#[test]
fn rustc_panic_test() {
  FileProducer::new("links.txt", 20).map(|producer: FileProducer| {
    let mut p = producer;
    p.push(pr);
  });
}*/
<commit_msg>can ignore tags left and right<commit_after>#![feature(globs,macro_rules)]
#![desc = "Omnomnom incremental byte parser"]
#![license = "MIT"]

extern crate collections;

use std::fmt::Show;
use std::io::fs::File;
use std::io::{IoResult, IoErrorKind};
use self::IResult::*;
use self::ProducerState::*;
use std::kinds::Sized;

pub type Err = uint;
type IResultClosure<'a,I,O> = |I|:'a -> IResult<I,O>;

//type IResultClosure<'a,I,O> = |I|:'a -> IResult<'a,I,O>;
//type IResultClosure<'a,I,O> = Fn<I, IResult<'a,I,O>>;
#[deriving(Show,PartialEq,Eq)]
pub enum IResult<I,O> {
  Done(I,O),
  Error(Err),
  //Incomplete(IResultClosure<'a,I,O>)
  //Incomplete(|I|:'a -> IResult<'a,I,O>)
  //Incomplete(fn(I) -> IResult<'a,I,O>)
}

pub trait Mapper<O,N> for Sized? {
  fn flat_map(& self, f: |O| -> IResult<O,N>) -> IResult<O,N>;
  fn map_opt(& self, f: |O| -> Option<N>) -> IResult<O,N>;
}

impl<'a,R,S,T> Mapper<&'a[S], T> for IResult<R,&'a [S]> {
  fn flat_map(&self, f: |&'a[S]| -> IResult<&'a[S],T>) -> IResult<&'a[S],T> {
    match self {
      &Error(ref e) => Error(*e),
      //&Incomplete(ref cl) => Incomplete(f), //Incomplete(|input:I| { cl(input).map(f) })
      &Done(_, ref o) => f(*o)
    }
  }

  fn map_opt(&self, f: |&'a[S]| -> Option<T>) -> IResult<&'a[S],T> {
    match self {
      &Error(ref e) => Error(*e),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done(_, ref o) => match f(*o) {
        Some(output) => Done(*o, output),
        None         => Error(0)
      }
    }
  }
}

impl<R,T> Mapper<(), T> for IResult<R,()> {
  fn flat_map(&self, f: |()| -> IResult<(),T>) -> IResult<(),T> {
    match self {
      &Error(ref e) => Error(*e),
      //&Incomplete(ref cl) => Incomplete(f), //Incomplete(|input:I| { cl(input).map(f) })
      &Done(_, _) => f(())
    }
  }

  fn map_opt(&self, f: |()| -> Option<T>) -> IResult<(),T> {
    match self {
      &Error(ref e) => Error(*e),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done(_, __) => match f(()) {
        Some(output) => Done((), output),
        None         => Error(0)
      }
    }
  }
}

pub fn print<T: Show>(input: T) -> IResult<T, ()> {
  println!("{}", input);
  Done(input, ())
}

pub fn begin<'a>(input: &'a [u8]) -> IResult<(), &'a [u8]> {
  Done((), input)
}

#[macro_export]
macro_rules! tag(
  ($name:ident $inp:expr) => (
    fn $name(i:&[u8]) -> IResult<&[u8], &[u8]>{
      if i.len() >= $inp.len() && i.slice(0, $inp.len()) == $inp {
        Done(i.slice_from($inp.len()), i.slice(0, 0))
      } else {
        Error(0)
      }
    }
  )
)

macro_rules! o (
  ($name:ident<$i:ty,$o:ty> $f1:expr $($rest:tt)*) => (
    fn $name(input:$i) -> IResult<$i, $o>{
      match $f1(input) {
        Error(e)  => Error(e),
        Done(i,o) => {
          o_parser!(i o $($rest)*)
        }
      }
    }
  );
)

macro_rules! o_parser (
  ($i:expr $o:expr) => (Done($i,$o));

  ($i:expr $o:expr ~ $e:expr ~ $($rest:tt)*) => (
    match $e($i) {
      Error(e)  => Error(e),
      Done(i,o) => {
        o_parser!(i o $($rest)*)
      }
    }

   );
  ($i:expr $o:expr $e:expr $($rest:tt)*) => (
    match $e($i) {
      Error(e)  => Error(e),
      Done(i,_) => {
        o_parser!(i $o $($rest)*)
      }
    }
   );
)

macro_rules! chain (
  ($name:ident<$i:ty,$o:ty>, $assemble:expr, $($rest:tt)*) => (
    fn $name(i:$i) -> IResult<$i,$o>{
      chaining_parser!(i, $assemble, $($rest)*)
    }
  );
)

macro_rules! chaining_parser (
  ($i:expr, $assemble:expr, $field:ident : $e:expr, $($rest:tt)*) => (
    match $e($i) {
      Error(e)  => Error(e),
      Done(i,o) => {
        let $field = o;
        chaining_parser!(i, $assemble, $($rest)*)
      }
    }
  );

  ($i:expr, $assemble:expr, ) => (
    Done($i, $assemble())
  )
)

#[deriving(Show,PartialEq,Eq)]
pub enum ProducerState<O> {
  Eof(O),
  Continue,
  Data(O),
  ProducerError(Err),
}

type IResultStarterClosure<'a,I,T,O> = |IResult<(),I>|:'a -> IResult<T,O>;

pub struct FileProducer {
  size: uint,
  file: File
}

impl FileProducer {
  pub fn new(filename: &str, buffer_size: uint) -> IoResult<FileProducer> {
    File::open(&Path::new(filename)).map(|f| { FileProducer {size: buffer_size, file: f} })
  }

  fn produce(&mut self) -> ProducerState<Vec<u8>> {
    let mut v = Vec::with_capacity(self.size);
    match self.file.push(self.size, &mut v) {
      Err(e) => {
        match e.kind {
          IoErrorKind::NoProgress => Continue,
          IoErrorKind::EndOfFile  => Eof(v),
          _          => ProducerError(0)
        }
      },
      Ok(i)  => {
        println!("read {} bytes", i);
        Data(v)
      }
    }
  }
/*}

impl Producer for FileProducer {
*/
  pub fn push<'y,O>(&mut self, f: |IResult<(),&[u8]>| -> IResult<&'y[u8],O>) {
    loop {
      if self.file.eof() {
        println!("end");
        break;
      }
      let state = self.produce();
      let mut acc: Vec<u8> = Vec::new();
      match state {
        ProducerError(e)  => println!("error: {}", e),
        Continue => {},
        Data(v) => {
          let mut v2 = Vec::new();
          v2.push_all(acc.as_slice());
          v2.push_all(v.as_slice());
          let p = Done((), v2.as_slice());
          match f(p) {
          //match f(begin(v2.as_slice())) {
            Error(e)      => println!("error, stopping: {}", e),
            //Incomplete(_) => println!("incomplete, continue"),
            Done(_, _)    => {
              //println!("end, done");
              acc.clear();
            }
          }
        },
        Eof(v) => {
          println!("GOT EOF");
          let mut v3 = Vec::new();
          v3.push_all(acc.as_slice());
          v3.push_all(v.as_slice());
          let p = Done((), v3.as_slice());
          match f(p) {
          //match f(begin(v2.as_slice())) {
            Error(e)      => println!("error, stopping: {}", e),
            //Incomplete(_) => println!("incomplete, continue"),
            Done(_, _)    => {
              println!("end, done");
              acc.clear();
            }
          };
          break;
        }
      }
      //v2.clear();
    }
    println!("end push");
  }
}

pub struct MemProducer<'x> {
  buffer: &'x [u8],
  chunk_size: uint,
  length: uint,
  index: uint
}

impl<'x> MemProducer<'x> {
  pub fn new(buffer: &'x[u8], chunk_size: uint) -> MemProducer {
    MemProducer {
      buffer:     buffer,
      chunk_size: chunk_size,
      length:     buffer.len(),
      index:      0
    }
  }

  fn produce(&mut self) -> ProducerState<&'x[u8]> {
    if self.index + self.chunk_size < self.length {
      println!("self.index + {} < self.length", self.chunk_size);
      let new_index = self.index+self.chunk_size;
      let res = Data(self.buffer.slice(self.index, new_index));
      self.index = new_index;
      res
    } else if self.index < self.length {
      println!("self.index < self.length - 1");
      let res = Eof(self.buffer.slice(self.index, self.length));
      self.index = self.length;
      res
    } else {
      ProducerError(0)
    }
  }

  /*
}

impl<'x> Producer for MemProducer<'x> {
*/
  fn push<'b,O>(&mut self, f: |IResult<(),&'b[u8]>| -> IResult<&'b[u8],O>) {
    loop {
      let state = self.produce();
      match state {
        ProducerError(e)  => {println!("error: {}", e);break;},
        Continue => {println!("continue should not happen");break;},
        Data(v) => {
          let p = Done((), v);
          match f(p) {
            Error(e)      => println!("error, stopping: {}", e),
            Done(_, _)    => {
              println!("data, done");
            }
          }
        },
        Eof(v) => {
          let p = Done((), v);
          match f(p) {
            Error(e)      => println!("error, stopping: {}", e),
            Done(_, _)    => {
              println!("eof, done");
            }
          }
          break;
        }
      }
    }
  }
}

#[test]
fn flat_map_fn_test() {
  Done((),()).flat_map(print);
}

#[test]
fn flat_map_closure_test() {
  Done((),()).flat_map(|data| { println!("data: {}", data); Done(data,())});
  //assert_eq!(decoded.number, 10);
}

#[test]
fn t1() {
  let v1:Vec<u8> = vec![1,2,3];
  let v2:Vec<u8> = vec![4,5,6];
  let d = Done(v1.as_slice(), v2.as_slice());
  let res = d.flat_map(print);
  assert_eq!(res, Done(v2.as_slice(), ()));
}

#[test]
fn mem_producer_test() {
  let mut p = MemProducer::new("abcdefgh".as_bytes(), 4);
  assert_eq!(p.produce(), Data("abcd".as_bytes()));
}

#[test]
fn mem_producer_test_2() {
  let mut p = MemProducer::new("abcdefgh".as_bytes(), 8);
  p.push(|par| par.flat_map(print));
  let mut iterations: uint = 0;
  let mut p = MemProducer::new("abcdefghi".as_bytes(), 4);
  p.push(|par| {iterations = iterations + 1; par.flat_map(print)});
  assert_eq!(iterations, 3);
}

#[test]
fn file_test() {
  FileProducer::new("links.txt", 20).map(|producer: FileProducer| {
    let mut p = producer;
    //p.push(|par| {println!("parsed file: {}", par); par});
    p.push(|par| par.flat_map(print));
  });
}

#[test]
fn tag_test() {
  FileProducer::new("links.txt", 20).map(|producer: FileProducer| {
    let mut p = producer;
    tag!(f "https://".as_bytes());
    p.push(|par| par.flat_map(f).flat_map(print));
  });
}

#[deriving(PartialEq,Eq,Show)]
struct B {
  a: int,
  b: int
}

#[test]
fn chain_and_ignore_test() {
  tag!(x "abcd".as_bytes());
  tag!(y "efgh".as_bytes());
  fn retInt(i:&[u8]) -> IResult<&[u8], int> { Done(i,1) };
  //o!(z<&[u8], int>  x S x S retInt Z y);
  o!(z<&[u8], int>  x  x ~retInt~ y);

  let r = Done((), "abcdabcdefgh".as_bytes()).flat_map(z);
  assert_eq!(r, Done("".as_bytes(), 1));
}

#[test]
fn chain_test() {
  tag!(x "abcd".as_bytes());
  fn tempRetInt1(i:&[u8]) -> IResult<&[u8], int> { Done(i,1) };
  o!(retInt1<&[u8],int> x ~ tempRetInt1 ~);
  fn retInt2(i:&[u8]) -> IResult<&[u8], int> { Done(i,2) };
  chain!(f<&[u8],B>, ||{B{a: aa, b: bb}}, aa: retInt1, bb: retInt2,);

  let r = Done((), "abcde".as_bytes()).flat_map(f);
  assert_eq!(r, Done("e".as_bytes(), B{a: 1, b: 2}));
}

/* FIXME: this makes rustc weep
fn pr(par: IResult<(),&[u8]>) -> IResult<&[u8], ()> {
  Error(0)
}

#[test]
fn rustc_panic_test() {
  FileProducer::new("links.txt", 20).map(|producer: FileProducer| {
    let mut p = producer;
    p.push(pr);
  });
}*/
<|endoftext|>


<commit_before>//! The functions in this section provide optimized copying to persistent memory
//!
//! The `copy`, `copy_nonoverlapping`, and `write_bytes`, provide the same memory copying as
//! `memmove(3)`, `memcpy(3)`, and `memset(3)`, and ensure that the result has been flushed to persistence before returning.
//!
//! > **Warning:** Using these functions where `is_pmem(1)` returns false may not do anything useful.
//! >              Use the normal libc functions in that case.

use ::std::mem;
use ::std::io;
use ::std::marker::PhantomData;

use ::libc::{c_void, c_int};
use ::libc::size_t;
use ::pmem_sys as ffi;

use pmap::PersistentMap;

/// Persistent memory virtual pointer
///
/// This pointer is safe to store.
pub struct PmemConstVirtualPtr<T: ?Sized> {
    poolid: usize,
    offset: usize,
    _t: PhantomData<T>,
}

impl<T: ?Sized> PmemConstVirtualPtr<T> {
    pub unsafe fn new(poolid: usize, offset: usize) -> Self {
        assert!(poolid != 0, "Poolid 0 is reserved for null pointers");
        PmemConstVirtualPtr { poolid: poolid, offset: offset, _t: PhantomData }
    }

    pub fn null() -> Self { PmemConstVirtualPtr { poolid: 0, offset: 0, _t: PhantomData } }

    pub fn is_null(&self) -> bool { self.poolid == 0 }
}

impl<T> PmemConstVirtualPtr<T> {
    pub unsafe fn offset(&self, count: isize) -> Self {
        if self.is_null() {
            PmemConstVirtualPtr::null()
        } else {
            let new_offset = self.offset as isize + mem::size_of::<T>() as isize * count;
            PmemConstVirtualPtr { poolid: self.poolid, offset: new_offset as usize, _t: self._t }
        }
    }

    pub unsafe fn link(self, pool: &PersistentMap) -> PmemConstPtr<T> {
        PmemConstPtr { virt: self, pool: pool.as_ptr() }
    }
}

/// Persistent memory virtual mutable pointer
///
/// This pointer is safe to store.
pub struct PmemMutVirtualPtr<T: ?Sized> {
    poolid: usize,
    offset: usize,
    _t: PhantomData<T>,
}

impl<T: ?Sized> PmemMutVirtualPtr<T> {
    pub unsafe fn new(poolid: usize, offset: usize) -> Self {
        assert!(poolid != 0, "Poolid 0 is reserved for null pointers");
        PmemMutVirtualPtr { poolid: poolid, offset: offset, _t: PhantomData }
    }

    pub fn null() -> Self { PmemMutVirtualPtr { poolid: 0, offset: 0, _t: PhantomData } }

    pub fn is_null(&self) -> bool { self.poolid == 0 }
}

impl<T> PmemMutVirtualPtr<T> {
    pub unsafe fn offset(&self, count: isize) -> Self {
        if self.is_null() {
            PmemMutVirtualPtr::null()
        } else {
            let new_offset = self.offset as isize + mem::size_of::<T>() as isize * count;
            PmemMutVirtualPtr { poolid: self.poolid, offset: new_offset as usize, _t: self._t }
        }
    }

    pub unsafe fn link(self, pool: &mut PersistentMap) -> PmemMutPtr<T> {
        PmemMutPtr { virt: self, pool: pool.as_mut_ptr() }
    }
}

/// Direct `*const T` pointer to a pmem location
///
/// # Safety
///
/// This pointer is **not** safe to store directly on pmem.
/// You can get a _safe_ virtual pointer using `as_virtual()`.
pub struct PmemConstPtr<T: ?Sized> {
    virt: PmemConstVirtualPtr<T>,
    pool: *const T,
}

impl<T> PmemConstPtr<T> {
    pub unsafe fn direct(&self) -> *const T {
        self.pool.offset(self.virt.offset as isize) as *const T
    }

    pub fn as_virtual(self) -> PmemConstVirtualPtr<T> {
        self.virt
    }
}

/// Direct `*mut T` pointer to a pmem location
///
/// # Safety
///
/// This pointer is **not** safe to store directly on pmem.
/// You can get a _safe_ virtual pointer using `as_virtual()`.
pub struct PmemMutPtr<T: ?Sized> {
    virt: PmemMutVirtualPtr<T>,
    pool: *mut T,
}

impl<T> PmemMutPtr<T> {
    pub unsafe fn direct(&self) -> *mut T {
        self.pool.offset(self.virt.offset as isize) as *mut T
    }

    pub fn as_virtual(self) -> PmemMutVirtualPtr<T> {
        self.virt
    }
}

/// Copies `count * size_of<T>` bytes from `src` to `pmemdest`. The source and destination may overlap.
///
/// `copy` is semantically equivalent to C's `memmove` and is optimized for persitent memory.
///
/// Ensures that the result has been flushed to persistence before returning.
///
/// # Safety
///
/// Care must be taken with the ownership of `src` and `pmemdest`.
/// This method semantically moves the values of `src` into `pmemdest`.
/// However it does not drop the contents of `pmemdest`, or prevent the contents of `src` from being dropped or used.
pub unsafe fn copy<T>(src: *const T, pmemdest: *mut T, count: usize) {
    let len = mem::size_of::<T>() * count;
    ffi::pmem_memmove_persist(pmemdest as *mut c_void, src as *const c_void, len as size_t);
}

/// Copies `count * size_of<T>` bytes from `src` to `pmemdest`. The source and destination may _not_ overlap.
///
/// `copy_nonoverlapping` is semantically equivalent to C's `memcpy` and is optimized for persitent memory.
///
/// Ensures that the result has been flushed to persistence before returning.
///
/// # Safety
///
/// Beyond requiring that the program must be allowed to access both regions of memory,
/// it is _Undefined Behavior_ for source and destination to overlap.
/// Care must also be taken with the ownership of `src` and `pmemdest`.
/// This method semantically moves the values of `src` into `pmemdest`.
/// However it does not drop the contents of `pmemdest`, or prevent the contents of `src` from being dropped or used.
pub unsafe fn copy_nonoverlapping<T>(src: *const T, pmemdest: *mut T, count: usize) {
    let len = mem::size_of::<T>() * count;
    ffi::pmem_memcpy_persist(pmemdest as *mut c_void, src as *const c_void, len as size_t);
}

/// Invokes memset on the specified pointer, setting `count * size_of::<T>()` bytes of memory starting at `pmemdest` to `val`.
///
/// Ensures that the result has been flushed to persistence before returning.
pub unsafe fn write_bytes<T>(pmemdest: *mut T, val: u8, count: usize) {
    let len = mem::size_of::<T>() * count;
    ffi::pmem_memset_persist(pmemdest as *mut c_void, val as c_int, len as size_t);
}

/// Overwrites a memory location with the given value without reading or dropping the old value.
///
/// Ensures that the result has been flushed to persistence before returning.
///
/// # Safety
///
/// This operation is marked unsafe because it accepts a raw pointer.
///
/// It does not drop the contents of dst. This is safe, but it could leak allocations or resources,
/// so care must be taken not to overwrite an object that should be dropped.
///
/// This is appropriate for initializing uninitialized memory, or overwriting memory that has previously been read from.
pub unsafe fn write<T>(pmemdest: *mut T, val: T) { copy_nonoverlapping(&val as *const _, pmemdest, 1) }

pub unsafe fn msync<T>(pmemdest: *const T, count: usize) -> Result<(), io::Error> {
    let len = count * mem::size_of::<T>();
    let r = ffi::pmem_msync(pmemdest as *const c_void, len as size_t);
    if r == -1 {
        Err(io::Error::last_os_error())
    } else {
        Ok(())
    }
}
<commit_msg>feat: add offset on direct ptrs<commit_after>//! The functions in this section provide optimized copying to persistent memory
//!
//! The `copy`, `copy_nonoverlapping`, and `write_bytes`, provide the same memory copying as
//! `memmove(3)`, `memcpy(3)`, and `memset(3)`, and ensure that the result has been flushed to persistence before returning.
//!
//! > **Warning:** Using these functions where `is_pmem(1)` returns false may not do anything useful.
//! >              Use the normal libc functions in that case.

use ::std::mem;
use ::std::io;
use ::std::marker::PhantomData;

use ::libc::{c_void, c_int};
use ::libc::size_t;
use ::pmem_sys as ffi;

use pmap::PersistentMap;

/// Persistent memory virtual pointer
///
/// This pointer is safe to store.
pub struct PmemConstVirtualPtr<T: ?Sized> {
    poolid: usize,
    offset: usize,
    _t: PhantomData<T>,
}

impl<T: ?Sized> PmemConstVirtualPtr<T> {
    pub unsafe fn new(poolid: usize, offset: usize) -> Self {
        assert!(poolid != 0, "Poolid 0 is reserved for null pointers");
        PmemConstVirtualPtr { poolid: poolid, offset: offset, _t: PhantomData }
    }

    pub fn null() -> Self { PmemConstVirtualPtr { poolid: 0, offset: 0, _t: PhantomData } }

    pub fn is_null(&self) -> bool { self.poolid == 0 }
}

impl<T> PmemConstVirtualPtr<T> {
    pub unsafe fn offset(&self, count: isize) -> Self {
        if self.is_null() {
            PmemConstVirtualPtr::null()
        } else {
            let new_offset = self.offset as isize + mem::size_of::<T>() as isize * count;
            PmemConstVirtualPtr { poolid: self.poolid, offset: new_offset as usize, _t: self._t }
        }
    }

    pub unsafe fn link(self, pool: &PersistentMap) -> PmemConstPtr<T> {
        PmemConstPtr { virt: self, pool: pool.as_ptr() }
    }
}

/// Persistent memory virtual mutable pointer
///
/// This pointer is safe to store.
pub struct PmemMutVirtualPtr<T: ?Sized> {
    poolid: usize,
    offset: usize,
    _t: PhantomData<T>,
}

impl<T: ?Sized> PmemMutVirtualPtr<T> {
    pub unsafe fn new(poolid: usize, offset: usize) -> Self {
        assert!(poolid != 0, "Poolid 0 is reserved for null pointers");
        PmemMutVirtualPtr { poolid: poolid, offset: offset, _t: PhantomData }
    }

    pub fn null() -> Self { PmemMutVirtualPtr { poolid: 0, offset: 0, _t: PhantomData } }

    pub fn is_null(&self) -> bool { self.poolid == 0 }
}

impl<T> PmemMutVirtualPtr<T> {
    pub unsafe fn offset(&self, count: isize) -> Self {
        if self.is_null() {
            PmemMutVirtualPtr::null()
        } else {
            let new_offset = self.offset as isize + mem::size_of::<T>() as isize * count;
            PmemMutVirtualPtr { poolid: self.poolid, offset: new_offset as usize, _t: self._t }
        }
    }

    pub unsafe fn link(self, pool: &mut PersistentMap) -> PmemMutPtr<T> {
        PmemMutPtr { virt: self, pool: pool.as_mut_ptr() }
    }
}

/// Direct `*const T` pointer to a pmem location
///
/// # Safety
///
/// This pointer is **not** safe to store directly on pmem.
/// You can get a _safe_ virtual pointer using `as_virtual()`.
pub struct PmemConstPtr<T: ?Sized> {
    virt: PmemConstVirtualPtr<T>,
    pool: *const T,
}

impl<T> PmemConstPtr<T> {
    pub unsafe fn direct(&self) -> *const T {
        self.pool.offset(self.virt.offset as isize) as *const T
    }

    pub fn as_virtual(self) -> PmemConstVirtualPtr<T> {
        self.virt
    }

    pub unsafe fn offset(&self, count: isize) -> Self {
        let new_virt = self.virt.offset(count);
        PmemConstPtr { virt: new_virt, pool: self.pool }
    }
}

/// Direct `*mut T` pointer to a pmem location
///
/// # Safety
///
/// This pointer is **not** safe to store directly on pmem.
/// You can get a _safe_ virtual pointer using `as_virtual()`.
pub struct PmemMutPtr<T: ?Sized> {
    virt: PmemMutVirtualPtr<T>,
    pool: *mut T,
}

impl<T> PmemMutPtr<T> {
    pub unsafe fn direct(&self) -> *mut T {
        self.pool.offset(self.virt.offset as isize) as *mut T
    }

    pub fn as_virtual(self) -> PmemMutVirtualPtr<T> {
        self.virt
    }

    pub unsafe fn offset(&self, count: isize) -> Self {
        let new_virt = self.virt.offset(count);
        PmemMutPtr { virt: new_virt, pool: self.pool }
    }
}

/// Copies `count * size_of<T>` bytes from `src` to `pmemdest`. The source and destination may overlap.
///
/// `copy` is semantically equivalent to C's `memmove` and is optimized for persitent memory.
///
/// Ensures that the result has been flushed to persistence before returning.
///
/// # Safety
///
/// Care must be taken with the ownership of `src` and `pmemdest`.
/// This method semantically moves the values of `src` into `pmemdest`.
/// However it does not drop the contents of `pmemdest`, or prevent the contents of `src` from being dropped or used.
pub unsafe fn copy<T>(src: *const T, pmemdest: *mut T, count: usize) {
    let len = mem::size_of::<T>() * count;
    ffi::pmem_memmove_persist(pmemdest as *mut c_void, src as *const c_void, len as size_t);
}

/// Copies `count * size_of<T>` bytes from `src` to `pmemdest`. The source and destination may _not_ overlap.
///
/// `copy_nonoverlapping` is semantically equivalent to C's `memcpy` and is optimized for persitent memory.
///
/// Ensures that the result has been flushed to persistence before returning.
///
/// # Safety
///
/// Beyond requiring that the program must be allowed to access both regions of memory,
/// it is _Undefined Behavior_ for source and destination to overlap.
/// Care must also be taken with the ownership of `src` and `pmemdest`.
/// This method semantically moves the values of `src` into `pmemdest`.
/// However it does not drop the contents of `pmemdest`, or prevent the contents of `src` from being dropped or used.
pub unsafe fn copy_nonoverlapping<T>(src: *const T, pmemdest: *mut T, count: usize) {
    let len = mem::size_of::<T>() * count;
    ffi::pmem_memcpy_persist(pmemdest as *mut c_void, src as *const c_void, len as size_t);
}

/// Invokes memset on the specified pointer, setting `count * size_of::<T>()` bytes of memory starting at `pmemdest` to `val`.
///
/// Ensures that the result has been flushed to persistence before returning.
pub unsafe fn write_bytes<T>(pmemdest: *mut T, val: u8, count: usize) {
    let len = mem::size_of::<T>() * count;
    ffi::pmem_memset_persist(pmemdest as *mut c_void, val as c_int, len as size_t);
}

/// Overwrites a memory location with the given value without reading or dropping the old value.
///
/// Ensures that the result has been flushed to persistence before returning.
///
/// # Safety
///
/// This operation is marked unsafe because it accepts a raw pointer.
///
/// It does not drop the contents of dst. This is safe, but it could leak allocations or resources,
/// so care must be taken not to overwrite an object that should be dropped.
///
/// This is appropriate for initializing uninitialized memory, or overwriting memory that has previously been read from.
pub unsafe fn write<T>(pmemdest: *mut T, val: T) { copy_nonoverlapping(&val as *const _, pmemdest, 1) }

pub unsafe fn msync<T>(pmemdest: *const T, count: usize) -> Result<(), io::Error> {
    let len = count * mem::size_of::<T>();
    let r = ffi::pmem_msync(pmemdest as *const c_void, len as size_t);
    if r == -1 {
        Err(io::Error::last_os_error())
    } else {
        Ok(())
    }
}
<|endoftext|>