<commit_before>extern crate libc;
extern crate winapi;
extern crate kernel32;

/// Allocates `size` Bytes aligned to `align` Bytes. Returns a null pointer on allocation failure.
///
/// The returned pointer must be deallocated by using `aligned_free`.
///
/// Note: This function is meant to be used for infrequent large allocations (as `malloc` already
/// guarantees suitable alignment for all native datatypes) and might be quite slow when used
/// heavily.
///
/// # Parameters
///
/// * `size`: The size of the allocation in bytes.
/// * `align`: The alignment of the allocation (at least the size of `usize` on the current
///   platform). Must also be a power of two.
#[inline]
pub fn aligned_alloc(size: usize, align: usize) -> *mut () {
    imp::aligned_alloc(size, align)
}

/// Deallocates aligned memory that was allocated with `aligned_alloc`. Unsafe because calling this
/// with a pointer that was not allocated with `aligned_alloc` (or already released) causes
/// undefined behavior.
#[inline]
pub unsafe fn aligned_free(ptr: *mut ()) {
    imp::aligned_free(ptr)
}

#[cfg(unix)]
mod imp {
    use libc::{c_void, c_int, size_t, EINVAL, ENOMEM, free};

    use std::{mem, ptr};

    extern "C" {
        fn posix_memalign(memptr: *mut *mut c_void, alignment: size_t, size: size_t) -> c_int;
    }

    pub fn aligned_alloc(size: usize, align: usize) -> *mut () {
        let mut memptr: *mut c_void = ptr::null_mut();
        let result = unsafe { posix_memalign(&mut memptr, align as size_t, size as size_t) };
        match result {
            0 => return memptr as *mut (),
            EINVAL => {
                if align < mem::size_of::<usize>() {
                    panic!("EINVAL: invalid alignment: {} (minimum is {})", align,
                        mem::size_of::<usize>());
                }
                if !align.is_power_of_two() {
                    panic!("EINVAL: invalid alignment: {} (must be a power of two)", align)
                }
                panic!("EINVAL: invalid alignment: {}", align);
            }
            ENOMEM => return ptr::null_mut(),
            _ => unreachable!(),
        }
    }

    #[inline]
    pub unsafe fn aligned_free(ptr: *mut ()) {
        free(ptr as *mut c_void)
    }
}

#[cfg(windows)]
mod imp {
    use kernel32::{GetLastError, GetSystemInfo, VirtualAlloc, VirtualFree};
    use winapi::{MEM_COMMIT, MEM_RESERVE, MEM_RELEASE, PAGE_NOACCESS, PAGE_READWRITE, SIZE_T,
        LPVOID, DWORD, SYSTEM_INFO};

    use std::mem;
    use std::ptr;

    static mut PAGE_SIZE: DWORD = 0;

    #[cold]
    fn get_page_size() {
        let mut info: SYSTEM_INFO = unsafe { mem::uninitialized() };
        unsafe { GetSystemInfo(&mut info); }

        unsafe {
            PAGE_SIZE = info.dwPageSize;
        }
    }

    pub fn aligned_alloc(size: usize, align: usize) -> *mut () {
        assert!(align.is_power_of_two(), "align must be a power of two");

        if unsafe { PAGE_SIZE } == 0 { get_page_size() }

        unsafe {
            if align <= PAGE_SIZE as usize {
                // Page alignment is guaranteed by `VirtualAlloc`
                let ptr = VirtualAlloc(ptr::null_mut(), size as SIZE_T, MEM_COMMIT | MEM_RESERVE,
                    PAGE_READWRITE);
                return ptr as *mut ()
            }

            // Step 1: Reserve `size+align-1` Bytes of address space to find a suitable address
            let ptr = VirtualAlloc(ptr::null_mut(), (size + align - 1) as SIZE_T, MEM_RESERVE,
                PAGE_NOACCESS);
            if ptr.is_null() { return ptr::null_mut() }

            // Step 2: Calculate an aligned address within the reserved range
            // (this works because `align` must be a power of two)
            let aligned_ptr = (ptr as usize + align - 1) & !(align - 1);

            // Step 3: Actually allocate (commit) the memory
            let res = VirtualFree(ptr as LPVOID, 0, MEM_RELEASE);
            if res == 0 {
                panic!("WINAPI error {} while freeing reserved memory", GetLastError());
            }
            let ptr = VirtualAlloc(aligned_ptr as LPVOID, size as SIZE_T, MEM_COMMIT | MEM_RESERVE,
                PAGE_READWRITE);
            ptr as *mut ()
        }
    }

    pub unsafe fn aligned_free(ptr: *mut ()) {
        let res = VirtualFree(ptr as LPVOID, 0, MEM_RELEASE);
        if res == 0 {
            panic!("WINAPI error {} while releasing memory", GetLastError());
        }
    }
}

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

    #[test]
    fn test_low_align() {
        let ptr = aligned_alloc(1, 128);
        assert!(!ptr.is_null());
        assert!(ptr as usize % 128 == 0);
        unsafe { aligned_free(ptr) }
    }

    #[test]
    fn test_high_align() {
        let ptr = aligned_alloc(1, 1024 * 1024);
        assert!(!ptr.is_null());
        assert!(ptr as usize % (1024 * 1024) == 0);
        unsafe { aligned_free(ptr) }
    }
}
<commit_msg>Add more tests<commit_after>extern crate libc;
extern crate winapi;
extern crate kernel32;

/// Allocates `size` Bytes aligned to `align` Bytes. Returns a null pointer on allocation failure.
///
/// The returned pointer must be deallocated by using `aligned_free`.
///
/// Note: This function is meant to be used for infrequent large allocations (as `malloc` already
/// guarantees suitable alignment for all native datatypes) and might be quite slow when used
/// heavily.
///
/// # Parameters
///
/// * `size`: The size of the allocation in bytes.
/// * `align`: The alignment of the allocation (at least the size of `usize` on the current
///   platform). Must also be a power of two.
#[inline]
pub fn aligned_alloc(size: usize, align: usize) -> *mut () {
    imp::aligned_alloc(size, align)
}

/// Deallocates aligned memory that was allocated with `aligned_alloc`. Unsafe because calling this
/// with a pointer that was not allocated with `aligned_alloc` (or already released) causes
/// undefined behavior.
#[inline]
pub unsafe fn aligned_free(ptr: *mut ()) {
    imp::aligned_free(ptr)
}

#[cfg(unix)]
mod imp {
    use libc::{c_void, c_int, size_t, EINVAL, ENOMEM, free};

    use std::{mem, ptr};

    extern "C" {
        fn posix_memalign(memptr: *mut *mut c_void, alignment: size_t, size: size_t) -> c_int;
    }

    pub fn aligned_alloc(size: usize, align: usize) -> *mut () {
        let mut memptr: *mut c_void = ptr::null_mut();
        let result = unsafe { posix_memalign(&mut memptr, align as size_t, size as size_t) };
        match result {
            0 => return memptr as *mut (),
            EINVAL => {
                if align < mem::size_of::<usize>() {
                    panic!("EINVAL: invalid alignment: {} (minimum is {})", align,
                        mem::size_of::<usize>());
                }
                if !align.is_power_of_two() {
                    panic!("EINVAL: invalid alignment: {} (must be a power of two)", align)
                }
                panic!("EINVAL: invalid alignment: {}", align);
            }
            ENOMEM => return ptr::null_mut(),
            _ => unreachable!(),
        }
    }

    #[inline]
    pub unsafe fn aligned_free(ptr: *mut ()) {
        free(ptr as *mut c_void)
    }
}

#[cfg(windows)]
mod imp {
    use kernel32::{GetLastError, GetSystemInfo, VirtualAlloc, VirtualFree};
    use winapi::{MEM_COMMIT, MEM_RESERVE, MEM_RELEASE, PAGE_NOACCESS, PAGE_READWRITE, SIZE_T,
        LPVOID, DWORD, SYSTEM_INFO};

    use std::mem;
    use std::ptr;

    static mut PAGE_SIZE: DWORD = 0;

    #[cold]
    fn get_page_size() {
        let mut info: SYSTEM_INFO = unsafe { mem::uninitialized() };
        unsafe { GetSystemInfo(&mut info); }

        unsafe {
            PAGE_SIZE = info.dwPageSize;
        }
    }

    pub fn aligned_alloc(size: usize, align: usize) -> *mut () {
        assert!(align.is_power_of_two(), "align must be a power of two");

        if unsafe { PAGE_SIZE } == 0 { get_page_size() }

        unsafe {
            if align <= PAGE_SIZE as usize {
                // Page alignment is guaranteed by `VirtualAlloc`
                let ptr = VirtualAlloc(ptr::null_mut(), size as SIZE_T, MEM_COMMIT | MEM_RESERVE,
                    PAGE_READWRITE);
                return ptr as *mut ()
            }

            // Step 1: Reserve `size+align-1` Bytes of address space to find a suitable address
            let ptr = VirtualAlloc(ptr::null_mut(), (size + align - 1) as SIZE_T, MEM_RESERVE,
                PAGE_NOACCESS);
            if ptr.is_null() { return ptr::null_mut() }

            // Step 2: Calculate an aligned address within the reserved range
            // (this works because `align` must be a power of two)
            let aligned_ptr = (ptr as usize + align - 1) & !(align - 1);

            // Step 3: Actually allocate (commit) the memory
            let res = VirtualFree(ptr as LPVOID, 0, MEM_RELEASE);
            if res == 0 {
                panic!("WINAPI error {} while freeing reserved memory", GetLastError());
            }
            let ptr = VirtualAlloc(aligned_ptr as LPVOID, size as SIZE_T, MEM_COMMIT | MEM_RESERVE,
                PAGE_READWRITE);
            ptr as *mut ()
        }
    }

    pub unsafe fn aligned_free(ptr: *mut ()) {
        let res = VirtualFree(ptr as LPVOID, 0, MEM_RELEASE);
        if res == 0 {
            panic!("WINAPI error {} while releasing memory", GetLastError());
        }
    }
}

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

    #[test]
    fn small_low_align() {
        let ptr = aligned_alloc(1, 128);
        assert!(!ptr.is_null());
        assert!(ptr as usize % 128 == 0);
        unsafe { aligned_free(ptr) }
    }

    #[test]
    fn small_high_align() {
        let ptr = aligned_alloc(1, 1024 * 1024);
        assert!(!ptr.is_null());
        assert!(ptr as usize % (1024 * 1024) == 0);
        unsafe { aligned_free(ptr) }
    }

    #[test]
    fn large_high_align() {
        // allocate 1 MiB aligned to 1 MiB
        let ptr = aligned_alloc(1024 * 1024, 1024 * 1024);
        assert!(!ptr.is_null());
        assert!(ptr as usize % (1024 * 1024) == 0);
        unsafe { aligned_free(ptr) }
    }

    #[test]
    #[should_panic]
    fn align_less_than_sizeof_usize() {
        // alignment of less than sizeof(usize)
        aligned_alloc(1, 3);
    }

    #[test]
    #[should_panic]
    fn align_not_power_of_two() {
        aligned_alloc(1, 27);
    }
}
<|endoftext|>


<commit_before>//! This crate provides x86_64 specific functions and data structures,
//! and access to various system registers.

#![cfg_attr(not(test), no_std)]
#![cfg_attr(feature = "const_fn", feature(const_fn))]
#![cfg_attr(feature = "const_fn", feature(const_mut_refs))]
#![cfg_attr(feature = "const_fn", feature(const_in_array_repeat_expressions))]
#![cfg_attr(feature = "inline_asm", feature(llvm_asm))]
#![cfg_attr(feature = "abi_x86_interrupt", feature(abi_x86_interrupt))]
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
#![cfg_attr(feature = "deny-warnings", deny(missing_docs))]
#![cfg_attr(not(feature = "deny-warnings"), warn(missing_docs))]
#![deny(missing_debug_implementations)]

pub use crate::addr::{align_down, align_up, PhysAddr, VirtAddr};

/// Makes a function const only when `feature = "const_fn"` is enabled.
///
/// This is needed for const functions with bounds on their generic parameters,
/// such as those in `Page` and `PhysFrame` and many more.
macro_rules! const_fn {
    (
        $(#[$attr:meta])*
        pub $($fn:tt)*
    ) => {
        $(#[$attr])*
        #[cfg(feature = "const_fn")]
        pub const $($fn)*

        $(#[$attr])*
        #[cfg(not(feature = "const_fn"))]
        pub $($fn)*
    }
}

#[cfg(all(feature = "instructions", feature = "external_asm"))]
pub(crate) mod asm;

pub mod addr;
pub mod instructions;
pub mod registers;
pub mod structures;

/// Represents a protection ring level.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(u8)]
pub enum PrivilegeLevel {
    /// Privilege-level 0 (most privilege): This level is used by critical system-software
    /// components that require direct access to, and control over, all processor and system
    /// resources. This can include BIOS, memory-management functions, and interrupt handlers.
    Ring0 = 0,

    /// Privilege-level 1 (moderate privilege): This level is used by less-critical system-
    /// software services that can access and control a limited scope of processor and system
    /// resources. Software running at these privilege levels might include some device drivers
    /// and library routines. The actual privileges of this level are defined by the
    /// operating system.
    Ring1 = 1,

    /// Privilege-level 2 (moderate privilege): Like level 1, this level is used by
    /// less-critical system-software services that can access and control a limited scope of
    /// processor and system resources. The actual privileges of this level are defined by the
    /// operating system.
    Ring2 = 2,

    /// Privilege-level 3 (least privilege): This level is used by application software.
    /// Software running at privilege-level 3 is normally prevented from directly accessing
    /// most processor and system resources. Instead, applications request access to the
    /// protected processor and system resources by calling more-privileged service routines
    /// to perform the accesses.
    Ring3 = 3,
}

impl PrivilegeLevel {
    /// Creates a `PrivilegeLevel` from a numeric value. The value must be in the range 0..4.
    ///
    /// This function panics if the passed value is >3.
    #[inline]
    pub fn from_u16(value: u16) -> PrivilegeLevel {
        match value {
            0 => PrivilegeLevel::Ring0,
            1 => PrivilegeLevel::Ring1,
            2 => PrivilegeLevel::Ring2,
            3 => PrivilegeLevel::Ring3,
            i => panic!("{} is not a valid privilege level", i),
        }
    }
}
<commit_msg>Fix build error on latest nightly<commit_after>//! This crate provides x86_64 specific functions and data structures,
//! and access to various system registers.

#![cfg_attr(not(test), no_std)]
#![cfg_attr(feature = "const_fn", feature(const_fn))]
#![cfg_attr(feature = "const_fn", feature(const_mut_refs))]
#![cfg_attr(feature = "const_fn", feature(const_fn_fn_ptr_basics))]
#![cfg_attr(feature = "const_fn", feature(const_in_array_repeat_expressions))]
#![cfg_attr(feature = "inline_asm", feature(llvm_asm))]
#![cfg_attr(feature = "abi_x86_interrupt", feature(abi_x86_interrupt))]
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
#![cfg_attr(feature = "deny-warnings", deny(missing_docs))]
#![cfg_attr(not(feature = "deny-warnings"), warn(missing_docs))]
#![deny(missing_debug_implementations)]

pub use crate::addr::{align_down, align_up, PhysAddr, VirtAddr};

/// Makes a function const only when `feature = "const_fn"` is enabled.
///
/// This is needed for const functions with bounds on their generic parameters,
/// such as those in `Page` and `PhysFrame` and many more.
macro_rules! const_fn {
    (
        $(#[$attr:meta])*
        pub $($fn:tt)*
    ) => {
        $(#[$attr])*
        #[cfg(feature = "const_fn")]
        pub const $($fn)*

        $(#[$attr])*
        #[cfg(not(feature = "const_fn"))]
        pub $($fn)*
    }
}

#[cfg(all(feature = "instructions", feature = "external_asm"))]
pub(crate) mod asm;

pub mod addr;
pub mod instructions;
pub mod registers;
pub mod structures;

/// Represents a protection ring level.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(u8)]
pub enum PrivilegeLevel {
    /// Privilege-level 0 (most privilege): This level is used by critical system-software
    /// components that require direct access to, and control over, all processor and system
    /// resources. This can include BIOS, memory-management functions, and interrupt handlers.
    Ring0 = 0,

    /// Privilege-level 1 (moderate privilege): This level is used by less-critical system-
    /// software services that can access and control a limited scope of processor and system
    /// resources. Software running at these privilege levels might include some device drivers
    /// and library routines. The actual privileges of this level are defined by the
    /// operating system.
    Ring1 = 1,

    /// Privilege-level 2 (moderate privilege): Like level 1, this level is used by
    /// less-critical system-software services that can access and control a limited scope of
    /// processor and system resources. The actual privileges of this level are defined by the
    /// operating system.
    Ring2 = 2,

    /// Privilege-level 3 (least privilege): This level is used by application software.
    /// Software running at privilege-level 3 is normally prevented from directly accessing
    /// most processor and system resources. Instead, applications request access to the
    /// protected processor and system resources by calling more-privileged service routines
    /// to perform the accesses.
    Ring3 = 3,
}

impl PrivilegeLevel {
    /// Creates a `PrivilegeLevel` from a numeric value. The value must be in the range 0..4.
    ///
    /// This function panics if the passed value is >3.
    #[inline]
    pub fn from_u16(value: u16) -> PrivilegeLevel {
        match value {
            0 => PrivilegeLevel::Ring0,
            1 => PrivilegeLevel::Ring1,
            2 => PrivilegeLevel::Ring2,
            3 => PrivilegeLevel::Ring3,
            i => panic!("{} is not a valid privilege level", i),
        }
    }
}
<|endoftext|>


<commit_before>#![deny(missing_docs)]
#![warn(dead_code)]

//! A user friendly game engine written in Rust.

#[cfg(feature = "include_gfx")]
extern crate libc;
#[cfg(feature = "include_gfx")]
extern crate gfx;
#[cfg(feature = "include_gfx")]
extern crate gfx_device_gl;
#[cfg(feature = "include_gfx")]
extern crate gfx_graphics;
#[cfg(feature = "include_opengl")]
extern crate opengl_graphics;
#[cfg(feature = "include_sdl2")]
extern crate sdl2;
#[cfg(feature = "include_sdl2")]
extern crate sdl2_window;
#[cfg(feature = "include_glfw")]
extern crate glfw;
#[cfg(feature = "include_glfw")]
extern crate glfw_window;
#[cfg(feature = "include_glutin")]
extern crate glutin;
#[cfg(feature = "include_glutin")]
extern crate glutin_window;
extern crate graphics;
extern crate fps_counter;
extern crate current;
extern crate shader_version;

extern crate piston;

#[cfg(feature = "include_sdl2")]
pub use sdl2_window::Sdl2Window as WindowBackEnd;
#[cfg(feature = "include_glfw")]
pub use glfw_window::GlfwWindow as WindowBackEnd;
#[cfg(feature = "include_glutin")]
pub use glutin_window::GlutinWindow as WindowBackEnd;

#[cfg(feature = "include_gfx")]
use gfx_graphics::Gfx2d;
#[cfg(feature = "include_gfx")]
use gfx_device_gl::{ Device, Resources };
#[cfg(feature = "include_gfx")]
use gfx_device_gl::CommandBuffer;

#[cfg(feature = "include_opengl")]
use opengl_graphics::GlGraphics;
use fps_counter::FPSCounter;

use std::rc::Rc;
use std::cell::RefCell;

use piston::window::WindowSettings;
use current::{ Current, CurrentGuard };

fn start_window<F>(
    opengl: shader_version::OpenGL,
    window_settings: WindowSettings,
    mut f: F
)
    where
        F: FnMut()
{
    let mut window = Rc::new(RefCell::new(WindowBackEnd::new(
        opengl,
        window_settings,
    )));
    let mut fps_counter = Rc::new(RefCell::new(FPSCounter::new()));

    #[cfg(feature = "include_sdl2")]
    fn disable_vsync() { sdl2::video::gl_set_swap_interval(0); }

    #[cfg(not(feature = "include_sdl2"))]
    fn disable_vsync() {}

    disable_vsync();

    let window_guard = CurrentGuard::new(&mut window);
    let fps_counter_guard = CurrentGuard::new(&mut fps_counter);

    f();

    drop(window_guard);
    drop(fps_counter_guard);
}

#[cfg(feature = "include_opengl")]
fn start_opengl<F>(opengl: shader_version::OpenGL, mut f: F)
    where
        F: FnMut()
{
    let mut gl = Rc::new(RefCell::new(GlGraphics::new(opengl)));

    let gl_guard = CurrentGuard::new(&mut gl);

    f();

    drop(gl_guard);
}

#[cfg(not(feature = "include_opengl"))]
fn start_opengl<F>(_opengl: shader_version::OpenGL, mut f: F)
    where
        F: FnMut()
{
    f();
}

#[cfg(feature = "include_gfx")]
fn start_gfx<F>(mut f: F)
    where
        F: FnMut()
{
    use piston::window::Window;
    use gfx::render::ext::factory::RenderFactory;

    let window = current_window();

    let (device, mut factory) = gfx_device_gl::create(|s| {
        #[cfg(feature = "include_sdl2")]
        fn get_proc_address(_: &WindowBackEnd, s: &str) ->
            *const libc::types::common::c95::c_void {
            unsafe { std::mem::transmute(sdl2::video::gl_get_proc_address(s)) }
        }

        #[cfg(feature = "include_glfw")]
        fn get_proc_address(window: &mut WindowBackEnd, s: &str) ->
            *const libc::types::common::c95::c_void {
            window.window.get_proc_address(s)
        }

        #[cfg(feature = "include_glutin")]
        fn get_proc_address(window: &WindowBackEnd, s: &str) ->
            *const libc::types::common::c95::c_void {
            window.window.get_proc_address(s)
        }

        get_proc_address(&mut *window.borrow_mut(), s)
    });
    let mut renderer: Rc<RefCell<
        gfx::Renderer<gfx_device_gl::Resources,
        <gfx_device_gl::Device as gfx::Device>::CommandBuffer
    >>> =
        Rc::new(RefCell::new(factory.create_renderer()));
    let mut device = Rc::new(RefCell::new(device));
    let factory = Rc::new(RefCell::new(factory));
    let mut g2d = Rc::new(RefCell::new(Gfx2d::new(&mut *device.borrow_mut(), &mut *factory.borrow_mut())));
    let size = window.borrow().size();
    let mut frame = Rc::new(RefCell::new(gfx::Frame::<Resources>::new(
        size.width as u16, size.height as u16)));

    let device_guard = CurrentGuard::new(&mut device);
    let g2d_guard = CurrentGuard::new(&mut g2d);
    let renderer_guard = CurrentGuard::new(&mut renderer);
    let frame_guard = CurrentGuard::new(&mut frame);

    f();

    drop(g2d_guard);
    drop(renderer_guard);
    drop(frame_guard);
    drop(device_guard);
}

#[cfg(not(feature = "include_gfx"))]
fn start_gfx<F>(mut f: F)
    where
        F: FnMut()
{
    f();
}

/// Initializes window and sets up current objects.
pub fn start<F>(
    opengl: shader_version::OpenGL,
    window_settings: WindowSettings,
    mut f: F
)
    where
        F: FnMut()
{
    start_window(opengl, window_settings, || {
        start_opengl(opengl, || {
            if cfg!(feature = "include_gfx") {
                start_gfx(|| f());
            } else {
                f();
            }
        })
    });
}

/// The current window
pub fn current_window() -> Rc<RefCell<WindowBackEnd>> {
    unsafe {
        Current::<Rc<RefCell<WindowBackEnd>>>::new().clone()
    }
}
/// The current Gfx device
#[cfg(feature = "include_gfx")]
pub fn current_gfx_device() -> Rc<RefCell<Device>> {
    unsafe {
        Current::<Rc<RefCell<Device>>>::new().clone()
    }
}
/// The current opengl_graphics back-end
#[cfg(feature = "include_opengl")]
pub fn current_gl() -> Rc<RefCell<GlGraphics>> {
    unsafe {
        Current::<Rc<RefCell<GlGraphics>>>::new().clone()
    }
}
/// The current gfx_graphics back-end
#[cfg(feature = "include_gfx")]
pub fn current_g2d() -> Rc<RefCell<Gfx2d<Resources>>> {
    unsafe {
        Current::<Rc<RefCell<Gfx2d<Resources>>>>::new().clone()
    }
}
/// The current Gfx renderer
#[cfg(feature = "include_gfx")]
pub fn current_renderer() -> Rc<RefCell<gfx::Renderer<Resources, CommandBuffer>>> {
    unsafe {
        Current::<Rc<RefCell<gfx::Renderer<Resources, CommandBuffer>>>>::new().clone()
    }
}
/// The current Gfx frame
#[cfg(feature = "include_gfx")]
pub fn current_frame() -> Rc<RefCell<gfx::Frame<Resources>>> {
    unsafe {
        Current::<Rc<RefCell<gfx::Frame<Resources>>>>::new().clone()
    }
}
/// The current FPS counter
pub fn current_fps_counter() -> Rc<RefCell<FPSCounter>> {
    unsafe {
        Current::<Rc<RefCell<FPSCounter>>>::new().clone()
    }
}

/// Returns an event iterator for the event loop
pub fn events() -> piston::event::events::Events<WindowBackEnd, piston::event::Event> {
    use piston::event::Events;

    current_window().events()
}

/// Updates the FPS counter and gets the frames per second.
pub fn fps_tick() -> usize {
    let fps_counter = current_fps_counter();
    let mut fps_counter = fps_counter.borrow_mut();
    fps_counter.tick()
}

/// Sets title of the current window.
pub fn set_title(text: String) {
    use piston::window::AdvancedWindow;

    let window = current_window();
    let mut window = window.borrow_mut();
    window.set_title(text);
}

/// Returns true if the current window should be closed.
pub fn should_close() -> bool {
    use piston::window::Window;

    let window = current_window();
    let window = window.borrow();
    window.should_close()
}

/// Renders 2D graphics using Gfx.
#[cfg(feature = "include_gfx")]
pub fn render_2d_gfx<F>(
    bg_color: Option<[f32; 4]>,
    mut f: F
)
    where
        F: FnMut(graphics::Context,
            &mut gfx_graphics::GfxGraphics<Resources, CommandBuffer>)
{
    use gfx::Device;

    let renderer = current_renderer();
    let mut renderer = renderer.borrow_mut();
    let renderer = &mut *renderer;
    let gfx = current_g2d();
    let mut gfx = gfx.borrow_mut();
    let frame = current_frame();
    let frame = frame.borrow();
    gfx.draw(
        renderer,
        &*frame,
        |c, g| {
            if let Some(bg_color) = bg_color {
                graphics::clear(bg_color, g);
            }
            f(c, g);
        });
    let gfx_device = current_gfx_device();
    let mut gfx_device = gfx_device.borrow_mut();
    gfx_device.submit(renderer.as_buffer());
    renderer.reset();
}

/// Renders 2D graphics using OpenGL.
///
/// Panics if called nested within the closure
/// to prevent mutable aliases to the graphics back-end.
#[cfg(feature = "include_opengl")]
pub fn render_2d_opengl<F>(
    bg_color: Option<[f32; 4]>,
    mut f: F
)
    where
        F: FnMut(graphics::Context, &mut opengl_graphics::Gl)
{
    use piston::window::Window;
    use graphics::Viewport;

    let window = current_window();
    let window = window.borrow();
    let size = window.size();
    let draw_size = window.draw_size();
    let gl = current_gl();
    let mut gl = gl.borrow_mut();
    gl.draw(Viewport {
        rect: [0, 0, draw_size.width as i32, draw_size.height as i32],
        draw_size: [draw_size.width, draw_size.height],
        window_size: [size.width, size.height]
    }, |c, g| {
        use graphics::*;
        if let Some(bg_color) = bg_color {
            graphics::clear(bg_color, g);
        }
        f(c, g);
    });
}

<commit_msg>Computing `Viewport` for Gfx<commit_after>#![deny(missing_docs)]
#![warn(dead_code)]

//! A user friendly game engine written in Rust.

#[cfg(feature = "include_gfx")]
extern crate libc;
#[cfg(feature = "include_gfx")]
extern crate gfx;
#[cfg(feature = "include_gfx")]
extern crate gfx_device_gl;
#[cfg(feature = "include_gfx")]
extern crate gfx_graphics;
#[cfg(feature = "include_opengl")]
extern crate opengl_graphics;
#[cfg(feature = "include_sdl2")]
extern crate sdl2;
#[cfg(feature = "include_sdl2")]
extern crate sdl2_window;
#[cfg(feature = "include_glfw")]
extern crate glfw;
#[cfg(feature = "include_glfw")]
extern crate glfw_window;
#[cfg(feature = "include_glutin")]
extern crate glutin;
#[cfg(feature = "include_glutin")]
extern crate glutin_window;
extern crate graphics;
extern crate fps_counter;
extern crate current;
extern crate shader_version;

extern crate piston;

#[cfg(feature = "include_sdl2")]
pub use sdl2_window::Sdl2Window as WindowBackEnd;
#[cfg(feature = "include_glfw")]
pub use glfw_window::GlfwWindow as WindowBackEnd;
#[cfg(feature = "include_glutin")]
pub use glutin_window::GlutinWindow as WindowBackEnd;

#[cfg(feature = "include_gfx")]
use gfx_graphics::Gfx2d;
#[cfg(feature = "include_gfx")]
use gfx_device_gl::{ Device, Resources };
#[cfg(feature = "include_gfx")]
use gfx_device_gl::CommandBuffer;

#[cfg(feature = "include_opengl")]
use opengl_graphics::GlGraphics;
use fps_counter::FPSCounter;

use std::rc::Rc;
use std::cell::RefCell;

use piston::window::WindowSettings;
use current::{ Current, CurrentGuard };

fn start_window<F>(
    opengl: shader_version::OpenGL,
    window_settings: WindowSettings,
    mut f: F
)
    where
        F: FnMut()
{
    let mut window = Rc::new(RefCell::new(WindowBackEnd::new(
        opengl,
        window_settings,
    )));
    let mut fps_counter = Rc::new(RefCell::new(FPSCounter::new()));

    #[cfg(feature = "include_sdl2")]
    fn disable_vsync() { sdl2::video::gl_set_swap_interval(0); }

    #[cfg(not(feature = "include_sdl2"))]
    fn disable_vsync() {}

    disable_vsync();

    let window_guard = CurrentGuard::new(&mut window);
    let fps_counter_guard = CurrentGuard::new(&mut fps_counter);

    f();

    drop(window_guard);
    drop(fps_counter_guard);
}

#[cfg(feature = "include_opengl")]
fn start_opengl<F>(opengl: shader_version::OpenGL, mut f: F)
    where
        F: FnMut()
{
    let mut gl = Rc::new(RefCell::new(GlGraphics::new(opengl)));

    let gl_guard = CurrentGuard::new(&mut gl);

    f();

    drop(gl_guard);
}

#[cfg(not(feature = "include_opengl"))]
fn start_opengl<F>(_opengl: shader_version::OpenGL, mut f: F)
    where
        F: FnMut()
{
    f();
}

#[cfg(feature = "include_gfx")]
fn start_gfx<F>(mut f: F)
    where
        F: FnMut()
{
    use piston::window::Window;
    use gfx::render::ext::factory::RenderFactory;

    let window = current_window();

    let (device, mut factory) = gfx_device_gl::create(|s| {
        #[cfg(feature = "include_sdl2")]
        fn get_proc_address(_: &WindowBackEnd, s: &str) ->
            *const libc::types::common::c95::c_void {
            unsafe { std::mem::transmute(sdl2::video::gl_get_proc_address(s)) }
        }

        #[cfg(feature = "include_glfw")]
        fn get_proc_address(window: &mut WindowBackEnd, s: &str) ->
            *const libc::types::common::c95::c_void {
            window.window.get_proc_address(s)
        }

        #[cfg(feature = "include_glutin")]
        fn get_proc_address(window: &WindowBackEnd, s: &str) ->
            *const libc::types::common::c95::c_void {
            window.window.get_proc_address(s)
        }

        get_proc_address(&mut *window.borrow_mut(), s)
    });
    let mut renderer: Rc<RefCell<
        gfx::Renderer<gfx_device_gl::Resources,
        <gfx_device_gl::Device as gfx::Device>::CommandBuffer
    >>> =
        Rc::new(RefCell::new(factory.create_renderer()));
    let mut device = Rc::new(RefCell::new(device));
    let factory = Rc::new(RefCell::new(factory));
    let mut g2d = Rc::new(RefCell::new(Gfx2d::new(&mut *device.borrow_mut(), &mut *factory.borrow_mut())));
    let size = window.borrow().size();
    let mut frame = Rc::new(RefCell::new(gfx::Frame::<Resources>::new(
        size.width as u16, size.height as u16)));

    let device_guard = CurrentGuard::new(&mut device);
    let g2d_guard = CurrentGuard::new(&mut g2d);
    let renderer_guard = CurrentGuard::new(&mut renderer);
    let frame_guard = CurrentGuard::new(&mut frame);

    f();

    drop(g2d_guard);
    drop(renderer_guard);
    drop(frame_guard);
    drop(device_guard);
}

#[cfg(not(feature = "include_gfx"))]
fn start_gfx<F>(mut f: F)
    where
        F: FnMut()
{
    f();
}

/// Initializes window and sets up current objects.
pub fn start<F>(
    opengl: shader_version::OpenGL,
    window_settings: WindowSettings,
    mut f: F
)
    where
        F: FnMut()
{
    start_window(opengl, window_settings, || {
        start_opengl(opengl, || {
            if cfg!(feature = "include_gfx") {
                start_gfx(|| f());
            } else {
                f();
            }
        })
    });
}

/// The current window
pub fn current_window() -> Rc<RefCell<WindowBackEnd>> {
    unsafe {
        Current::<Rc<RefCell<WindowBackEnd>>>::new().clone()
    }
}
/// The current Gfx device
#[cfg(feature = "include_gfx")]
pub fn current_gfx_device() -> Rc<RefCell<Device>> {
    unsafe {
        Current::<Rc<RefCell<Device>>>::new().clone()
    }
}
/// The current opengl_graphics back-end
#[cfg(feature = "include_opengl")]
pub fn current_gl() -> Rc<RefCell<GlGraphics>> {
    unsafe {
        Current::<Rc<RefCell<GlGraphics>>>::new().clone()
    }
}
/// The current gfx_graphics back-end
#[cfg(feature = "include_gfx")]
pub fn current_g2d() -> Rc<RefCell<Gfx2d<Resources>>> {
    unsafe {
        Current::<Rc<RefCell<Gfx2d<Resources>>>>::new().clone()
    }
}
/// The current Gfx renderer
#[cfg(feature = "include_gfx")]
pub fn current_renderer() -> Rc<RefCell<gfx::Renderer<Resources, CommandBuffer>>> {
    unsafe {
        Current::<Rc<RefCell<gfx::Renderer<Resources, CommandBuffer>>>>::new().clone()
    }
}
/// The current Gfx frame
#[cfg(feature = "include_gfx")]
pub fn current_frame() -> Rc<RefCell<gfx::Frame<Resources>>> {
    unsafe {
        Current::<Rc<RefCell<gfx::Frame<Resources>>>>::new().clone()
    }
}
/// The current FPS counter
pub fn current_fps_counter() -> Rc<RefCell<FPSCounter>> {
    unsafe {
        Current::<Rc<RefCell<FPSCounter>>>::new().clone()
    }
}

/// Returns an event iterator for the event loop
pub fn events() -> piston::event::events::Events<WindowBackEnd, piston::event::Event> {
    use piston::event::Events;

    current_window().events()
}

/// Updates the FPS counter and gets the frames per second.
pub fn fps_tick() -> usize {
    let fps_counter = current_fps_counter();
    let mut fps_counter = fps_counter.borrow_mut();
    fps_counter.tick()
}

/// Sets title of the current window.
pub fn set_title(text: String) {
    use piston::window::AdvancedWindow;

    let window = current_window();
    let mut window = window.borrow_mut();
    window.set_title(text);
}

/// Returns true if the current window should be closed.
pub fn should_close() -> bool {
    use piston::window::Window;

    let window = current_window();
    let window = window.borrow();
    window.should_close()
}

/// Renders 2D graphics using Gfx.
#[cfg(feature = "include_gfx")]
pub fn render_2d_gfx<F>(
    bg_color: Option<[f32; 4]>,
    mut f: F
)
    where
        F: FnMut(graphics::Context,
            &mut gfx_graphics::GfxGraphics<Resources, CommandBuffer>)
{
    use gfx::Device;
    use piston::window::Window;
    use graphics::Viewport;

    let window = current_window();
    let window = window.borrow();
    let size = window.size();
    let draw_size = window.draw_size();
    let renderer = current_renderer();
    let mut renderer = renderer.borrow_mut();
    let renderer = &mut *renderer;
    let gfx = current_g2d();
    let mut gfx = gfx.borrow_mut();
    let frame = current_frame();
    let frame = frame.borrow();
    gfx.draw(
        renderer,
        &*frame,
        Viewport {
            rect: [0, 0, draw_size.width as i32, draw_size.height as i32],
            draw_size: [draw_size.width, draw_size.height],
            window_size: [size.width, size.height],
        },
        |c, g| {
            if let Some(bg_color) = bg_color {
                graphics::clear(bg_color, g);
            }
            f(c, g);
        });
    let gfx_device = current_gfx_device();
    let mut gfx_device = gfx_device.borrow_mut();
    gfx_device.submit(renderer.as_buffer());
    renderer.reset();
}

/// Renders 2D graphics using OpenGL.
///
/// Panics if called nested within the closure
/// to prevent mutable aliases to the graphics back-end.
#[cfg(feature = "include_opengl")]
pub fn render_2d_opengl<F>(
    bg_color: Option<[f32; 4]>,
    mut f: F
)
    where
        F: FnMut(graphics::Context, &mut opengl_graphics::Gl)
{
    use piston::window::Window;
    use graphics::Viewport;

    let window = current_window();
    let window = window.borrow();
    let size = window.size();
    let draw_size = window.draw_size();
    let gl = current_gl();
    let mut gl = gl.borrow_mut();
    gl.draw(Viewport {
        rect: [0, 0, draw_size.width as i32, draw_size.height as i32],
        draw_size: [draw_size.width, draw_size.height],
        window_size: [size.width, size.height]
    }, |c, g| {
        use graphics::*;
        if let Some(bg_color) = bg_color {
            graphics::clear(bg_color, g);
        }
        f(c, g);
    });
}

<|endoftext|>


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

//! A library for passing arbitrary file descriptors when spawning child processes.
//!
//! # Example
//!
//! ```rust
//! use command_fds::{CommandFdExt, FdMapping};
//! use std::fs::File;
//! use std::os::unix::io::AsRawFd;
//! use std::process::Command;
//!
//! // Open a file.
//! let file = File::open("Cargo.toml").unwrap();
//!
//! // Prepare to run `ls -l /proc/self/fd` with some FDs mapped.
//! let mut command = Command::new("ls");
//! command.arg("-l").arg("/proc/self/fd");
//! command
//!     .fd_mappings(vec![
//!         // Map `file` as FD 3 in the child process.
//!         FdMapping {
//!             parent_fd: file.as_raw_fd(),
//!             child_fd: 3,
//!         },
//!         // Map this process's stdin as FD 5 in the child process.
//!         FdMapping {
//!             parent_fd: 0,
//!             child_fd: 5,
//!         },
//!     ])
//!     .unwrap();
//!
//! // Spawn the child process.
//! let mut child = command.spawn().unwrap();
//! child.wait().unwrap();
//! ```

use nix::fcntl::{fcntl, FcntlArg, FdFlag};
use nix::unistd::dup2;
use std::cmp::max;
use std::io::{self, ErrorKind};
use std::os::unix::io::RawFd;
use std::os::unix::process::CommandExt;
use std::process::Command;
use thiserror::Error;

/// A mapping from a file descriptor in the parent to a file descriptor in the child, to be applied
/// when spawning a child process.
///
/// The parent_fd must be kept open until after the child is spawned.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct FdMapping {
    pub parent_fd: RawFd,
    pub child_fd: RawFd,
}

/// Error setting up FD mappings, because there were two or more mappings for the same child FD.
#[derive(Copy, Clone, Debug, Eq, Error, PartialEq)]
#[error("Two or more mappings for the same child FD")]
pub struct FdMappingCollision;

/// Extension to add file descriptor mappings to a [`Command`].
pub trait CommandFdExt {
    /// Adds the given set of file descriptor to the command.
    ///
    /// Calling this more than once on the same command may result in unexpected behaviour.
    fn fd_mappings(&mut self, mappings: Vec<FdMapping>) -> Result<(), FdMappingCollision>;
}

impl CommandFdExt for Command {
    fn fd_mappings(&mut self, mappings: Vec<FdMapping>) -> Result<(), FdMappingCollision> {
        // Validate that there are no conflicting mappings to the same child FD.
        let mut child_fds: Vec<RawFd> = mappings.iter().map(|mapping| mapping.child_fd).collect();
        child_fds.sort_unstable();
        child_fds.dedup();
        if child_fds.len() != mappings.len() {
            return Err(FdMappingCollision);
        }

        // Register the callback to apply the mappings after forking but before execing.
        unsafe {
            self.pre_exec(move || map_fds(&mappings));
        }

        Ok(())
    }
}

fn map_fds(mappings: &[FdMapping]) -> io::Result<()> {
    if mappings.is_empty() {
        // No need to do anything, and finding first_unused_fd would fail.
        return Ok(());
    }

    // Find the first FD which is higher than any parent or child FD in the mapping, so we can
    // safely use it and higher FDs as temporary FDs. There may be other files open with these FDs,
    // so we still need to ensure we don't conflict with them.
    let first_safe_fd = mappings
        .iter()
        .map(|mapping| max(mapping.parent_fd, mapping.child_fd))
        .max()
        .unwrap()
        + 1;

    // If any parent FDs conflict with child FDs, then first duplicate them to a temporary FD which
    // is clear of either range. Mappings to the same FD are fine though, we can handle them by just
    // removing the FD_CLOEXEC flag.
    let child_fds: Vec<RawFd> = mappings.iter().map(|mapping| mapping.child_fd).collect();
    let mappings = mappings
        .iter()
        .map(|mapping| {
            Ok(
                if child_fds.contains(&mapping.parent_fd) && mapping.parent_fd != mapping.child_fd {
                    let temporary_fd =
                        fcntl(mapping.parent_fd, FcntlArg::F_DUPFD_CLOEXEC(first_safe_fd))?;
                    FdMapping {
                        parent_fd: temporary_fd,
                        child_fd: mapping.child_fd,
                    }
                } else {
                    mapping.to_owned()
                },
            )
        })
        .collect::<nix::Result<Vec<_>>>()
        .map_err(nix_to_io_error)?;

    // Now we can actually duplicate FDs to the desired child FDs.
    for mapping in mappings {
        if mapping.child_fd == mapping.parent_fd {
            // Remove the FD_CLOEXEC flag, so the FD will be kept open when exec is called for the
            // child.
            fcntl(mapping.parent_fd, FcntlArg::F_SETFD(FdFlag::empty()))
                .map_err(nix_to_io_error)?;
        } else {
            // This closes child_fd if it is already open as something else, and clears the
            // FD_CLOEXEC flag on child_fd.
            dup2(mapping.parent_fd, mapping.child_fd).map_err(nix_to_io_error)?;
        }
    }

    Ok(())
}

/// Convert a [`nix::Error`] to a [`std::io::Error`].
fn nix_to_io_error(error: nix::Error) -> io::Error {
    if let nix::Error::Sys(errno) = error {
        io::Error::from_raw_os_error(errno as i32)
    } else {
        io::Error::new(ErrorKind::Other, error)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use nix::unistd::close;
    use std::collections::HashSet;
    use std::fs::{read_dir, File};
    use std::os::unix::io::AsRawFd;
    use std::process::Output;
    use std::str;
    use std::sync::Once;

    static SETUP: Once = Once::new();

    #[test]
    fn conflicting_mappings() {
        setup();

        let mut command = Command::new("ls");

        // The same mapping can't be included twice.
        assert_eq!(
            command.fd_mappings(vec![
                FdMapping {
                    child_fd: 4,
                    parent_fd: 5,
                },
                FdMapping {
                    child_fd: 4,
                    parent_fd: 5,
                },
            ]),
            Err(FdMappingCollision)
        );

        // Mapping two different FDs to the same FD isn't allowed either.
        assert_eq!(
            command.fd_mappings(vec![
                FdMapping {
                    child_fd: 4,
                    parent_fd: 5,
                },
                FdMapping {
                    child_fd: 4,
                    parent_fd: 6,
                },
            ]),
            Err(FdMappingCollision)
        );
    }

    #[test]
    fn no_mappings() {
        setup();

        let mut command = Command::new("ls");
        command.arg("/proc/self/fd");

        assert_eq!(command.fd_mappings(vec![]), Ok(()));

        let output = command.output().unwrap();
        expect_fds(&output, &[0, 1, 2, 3], 0);
    }

    #[test]
    fn one_mapping() {
        setup();

        let mut command = Command::new("ls");
        command.arg("/proc/self/fd");

        let file = File::open("testdata/file1.txt").unwrap();
        // Map the file an otherwise unused FD.
        assert_eq!(
            command.fd_mappings(vec![FdMapping {
                parent_fd: file.as_raw_fd(),
                child_fd: 5,
            },]),
            Ok(())
        );

        let output = command.output().unwrap();
        expect_fds(&output, &[0, 1, 2, 3, 5], 0);
    }

    #[test]
    fn swap_mappings() {
        setup();

        let mut command = Command::new("ls");
        command.arg("/proc/self/fd");

        let file1 = File::open("testdata/file1.txt").unwrap();
        let file2 = File::open("testdata/file2.txt").unwrap();
        let fd1 = file1.as_raw_fd();
        let fd2 = file2.as_raw_fd();
        // Map files to each other's FDs, to ensure that the temporary FD logic works.
        assert_eq!(
            command.fd_mappings(vec![
                FdMapping {
                    parent_fd: fd1,
                    child_fd: fd2,
                },
                FdMapping {
                    parent_fd: fd2,
                    child_fd: fd1,
                },
            ]),
            Ok(())
        );

        let output = command.output().unwrap();
        // Expect one more Fd for the /proc/self/fd directory. We can't predict what number it will
        // be assigned, because 3 might or might not be taken already by fd1 or fd2.
        expect_fds(&output, &[0, 1, 2, fd1, fd2], 1);
    }

    #[test]
    fn one_to_one_mapping() {
        setup();

        let mut command = Command::new("ls");
        command.arg("/proc/self/fd");

        let file1 = File::open("testdata/file1.txt").unwrap();
        let file2 = File::open("testdata/file2.txt").unwrap();
        let fd1 = file1.as_raw_fd();
        // Map files to each other's FDs, to ensure that the temporary FD logic works.
        assert_eq!(
            command.fd_mappings(vec![FdMapping {
                parent_fd: fd1,
                child_fd: fd1,
            }]),
            Ok(())
        );

        let output = command.output().unwrap();
        // Expect one more Fd for the /proc/self/fd directory. We can't predict what number it will
        // be assigned, because 3 might or might not be taken already by fd1 or fd2.
        expect_fds(&output, &[0, 1, 2, fd1], 1);

        // Keep file2 open until the end, to ensure that it's not passed to the child.
        drop(file2);
    }

    #[test]
    fn map_stdin() {
        setup();

        let mut command = Command::new("cat");

        let file = File::open("testdata/file1.txt").unwrap();
        // Map the file to stdin.
        assert_eq!(
            command.fd_mappings(vec![FdMapping {
                parent_fd: file.as_raw_fd(),
                child_fd: 0,
            },]),
            Ok(())
        );

        let output = command.output().unwrap();
        assert!(output.status.success());
        assert_eq!(output.stdout, b"test 1");
    }

    /// Parse the output of ls into a set of filenames
    fn parse_ls_output(output: &[u8]) -> HashSet<String> {
        str::from_utf8(output)
            .unwrap()
            .split_terminator("\n")
            .map(str::to_owned)
            .collect()
    }

    /// Check that the output of `ls /proc/self/fd` contains the expected set of FDs, plus exactly
    /// `extra` extra FDs.
    fn expect_fds(output: &Output, expected_fds: &[RawFd], extra: usize) {
        assert!(output.status.success());
        let expected_fds: HashSet<String> = expected_fds.iter().map(RawFd::to_string).collect();
        let fds = parse_ls_output(&output.stdout);
        if extra == 0 {
            assert_eq!(fds, expected_fds);
        } else {
            assert!(expected_fds.is_subset(&fds));
            assert_eq!(fds.len(), expected_fds.len() + extra);
        }
    }

    fn setup() {
        SETUP.call_once(close_excess_fds);
    }

    /// Close all file descriptors apart from stdin, stdout and stderr.
    ///
    /// This is necessary because GitHub Actions opens a bunch of others for some reason.
    fn close_excess_fds() {
        let dir = read_dir("/proc/self/fd").unwrap();
        for entry in dir {
            let entry = entry.unwrap();
            let fd: RawFd = entry.file_name().to_str().unwrap().parse().unwrap();
            if fd > 3 {
                close(fd).unwrap();
            }
        }
    }
}
<commit_msg>Return &mut self from fd_mappings.<commit_after>// Copyright 2021, The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! A library for passing arbitrary file descriptors when spawning child processes.
//!
//! # Example
//!
//! ```rust
//! use command_fds::{CommandFdExt, FdMapping};
//! use std::fs::File;
//! use std::os::unix::io::AsRawFd;
//! use std::process::Command;
//!
//! // Open a file.
//! let file = File::open("Cargo.toml").unwrap();
//!
//! // Prepare to run `ls -l /proc/self/fd` with some FDs mapped.
//! let mut command = Command::new("ls");
//! command.arg("-l").arg("/proc/self/fd");
//! command
//!     .fd_mappings(vec![
//!         // Map `file` as FD 3 in the child process.
//!         FdMapping {
//!             parent_fd: file.as_raw_fd(),
//!             child_fd: 3,
//!         },
//!         // Map this process's stdin as FD 5 in the child process.
//!         FdMapping {
//!             parent_fd: 0,
//!             child_fd: 5,
//!         },
//!     ])
//!     .unwrap();
//!
//! // Spawn the child process.
//! let mut child = command.spawn().unwrap();
//! child.wait().unwrap();
//! ```

use nix::fcntl::{fcntl, FcntlArg, FdFlag};
use nix::unistd::dup2;
use std::cmp::max;
use std::io::{self, ErrorKind};
use std::os::unix::io::RawFd;
use std::os::unix::process::CommandExt;
use std::process::Command;
use thiserror::Error;

/// A mapping from a file descriptor in the parent to a file descriptor in the child, to be applied
/// when spawning a child process.
///
/// The parent_fd must be kept open until after the child is spawned.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct FdMapping {
    pub parent_fd: RawFd,
    pub child_fd: RawFd,
}

/// Error setting up FD mappings, because there were two or more mappings for the same child FD.
#[derive(Copy, Clone, Debug, Eq, Error, PartialEq)]
#[error("Two or more mappings for the same child FD")]
pub struct FdMappingCollision;

/// Extension to add file descriptor mappings to a [`Command`].
pub trait CommandFdExt {
    /// Adds the given set of file descriptor to the command.
    ///
    /// Calling this more than once on the same command may result in unexpected behaviour.
    fn fd_mappings(&mut self, mappings: Vec<FdMapping>) -> Result<&mut Self, FdMappingCollision>;
}

impl CommandFdExt for Command {
    fn fd_mappings(&mut self, mappings: Vec<FdMapping>) -> Result<&mut Self, FdMappingCollision> {
        // Validate that there are no conflicting mappings to the same child FD.
        let mut child_fds: Vec<RawFd> = mappings.iter().map(|mapping| mapping.child_fd).collect();
        child_fds.sort_unstable();
        child_fds.dedup();
        if child_fds.len() != mappings.len() {
            return Err(FdMappingCollision);
        }

        // Register the callback to apply the mappings after forking but before execing.
        unsafe {
            self.pre_exec(move || map_fds(&mappings));
        }

        Ok(self)
    }
}

fn map_fds(mappings: &[FdMapping]) -> io::Result<()> {
    if mappings.is_empty() {
        // No need to do anything, and finding first_unused_fd would fail.
        return Ok(());
    }

    // Find the first FD which is higher than any parent or child FD in the mapping, so we can
    // safely use it and higher FDs as temporary FDs. There may be other files open with these FDs,
    // so we still need to ensure we don't conflict with them.
    let first_safe_fd = mappings
        .iter()
        .map(|mapping| max(mapping.parent_fd, mapping.child_fd))
        .max()
        .unwrap()
        + 1;

    // If any parent FDs conflict with child FDs, then first duplicate them to a temporary FD which
    // is clear of either range. Mappings to the same FD are fine though, we can handle them by just
    // removing the FD_CLOEXEC flag.
    let child_fds: Vec<RawFd> = mappings.iter().map(|mapping| mapping.child_fd).collect();
    let mappings = mappings
        .iter()
        .map(|mapping| {
            Ok(
                if child_fds.contains(&mapping.parent_fd) && mapping.parent_fd != mapping.child_fd {
                    let temporary_fd =
                        fcntl(mapping.parent_fd, FcntlArg::F_DUPFD_CLOEXEC(first_safe_fd))?;
                    FdMapping {
                        parent_fd: temporary_fd,
                        child_fd: mapping.child_fd,
                    }
                } else {
                    mapping.to_owned()
                },
            )
        })
        .collect::<nix::Result<Vec<_>>>()
        .map_err(nix_to_io_error)?;

    // Now we can actually duplicate FDs to the desired child FDs.
    for mapping in mappings {
        if mapping.child_fd == mapping.parent_fd {
            // Remove the FD_CLOEXEC flag, so the FD will be kept open when exec is called for the
            // child.
            fcntl(mapping.parent_fd, FcntlArg::F_SETFD(FdFlag::empty()))
                .map_err(nix_to_io_error)?;
        } else {
            // This closes child_fd if it is already open as something else, and clears the
            // FD_CLOEXEC flag on child_fd.
            dup2(mapping.parent_fd, mapping.child_fd).map_err(nix_to_io_error)?;
        }
    }

    Ok(())
}

/// Convert a [`nix::Error`] to a [`std::io::Error`].
fn nix_to_io_error(error: nix::Error) -> io::Error {
    if let nix::Error::Sys(errno) = error {
        io::Error::from_raw_os_error(errno as i32)
    } else {
        io::Error::new(ErrorKind::Other, error)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use nix::unistd::close;
    use std::collections::HashSet;
    use std::fs::{read_dir, File};
    use std::os::unix::io::AsRawFd;
    use std::process::Output;
    use std::str;
    use std::sync::Once;

    static SETUP: Once = Once::new();

    #[test]
    fn conflicting_mappings() {
        setup();

        let mut command = Command::new("ls");

        // The same mapping can't be included twice.
        assert!(command
            .fd_mappings(vec![
                FdMapping {
                    child_fd: 4,
                    parent_fd: 5,
                },
                FdMapping {
                    child_fd: 4,
                    parent_fd: 5,
                },
            ])
            .is_err());

        // Mapping two different FDs to the same FD isn't allowed either.
        assert!(command
            .fd_mappings(vec![
                FdMapping {
                    child_fd: 4,
                    parent_fd: 5,
                },
                FdMapping {
                    child_fd: 4,
                    parent_fd: 6,
                },
            ])
            .is_err());
    }

    #[test]
    fn no_mappings() {
        setup();

        let mut command = Command::new("ls");
        command.arg("/proc/self/fd");

        assert!(command.fd_mappings(vec![]).is_ok());

        let output = command.output().unwrap();
        expect_fds(&output, &[0, 1, 2, 3], 0);
    }

    #[test]
    fn one_mapping() {
        setup();

        let mut command = Command::new("ls");
        command.arg("/proc/self/fd");

        let file = File::open("testdata/file1.txt").unwrap();
        // Map the file an otherwise unused FD.
        assert!(command
            .fd_mappings(vec![FdMapping {
                parent_fd: file.as_raw_fd(),
                child_fd: 5,
            },])
            .is_ok());

        let output = command.output().unwrap();
        expect_fds(&output, &[0, 1, 2, 3, 5], 0);
    }

    #[test]
    fn swap_mappings() {
        setup();

        let mut command = Command::new("ls");
        command.arg("/proc/self/fd");

        let file1 = File::open("testdata/file1.txt").unwrap();
        let file2 = File::open("testdata/file2.txt").unwrap();
        let fd1 = file1.as_raw_fd();
        let fd2 = file2.as_raw_fd();
        // Map files to each other's FDs, to ensure that the temporary FD logic works.
        assert!(command
            .fd_mappings(vec![
                FdMapping {
                    parent_fd: fd1,
                    child_fd: fd2,
                },
                FdMapping {
                    parent_fd: fd2,
                    child_fd: fd1,
                },
            ])
            .is_ok(),);

        let output = command.output().unwrap();
        // Expect one more Fd for the /proc/self/fd directory. We can't predict what number it will
        // be assigned, because 3 might or might not be taken already by fd1 or fd2.
        expect_fds(&output, &[0, 1, 2, fd1, fd2], 1);
    }

    #[test]
    fn one_to_one_mapping() {
        setup();

        let mut command = Command::new("ls");
        command.arg("/proc/self/fd");

        let file1 = File::open("testdata/file1.txt").unwrap();
        let file2 = File::open("testdata/file2.txt").unwrap();
        let fd1 = file1.as_raw_fd();
        // Map files to each other's FDs, to ensure that the temporary FD logic works.
        assert!(command
            .fd_mappings(vec![FdMapping {
                parent_fd: fd1,
                child_fd: fd1,
            }])
            .is_ok());

        let output = command.output().unwrap();
        // Expect one more Fd for the /proc/self/fd directory. We can't predict what number it will
        // be assigned, because 3 might or might not be taken already by fd1 or fd2.
        expect_fds(&output, &[0, 1, 2, fd1], 1);

        // Keep file2 open until the end, to ensure that it's not passed to the child.
        drop(file2);
    }

    #[test]
    fn map_stdin() {
        setup();

        let mut command = Command::new("cat");

        let file = File::open("testdata/file1.txt").unwrap();
        // Map the file to stdin.
        assert!(command
            .fd_mappings(vec![FdMapping {
                parent_fd: file.as_raw_fd(),
                child_fd: 0,
            },])
            .is_ok());

        let output = command.output().unwrap();
        assert!(output.status.success());
        assert_eq!(output.stdout, b"test 1");
    }

    /// Parse the output of ls into a set of filenames
    fn parse_ls_output(output: &[u8]) -> HashSet<String> {
        str::from_utf8(output)
            .unwrap()
            .split_terminator("\n")
            .map(str::to_owned)
            .collect()
    }

    /// Check that the output of `ls /proc/self/fd` contains the expected set of FDs, plus exactly
    /// `extra` extra FDs.
    fn expect_fds(output: &Output, expected_fds: &[RawFd], extra: usize) {
        assert!(output.status.success());
        let expected_fds: HashSet<String> = expected_fds.iter().map(RawFd::to_string).collect();
        let fds = parse_ls_output(&output.stdout);
        if extra == 0 {
            assert_eq!(fds, expected_fds);
        } else {
            assert!(expected_fds.is_subset(&fds));
            assert_eq!(fds.len(), expected_fds.len() + extra);
        }
    }

    fn setup() {
        SETUP.call_once(close_excess_fds);
    }

    /// Close all file descriptors apart from stdin, stdout and stderr.
    ///
    /// This is necessary because GitHub Actions opens a bunch of others for some reason.
    fn close_excess_fds() {
        let dir = read_dir("/proc/self/fd").unwrap();
        for entry in dir {
            let entry = entry.unwrap();
            let fd: RawFd = entry.file_name().to_str().unwrap().parse().unwrap();
            if fd > 3 {
                close(fd).unwrap();
            }
        }
    }
}
<|endoftext|>


<commit_before>#![crate_name="gdal"]
#![crate_type="lib"]
#![feature(unsafe_destructor)]
#![feature(associated_types)]

extern crate libc;
#[cfg(test)] extern crate test;

use libc::c_char;
use std::c_str::ToCStr;

mod utils;
pub mod raster;
pub mod vector;
pub mod proj;
pub mod geom;
pub mod warp;

#[link(name="gdal")]
extern {
    fn GDALVersionInfo(key: *const c_char) -> *const c_char;
}

pub fn version_info(key: &str) -> String {
    let info = key.with_c_str(|c_key| {
        let rv = unsafe { GDALVersionInfo(c_key) };
        return utils::_string(rv);
    });
    return info;
}

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

    #[test]
    fn test_version_info() {
        let release_date = version_info("RELEASE_DATE");
        let release_name = version_info("RELEASE_NAME");
        let version_text = version_info("--version");

        let expected_text: String = format!(
            "GDAL {}, released {}/{}/{}",
            release_name,
            release_date.as_slice().slice(0, 4),
            release_date.as_slice().slice(4, 6),
            release_date.as_slice().slice(6, 8),
        );

        assert_eq!(version_text, expected_text);
    }
}
<commit_msg>remove 'associated_types' feature<commit_after>#![crate_name="gdal"]
#![crate_type="lib"]
#![feature(unsafe_destructor)]

extern crate libc;
#[cfg(test)] extern crate test;

use libc::c_char;
use std::c_str::ToCStr;

mod utils;
pub mod raster;
pub mod vector;
pub mod proj;
pub mod geom;
pub mod warp;

#[link(name="gdal")]
extern {
    fn GDALVersionInfo(key: *const c_char) -> *const c_char;
}

pub fn version_info(key: &str) -> String {
    let info = key.with_c_str(|c_key| {
        let rv = unsafe { GDALVersionInfo(c_key) };
        return utils::_string(rv);
    });
    return info;
}

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

    #[test]
    fn test_version_info() {
        let release_date = version_info("RELEASE_DATE");
        let release_name = version_info("RELEASE_NAME");
        let version_text = version_info("--version");

        let expected_text: String = format!(
            "GDAL {}, released {}/{}/{}",
            release_name,
            release_date.as_slice().slice(0, 4),
            release_date.as_slice().slice(4, 6),
            release_date.as_slice().slice(6, 8),
        );

        assert_eq!(version_text, expected_text);
    }
}
<|endoftext|>


<commit_before>#![crate_id = "typedopts"]
#![crate_type = "lib"]

extern crate getopts;
extern crate serialize;
use getopts::Matches;
use std::from_str::FromStr;
use std::str::StrSlice;
use serialize::Decodable;

#[deriving(Eq, Show)]
pub enum ErrorType {
  UnimplementedDecoder,
  MissingField(~str),
  ExpectedType(~str, ~str, ~str)
}

#[deriving(Eq, Show)]
pub struct Error {
  e: ErrorType
}

pub type DecodeResult<T> =  Result<T, ErrorType>;

pub struct Decoder {
  priv matches: Matches,
  priv cur: ~str,
  priv current_type: ~str
}

impl Decoder {
  pub fn new(matches: Matches) -> Decoder {
    Decoder {
      matches: matches,
      cur: ~"",
      current_type: ~""
    }
  }

  fn expected(&self, expected_type: &str) -> ErrorType {
    ExpectedType(self.cur.to_owned(),
                       expected_type.to_owned(),
                       self.matches.opt_str(self.cur).unwrap())
  }

}

pub fn decode<T:Send+Decodable<Decoder, ErrorType>>(matches: Matches) -> DecodeResult<T> {
  let mut decoder = Decoder::new(matches);
  Decodable::decode(&mut decoder)
}

impl ErrorType {
  pub fn to_err_msg(self) -> ~str {
    match self {
      UnimplementedDecoder => format!("this function is not implemented"),
      MissingField(ref s)  => format!("the required field '{}' is not present", s),
      ExpectedType(ref field, ref expected, ref value) => {
        format!("Expected type '{}' for field '{}' but got value '{}'", expected, field, value)
      }
    }
  }
}
impl<T:FromStr> Decoder {
  fn get_field<T:FromStr>(&self, field: &str) -> Option<T> {
    match self.matches.opt_str(self.cur) {
      None    => None,
      Some(s) => FromStr::from_str(s)
    }
  }
}

impl serialize::Decoder<ErrorType> for Decoder {

  fn read_nil(&mut self) -> DecodeResult<()> {
    Err(UnimplementedDecoder)
  }

  fn read_u64(&mut self)  -> DecodeResult<u64>  {
    match self.matches.opt_str(self.cur) {
      None    => Err(MissingField(self.cur.clone())),
      Some(s) => match FromStr::from_str(s) {
        None     => Err(self.expected(~"u64")),
        Some(nb) => Ok(nb)
      }
    }
  }
  fn read_u32(&mut self)  -> DecodeResult<u32>  { Ok(try!(self.read_u64()) as u32) }
  fn read_u16(&mut self)  -> DecodeResult<u16>  { Ok(try!(self.read_u64()) as u16) }
  fn read_u8 (&mut self)  -> DecodeResult<u8>   { Ok(try!(self.read_u64()) as u8) }
  fn read_uint(&mut self) -> DecodeResult<uint> { Ok(try!(self.read_u64()) as uint) }

  fn read_i64(&mut self) -> DecodeResult<i64> {
    match self.matches.opt_str(self.cur) {
      None    => Err(MissingField(self.cur.clone())),
      Some(s) => match FromStr::from_str(s) {
        None     => Err(self.expected(~"i64")),
        Some(nb) => Ok(nb)
      }
    }
  }
  fn read_i32(&mut self) -> DecodeResult<i32> { Ok(try!(self.read_i64()) as i32) }
  fn read_i16(&mut self) -> DecodeResult<i16> { Ok(try!(self.read_i64()) as i16) }
  fn read_i8 (&mut self) -> DecodeResult<i8>  { Ok(try!(self.read_i64()) as i8) }
  fn read_int(&mut self) -> DecodeResult<int> { Ok(try!(self.read_i64()) as int) }

  fn read_f32(&mut self) -> DecodeResult<f32> { Ok(try!(self.read_f64()) as f32) }
  fn read_f64(&mut self) -> DecodeResult<f64> {
    match self.matches.opt_str(self.cur) {
      None    => Err(MissingField(self.cur.clone())),
      Some(s) => match FromStr::from_str(s) {
        None     => Err(self.expected(~"f64")),
        Some(nb) => Ok(nb)
      }
    }
  }

  fn read_bool(&mut self) -> DecodeResult<bool> {
    match self.matches.opt_str(self.cur) {
      None    => Err(MissingField(self.cur.clone())),
      Some(s) => match FromStr::from_str(s) {
        None     => Err(self.expected("boolean")),
        Some(b) => Ok(b)
      }
    }
  }

  fn read_char(&mut self) -> DecodeResult<char> {
    match self.matches.opt_str(self.cur) {
      None    => Err(MissingField(self.cur.clone())),
      Some(s) => if s.char_len() == 1 { Ok(s.char_at(0)) } else { Err(self.expected("char")) }
    }
  }

  fn read_str(&mut self) -> DecodeResult<~str> {
    match self.matches.opt_str(self.cur) {
      None    => Err(MissingField(self.cur.clone())),
      Some(s) => Ok(s)
    }
  }

  fn read_enum<T>(&mut self, name: &str, f: |&mut Decoder| -> DecodeResult<T>) -> DecodeResult<T> {
    //println!("reading enum: {}", name);
    self.current_type = name.to_owned();
    f(self)
  }

  fn read_enum_variant<T>(&mut self, names: &[&str], f: |&mut Decoder, uint| -> DecodeResult<T>) -> DecodeResult<T> {
    //println!("reading enum variant({}): {}", self.cur, names);
    match self.matches.opt_str(self.cur) {
      None    => Err(MissingField(self.cur.clone())),
      Some(s) => match names.iter().position(|&e| e == s) {
        None    => Err(self.expected(self.current_type + " enum")),
        Some(i) => f(self, i)
      }
    }
  }

  fn read_enum_variant_arg<T>(&mut self, a_idx: uint, f: |&mut Decoder| -> DecodeResult<T>) -> DecodeResult<T> {
    //println!("reading enum variant_arg: {}", a_idx);
    f(self);
    Err(UnimplementedDecoder)
  }

  fn read_enum_struct_variant<T>(&mut self, names: &[&str], f: |&mut Decoder, uint| -> DecodeResult<T>) -> DecodeResult<T> {
    //println!("reading enum struct variant: {}", names);
    f(self, 0);
    Err(UnimplementedDecoder)
  }

  fn read_enum_struct_variant_field<T>(&mut self, f_name: &str, f_idx: uint, f: |&mut Decoder| -> DecodeResult<T>) -> DecodeResult<T> {
    //println!("reading enum struct variant field: {}, {}", f_name, f_idx);
    f(self);
    Err(UnimplementedDecoder)
  }

  fn read_struct<T>(&mut self, s_name: &str, len: uint, f: |&mut Decoder| -> DecodeResult<T>) -> DecodeResult<T> {
    //println!("reading struct: {} | len = {}", s_name, len);
    self.cur = s_name.to_owned();
    f(self)
  }

  fn read_struct_field<T>(&mut self, f_name: &str, f_idx: uint, f: |&mut Decoder| -> DecodeResult<T>) -> DecodeResult<T> {
    //println!("reading struct field: {} | idx = {}", f_name, f_idx);
    self.cur = f_name.to_owned();
    let data = f(self);
    //println!("got struct field data: {}", data);
    data
  }

  fn read_option<T>(&mut self, f: |&mut Decoder, bool| -> DecodeResult<T>) -> DecodeResult<T> {
    //println!("read_option");
    match self.matches.opt_str(self.cur) {
      None    => {
        //println!("option not there");
        f(self, false)
      },
      Some(s) => {
        //println!("option is there");
        f(self, true)
      }
    }
  }

  fn read_tuple<T>(&mut self, f: |&mut Decoder, uint| -> DecodeResult<T>) -> DecodeResult<T> {
    f(self, 0);
    Err(UnimplementedDecoder)
  }

  fn read_tuple_arg<T>(&mut self, a_idx: uint, f: |&mut Decoder| -> DecodeResult<T>) -> DecodeResult<T> {
    f(self);
    Err(UnimplementedDecoder)
  }

  fn read_tuple_struct<T>(&mut self, s_name: &str, f: |&mut Decoder, uint| -> DecodeResult<T>) -> DecodeResult<T> {
    f(self, 0);
    Err(UnimplementedDecoder)
  }

  fn read_tuple_struct_arg<T>(&mut self, a_idx: uint, f: |&mut Decoder| -> DecodeResult<T>) -> DecodeResult<T> {
    f(self);
    Err(UnimplementedDecoder)
  }

  fn read_seq<T>(&mut self, f: |&mut Decoder, uint| -> DecodeResult<T>) -> DecodeResult<T> {
    f(self, 0);
    Err(UnimplementedDecoder)
  }

  fn read_seq_elt<T>(&mut self, idx: uint, f: |&mut Decoder| -> DecodeResult<T>) -> DecodeResult<T> {
    f(self);
    Err(UnimplementedDecoder)
  }

  fn read_map<T>(&mut self, f: |&mut Decoder, uint| -> DecodeResult<T>) -> DecodeResult<T> {
    f(self, 0);
    Err(UnimplementedDecoder)
  }

  fn read_map_elt_key<T>(&mut self, idx: uint, f: |&mut Decoder| -> DecodeResult<T>) -> DecodeResult<T> {
    f(self);
    Err(UnimplementedDecoder)
  }

  fn read_map_elt_val<T>(&mut self, idx: uint, f: |&mut Decoder| -> DecodeResult<T>) -> DecodeResult<T> {
    f(self);
    Err(UnimplementedDecoder)
  }

}
<commit_msg>remove privacy tags<commit_after>#![crate_id = "typedopts"]
#![crate_type = "lib"]

extern crate getopts;
extern crate serialize;
use getopts::Matches;
use std::from_str::FromStr;
use std::str::StrSlice;
use serialize::Decodable;

#[deriving(Eq, Show)]
pub enum ErrorType {
  UnimplementedDecoder,
  MissingField(~str),
  ExpectedType(~str, ~str, ~str)
}

#[deriving(Eq, Show)]
pub struct Error {
  e: ErrorType
}

pub type DecodeResult<T> =  Result<T, ErrorType>;

pub struct Decoder {
  matches: Matches,
  cur: ~str,
  current_type: ~str
}

impl Decoder {
  pub fn new(matches: Matches) -> Decoder {
    Decoder {
      matches: matches,
      cur: ~"",
      current_type: ~""
    }
  }

  fn expected(&self, expected_type: &str) -> ErrorType {
    ExpectedType(self.cur.to_owned(),
                       expected_type.to_owned(),
                       self.matches.opt_str(self.cur).unwrap())
  }

}

pub fn decode<T:Send+Decodable<Decoder, ErrorType>>(matches: Matches) -> DecodeResult<T> {
  let mut decoder = Decoder::new(matches);
  Decodable::decode(&mut decoder)
}

impl ErrorType {
  pub fn to_err_msg(self) -> ~str {
    match self {
      UnimplementedDecoder => format!("this function is not implemented"),
      MissingField(ref s)  => format!("the required field '{}' is not present", s),
      ExpectedType(ref field, ref expected, ref value) => {
        format!("Expected type '{}' for field '{}' but got value '{}'", expected, field, value)
      }
    }
  }
}
impl<T:FromStr> Decoder {
  fn get_field<T:FromStr>(&self, field: &str) -> Option<T> {
    match self.matches.opt_str(self.cur) {
      None    => None,
      Some(s) => FromStr::from_str(s)
    }
  }
}

impl serialize::Decoder<ErrorType> for Decoder {

  fn read_nil(&mut self) -> DecodeResult<()> {
    Err(UnimplementedDecoder)
  }

  fn read_u64(&mut self)  -> DecodeResult<u64>  {
    match self.matches.opt_str(self.cur) {
      None    => Err(MissingField(self.cur.clone())),
      Some(s) => match FromStr::from_str(s) {
        None     => Err(self.expected(~"u64")),
        Some(nb) => Ok(nb)
      }
    }
  }
  fn read_u32(&mut self)  -> DecodeResult<u32>  { Ok(try!(self.read_u64()) as u32) }
  fn read_u16(&mut self)  -> DecodeResult<u16>  { Ok(try!(self.read_u64()) as u16) }
  fn read_u8 (&mut self)  -> DecodeResult<u8>   { Ok(try!(self.read_u64()) as u8) }
  fn read_uint(&mut self) -> DecodeResult<uint> { Ok(try!(self.read_u64()) as uint) }

  fn read_i64(&mut self) -> DecodeResult<i64> {
    match self.matches.opt_str(self.cur) {
      None    => Err(MissingField(self.cur.clone())),
      Some(s) => match FromStr::from_str(s) {
        None     => Err(self.expected(~"i64")),
        Some(nb) => Ok(nb)
      }
    }
  }
  fn read_i32(&mut self) -> DecodeResult<i32> { Ok(try!(self.read_i64()) as i32) }
  fn read_i16(&mut self) -> DecodeResult<i16> { Ok(try!(self.read_i64()) as i16) }
  fn read_i8 (&mut self) -> DecodeResult<i8>  { Ok(try!(self.read_i64()) as i8) }
  fn read_int(&mut self) -> DecodeResult<int> { Ok(try!(self.read_i64()) as int) }

  fn read_f32(&mut self) -> DecodeResult<f32> { Ok(try!(self.read_f64()) as f32) }
  fn read_f64(&mut self) -> DecodeResult<f64> {
    match self.matches.opt_str(self.cur) {
      None    => Err(MissingField(self.cur.clone())),
      Some(s) => match FromStr::from_str(s) {
        None     => Err(self.expected(~"f64")),
        Some(nb) => Ok(nb)
      }
    }
  }

  fn read_bool(&mut self) -> DecodeResult<bool> {
    match self.matches.opt_str(self.cur) {
      None    => Err(MissingField(self.cur.clone())),
      Some(s) => match FromStr::from_str(s) {
        None     => Err(self.expected("boolean")),
        Some(b) => Ok(b)
      }
    }
  }

  fn read_char(&mut self) -> DecodeResult<char> {
    match self.matches.opt_str(self.cur) {
      None    => Err(MissingField(self.cur.clone())),
      Some(s) => if s.char_len() == 1 { Ok(s.char_at(0)) } else { Err(self.expected("char")) }
    }
  }

  fn read_str(&mut self) -> DecodeResult<~str> {
    match self.matches.opt_str(self.cur) {
      None    => Err(MissingField(self.cur.clone())),
      Some(s) => Ok(s)
    }
  }

  fn read_enum<T>(&mut self, name: &str, f: |&mut Decoder| -> DecodeResult<T>) -> DecodeResult<T> {
    //println!("reading enum: {}", name);
    self.current_type = name.to_owned();
    f(self)
  }

  fn read_enum_variant<T>(&mut self, names: &[&str], f: |&mut Decoder, uint| -> DecodeResult<T>) -> DecodeResult<T> {
    //println!("reading enum variant({}): {}", self.cur, names);
    match self.matches.opt_str(self.cur) {
      None    => Err(MissingField(self.cur.clone())),
      Some(s) => match names.iter().position(|&e| e == s) {
        None    => Err(self.expected(self.current_type + " enum")),
        Some(i) => f(self, i)
      }
    }
  }

  fn read_enum_variant_arg<T>(&mut self, a_idx: uint, f: |&mut Decoder| -> DecodeResult<T>) -> DecodeResult<T> {
    //println!("reading enum variant_arg: {}", a_idx);
    f(self);
    Err(UnimplementedDecoder)
  }

  fn read_enum_struct_variant<T>(&mut self, names: &[&str], f: |&mut Decoder, uint| -> DecodeResult<T>) -> DecodeResult<T> {
    //println!("reading enum struct variant: {}", names);
    f(self, 0);
    Err(UnimplementedDecoder)
  }

  fn read_enum_struct_variant_field<T>(&mut self, f_name: &str, f_idx: uint, f: |&mut Decoder| -> DecodeResult<T>) -> DecodeResult<T> {
    //println!("reading enum struct variant field: {}, {}", f_name, f_idx);
    f(self);
    Err(UnimplementedDecoder)
  }

  fn read_struct<T>(&mut self, s_name: &str, len: uint, f: |&mut Decoder| -> DecodeResult<T>) -> DecodeResult<T> {
    //println!("reading struct: {} | len = {}", s_name, len);
    self.cur = s_name.to_owned();
    f(self)
  }

  fn read_struct_field<T>(&mut self, f_name: &str, f_idx: uint, f: |&mut Decoder| -> DecodeResult<T>) -> DecodeResult<T> {
    //println!("reading struct field: {} | idx = {}", f_name, f_idx);
    self.cur = f_name.to_owned();
    let data = f(self);
    //println!("got struct field data: {}", data);
    data
  }

  fn read_option<T>(&mut self, f: |&mut Decoder, bool| -> DecodeResult<T>) -> DecodeResult<T> {
    //println!("read_option");
    match self.matches.opt_str(self.cur) {
      None    => {
        //println!("option not there");
        f(self, false)
      },
      Some(s) => {
        //println!("option is there");
        f(self, true)
      }
    }
  }

  fn read_tuple<T>(&mut self, f: |&mut Decoder, uint| -> DecodeResult<T>) -> DecodeResult<T> {
    f(self, 0);
    Err(UnimplementedDecoder)
  }

  fn read_tuple_arg<T>(&mut self, a_idx: uint, f: |&mut Decoder| -> DecodeResult<T>) -> DecodeResult<T> {
    f(self);
    Err(UnimplementedDecoder)
  }

  fn read_tuple_struct<T>(&mut self, s_name: &str, f: |&mut Decoder, uint| -> DecodeResult<T>) -> DecodeResult<T> {
    f(self, 0);
    Err(UnimplementedDecoder)
  }

  fn read_tuple_struct_arg<T>(&mut self, a_idx: uint, f: |&mut Decoder| -> DecodeResult<T>) -> DecodeResult<T> {
    f(self);
    Err(UnimplementedDecoder)
  }

  fn read_seq<T>(&mut self, f: |&mut Decoder, uint| -> DecodeResult<T>) -> DecodeResult<T> {
    f(self, 0);
    Err(UnimplementedDecoder)
  }

  fn read_seq_elt<T>(&mut self, idx: uint, f: |&mut Decoder| -> DecodeResult<T>) -> DecodeResult<T> {
    f(self);
    Err(UnimplementedDecoder)
  }

  fn read_map<T>(&mut self, f: |&mut Decoder, uint| -> DecodeResult<T>) -> DecodeResult<T> {
    f(self, 0);
    Err(UnimplementedDecoder)
  }

  fn read_map_elt_key<T>(&mut self, idx: uint, f: |&mut Decoder| -> DecodeResult<T>) -> DecodeResult<T> {
    f(self);
    Err(UnimplementedDecoder)
  }

  fn read_map_elt_val<T>(&mut self, idx: uint, f: |&mut Decoder| -> DecodeResult<T>) -> DecodeResult<T> {
    f(self);
    Err(UnimplementedDecoder)
  }

}
<|endoftext|>


<commit_before>pub mod gregorian {
    /// Easter in the Gregorian calendar
    pub fn month_day(year: i32) -> (u32, u32) {
        let a: i32 = year % 19;
        let b: i32 = year / 100;
        let c: i32 = year % 100;
        let d: i32 = b / 4;
        let e: i32 = b % 4;
        let f: i32 = (b + 8) / 25;
        let g: i32 = (b - f + 1) / 3;
        let h: i32 = (19 * a + b - d - g + 15) % 30;
        let i: i32 = c / 4;
        let k: i32 = c % 4;
        let l: i32 = (32 + 2 * e + 2 * i - h - k) % 7;
        let m: i32 = (a + 11 * h + 22 * l) / 451;
        let month: i32 = (h + l - 7 * m + 114) / 31;
        let day: i32 = (h + l - 7 * m + 114) % 31 + 1;
        (month as u32, day as u32)
    }
}

pub mod julian {
    /// Easter in the Julian calendar
    pub fn month_day(year: i32) -> (u32, u32) {
        let a: i32 = year % 4;
        let b: i32 = year % 7;
        let c: i32 = year % 19;
        let d: i32 = (19 * c + 15) % 30;
        let e: i32 = (2 * a + 4 * b - d + 34) % 7;
        let f: i32 = d + e + 114;
        let month: i32 = f / 31;
        let day: i32 = f % 31 + 1;
        (month as u32, day as u32)
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn gregorian_month_day() {
        use super::gregorian::month_day;
        assert_eq!(month_day(1961), (4, 2));
        assert_eq!(month_day(1996), (4, 7));
        assert_eq!(month_day(1997), (3, 30));
        assert_eq!(month_day(1998), (4, 12));
        assert_eq!(month_day(2000), (4, 23));
        assert_eq!(month_day(2001), (4, 15));
        assert_eq!(month_day(2002), (3, 31));
        assert_eq!(month_day(2003), (4, 20));
        assert_eq!(month_day(2004), (4, 11));
        assert_eq!(month_day(2005), (3, 27));
        assert_eq!(month_day(2006), (4, 16));
        assert_eq!(month_day(2007), (4, 8));
        assert_eq!(month_day(2008), (3, 23));
        assert_eq!(month_day(2009), (4, 12));
        assert_eq!(month_day(2010), (4, 4));
        assert_eq!(month_day(2011), (4, 24));
        assert_eq!(month_day(2012), (4, 8));
        assert_eq!(month_day(2013), (3, 31));
        assert_eq!(month_day(2014), (4, 20));
        assert_eq!(month_day(2015), (4, 5));
        assert_eq!(month_day(2016), (3, 27));
        assert_eq!(month_day(2017), (4, 16));
        assert_eq!(month_day(2018), (4, 1));
        assert_eq!(month_day(2019), (4, 21));
        assert_eq!(month_day(2020), (4, 12));
    }

    #[test]
    fn julian_month_day() {
        use super::julian::month_day;
        assert_eq!(month_day(1961), (3, 27));
        assert_eq!(month_day(1996), (4, 1));
        assert_eq!(month_day(1997), (4, 14));
        assert_eq!(month_day(1998), (4, 6));
        assert_eq!(month_day(1999), (3, 29));
        assert_eq!(month_day(2000), (4, 17));
        assert_eq!(month_day(2001), (4, 2));
        assert_eq!(month_day(2002), (4, 22));
        assert_eq!(month_day(2003), (4, 14));
        assert_eq!(month_day(2004), (3, 29));
        assert_eq!(month_day(2005), (4, 18));
        assert_eq!(month_day(2006), (4, 10));
        assert_eq!(month_day(2007), (3, 26));
        assert_eq!(month_day(2008), (4, 14));
        assert_eq!(month_day(2009), (4, 6));
        assert_eq!(month_day(2010), (3, 22));
        assert_eq!(month_day(2011), (4, 11));
        assert_eq!(month_day(2012), (4, 2));
        assert_eq!(month_day(2013), (4, 22));
        assert_eq!(month_day(2014), (4, 7));
        assert_eq!(month_day(2015), (3, 30));
        assert_eq!(month_day(2016), (4, 18));
        assert_eq!(month_day(2017), (4, 3));
        assert_eq!(month_day(2018), (3, 26));
        assert_eq!(month_day(2019), (4, 15));
        assert_eq!(month_day(2020), (4, 6));
    }
}
<commit_msg>don't be so specific about i32<commit_after>pub mod gregorian {
    /// Easter in the Gregorian calendar
    pub fn month_day(year: i32) -> (u32, u32) {
        let a = year % 19;
        let b = year / 100;
        let c = year % 100;
        let d = b / 4;
        let e = b % 4;
        let f = (b + 8) / 25;
        let g = (b - f + 1) / 3;
        let h = (19 * a + b - d - g + 15) % 30;
        let i = c / 4;
        let k = c % 4;
        let l = (32 + 2 * e + 2 * i - h - k) % 7;
        let m = (a + 11 * h + 22 * l) / 451;
        let month = (h + l - 7 * m + 114) / 31;
        let day = (h + l - 7 * m + 114) % 31 + 1;
        (month as u32, day as u32)
    }
}

pub mod julian {
    /// Easter in the Julian calendar
    pub fn month_day(year: i32) -> (u32, u32) {
        let a = year % 4;
        let b = year % 7;
        let c = year % 19;
        let d = (19 * c + 15) % 30;
        let e = (2 * a + 4 * b - d + 34) % 7;
        let f = d + e + 114;
        let month = f / 31;
        let day = f % 31 + 1;
        (month as u32, day as u32)
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn gregorian_month_day() {
        use super::gregorian::month_day;
        assert_eq!(month_day(1961), (4, 2));
        assert_eq!(month_day(1996), (4, 7));
        assert_eq!(month_day(1997), (3, 30));
        assert_eq!(month_day(1998), (4, 12));
        assert_eq!(month_day(2000), (4, 23));
        assert_eq!(month_day(2001), (4, 15));
        assert_eq!(month_day(2002), (3, 31));
        assert_eq!(month_day(2003), (4, 20));
        assert_eq!(month_day(2004), (4, 11));
        assert_eq!(month_day(2005), (3, 27));
        assert_eq!(month_day(2006), (4, 16));
        assert_eq!(month_day(2007), (4, 8));
        assert_eq!(month_day(2008), (3, 23));
        assert_eq!(month_day(2009), (4, 12));
        assert_eq!(month_day(2010), (4, 4));
        assert_eq!(month_day(2011), (4, 24));
        assert_eq!(month_day(2012), (4, 8));
        assert_eq!(month_day(2013), (3, 31));
        assert_eq!(month_day(2014), (4, 20));
        assert_eq!(month_day(2015), (4, 5));
        assert_eq!(month_day(2016), (3, 27));
        assert_eq!(month_day(2017), (4, 16));
        assert_eq!(month_day(2018), (4, 1));
        assert_eq!(month_day(2019), (4, 21));
        assert_eq!(month_day(2020), (4, 12));
    }

    #[test]
    fn julian_month_day() {
        use super::julian::month_day;
        assert_eq!(month_day(1961), (3, 27));
        assert_eq!(month_day(1996), (4, 1));
        assert_eq!(month_day(1997), (4, 14));
        assert_eq!(month_day(1998), (4, 6));
        assert_eq!(month_day(1999), (3, 29));
        assert_eq!(month_day(2000), (4, 17));
        assert_eq!(month_day(2001), (4, 2));
        assert_eq!(month_day(2002), (4, 22));
        assert_eq!(month_day(2003), (4, 14));
        assert_eq!(month_day(2004), (3, 29));
        assert_eq!(month_day(2005), (4, 18));
        assert_eq!(month_day(2006), (4, 10));
        assert_eq!(month_day(2007), (3, 26));
        assert_eq!(month_day(2008), (4, 14));
        assert_eq!(month_day(2009), (4, 6));
        assert_eq!(month_day(2010), (3, 22));
        assert_eq!(month_day(2011), (4, 11));
        assert_eq!(month_day(2012), (4, 2));
        assert_eq!(month_day(2013), (4, 22));
        assert_eq!(month_day(2014), (4, 7));
        assert_eq!(month_day(2015), (3, 30));
        assert_eq!(month_day(2016), (4, 18));
        assert_eq!(month_day(2017), (4, 3));
        assert_eq!(month_day(2018), (3, 26));
        assert_eq!(month_day(2019), (4, 15));
        assert_eq!(month_day(2020), (4, 6));
    }
}
<|endoftext|>


<commit_before>#![feature(plugin_registrar, quote, rustc_private, custom_attribute)]

extern crate rustc_plugin;
extern crate syntax;

use rustc_plugin::registry::Registry;
use syntax::ast::{Attribute, Block, Expr, ExprKind, Ident, Item, ItemKind, Mac,
                  MetaItem, MetaItemKind};
use syntax::fold::{self, Folder};
use syntax::ptr::P;
use syntax::codemap::{DUMMY_SP, Span};
use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxExtension};
use syntax::ext::build::AstBuilder;
use syntax::feature_gate::AttributeType;
use syntax::symbol::Symbol;
use syntax::util::small_vector::SmallVector;

pub fn insert_flame_guard(cx: &mut ExtCtxt, _span: Span, _mi: &MetaItem,
                          a: Annotatable) -> Annotatable {
    match a {
        Annotatable::Item(i) => Annotatable::Item(
            Flamer { cx: cx, ident: i.ident }.fold_item(i).expect_one("expected exactly one item")),
        Annotatable::TraitItem(i) => Annotatable::TraitItem(
            i.map(|i| Flamer { cx: cx, ident: i.ident }.fold_trait_item(i).expect_one("expected exactly one item"))),
        Annotatable::ImplItem(i) => Annotatable::ImplItem(
            i.map(|i| Flamer { cx: cx, ident: i.ident }.fold_impl_item(i).expect_one("expected exactly one item"))),
    }
}

struct Flamer<'a, 'cx: 'a> {
    ident: Ident,
    cx: &'a mut ExtCtxt<'cx>,
}

impl<'a, 'cx> Folder for Flamer<'a, 'cx> {
    fn fold_item(&mut self, item: P<Item>) -> SmallVector<P<Item>> {
        if let ItemKind::Mac(_) = item.node {
            let expanded = self.cx.expander().fold_item(item);
            expanded.into_iter()
                    .flat_map(|i| fold::noop_fold_item(i, self).into_iter())
                    .collect()
        } else {
            fold::noop_fold_item(item, self)
        }
    }

    fn fold_item_simple(&mut self, i: Item) -> Item {
        fn is_flame_annotation(attr: &Attribute) -> bool {
            match attr.value.node {
                MetaItemKind::Word => {
                    let name = &*attr.value.name.as_str();
                    name == "flame" || name == "noflame"
                },
                _ => false
            }
        }
        // don't double-flame nested annotations
        if i.attrs.iter().any(is_flame_annotation) { return i; }
        if let ItemKind::Mac(_) = i.node {
            return i;
        } else {
            self.ident = i.ident; // update in case of nested items
            fold::noop_fold_item_simple(i, self)
        }
    }

    fn fold_block(&mut self, block: P<Block>) -> P<Block> {
        block.map(|block| {
            let name = self.cx.expr_str(DUMMY_SP, self.ident.name);
            quote_block!(self.cx, {
                let g = ::flame::start_guard($name);
                let r = $block;
                g.end();
                r
            }).unwrap()
        })
    }

    fn fold_expr(&mut self, expr: P<Expr>) -> P<Expr> {
        if let ExprKind::Mac(_) = expr.node {
            self.cx.expander().fold_expr(expr)
                              .map(|e| fold::noop_fold_expr(e, self))
        } else {
            expr
        }
    }

    fn fold_mac(&mut self, mac: Mac) -> Mac {
        mac
    }
}

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_syntax_extension(Symbol::intern("flame"),
        SyntaxExtension::MultiModifier(Box::new(insert_flame_guard)));
    reg.register_attribute(String::from("noflame"), AttributeType::Whitelisted);
}
<commit_msg>rustup<commit_after>#![feature(plugin_registrar, quote, rustc_private, custom_attribute)]

extern crate rustc_plugin;
extern crate syntax;

use rustc_plugin::registry::Registry;
use syntax::ast::{Attribute, Block, Expr, ExprKind, Ident, Item, ItemKind, Mac,
                  MetaItem};
use syntax::fold::{self, Folder};
use syntax::ptr::P;
use syntax::codemap::{DUMMY_SP, Span};
use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxExtension};
use syntax::ext::build::AstBuilder;
use syntax::feature_gate::AttributeType;
use syntax::symbol::Symbol;
use syntax::util::small_vector::SmallVector;

pub fn insert_flame_guard(cx: &mut ExtCtxt, _span: Span, _mi: &MetaItem,
                          a: Annotatable) -> Annotatable {
    match a {
        Annotatable::Item(i) => Annotatable::Item(
            Flamer { cx: cx, ident: i.ident }.fold_item(i).expect_one("expected exactly one item")),
        Annotatable::TraitItem(i) => Annotatable::TraitItem(
            i.map(|i| Flamer { cx: cx, ident: i.ident }.fold_trait_item(i).expect_one("expected exactly one item"))),
        Annotatable::ImplItem(i) => Annotatable::ImplItem(
            i.map(|i| Flamer { cx: cx, ident: i.ident }.fold_impl_item(i).expect_one("expected exactly one item"))),
    }
}

struct Flamer<'a, 'cx: 'a> {
    ident: Ident,
    cx: &'a mut ExtCtxt<'cx>,
}

impl<'a, 'cx> Folder for Flamer<'a, 'cx> {
    fn fold_item(&mut self, item: P<Item>) -> SmallVector<P<Item>> {
        if let ItemKind::Mac(_) = item.node {
            let expanded = self.cx.expander().fold_item(item);
            expanded.into_iter()
                    .flat_map(|i| fold::noop_fold_item(i, self).into_iter())
                    .collect()
        } else {
            fold::noop_fold_item(item, self)
        }
    }

    fn fold_item_simple(&mut self, i: Item) -> Item {
        fn is_flame_annotation(attr: &Attribute) -> bool {
            attr.name().map_or(false, |name|
                    name == "flame" || name == "noflame")
        }
        // don't double-flame nested annotations
        if i.attrs.iter().any(is_flame_annotation) { return i; }
        if let ItemKind::Mac(_) = i.node {
            return i;
        } else {
            self.ident = i.ident; // update in case of nested items
            fold::noop_fold_item_simple(i, self)
        }
    }

    fn fold_block(&mut self, block: P<Block>) -> P<Block> {
        block.map(|block| {
            let name = self.cx.expr_str(DUMMY_SP, self.ident.name);
            quote_block!(self.cx, {
                let g = ::flame::start_guard($name);
                let r = $block;
                g.end();
                r
            }).unwrap()
        })
    }

    fn fold_expr(&mut self, expr: P<Expr>) -> P<Expr> {
        if let ExprKind::Mac(_) = expr.node {
            self.cx.expander().fold_expr(expr)
                              .map(|e| fold::noop_fold_expr(e, self))
        } else {
            expr
        }
    }

    fn fold_mac(&mut self, mac: Mac) -> Mac {
        mac
    }
}

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_syntax_extension(Symbol::intern("flame"),
        SyntaxExtension::MultiModifier(Box::new(insert_flame_guard)));
    reg.register_attribute(String::from("noflame"), AttributeType::Whitelisted);
}
<|endoftext|>