<commit_before>// Copyright 2016 Amanieu d'Antras
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

use std::mem;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::time::Instant;

use winapi::shared::basetsd::SIZE_T;
use winapi::shared::minwindef::{BOOL, DWORD, FALSE, TRUE};
use winapi::shared::winerror::ERROR_TIMEOUT;
use winapi::um::errhandlingapi::GetLastError;
use winapi::um::libloaderapi::{GetModuleHandleA, GetProcAddress};
use winapi::um::winbase::INFINITE;
use winapi::um::winnt::{LPCSTR, PVOID};

#[allow(non_snake_case)]
pub struct WaitAddress {
    WaitOnAddress: extern "system" fn(
        Address: PVOID,
        CompareAddress: PVOID,
        AddressSize: SIZE_T,
        dwMilliseconds: DWORD,
    ) -> BOOL,
    WakeByAddressSingle: extern "system" fn(Address: PVOID),
}

impl WaitAddress {
    #[allow(non_snake_case)]
    pub fn create() -> Option<WaitAddress> {
        // MSDN claims that that WaitOnAddress and WakeByAddressSingle are
        // located in kernel32.dll, but they are lying...
        let synch_dll =
            unsafe { GetModuleHandleA(b"api-ms-win-core-synch-l1-2-0.dll\0".as_ptr() as LPCSTR) };
        if synch_dll.is_null() {
            return None;
        }

        let WaitOnAddress =
            unsafe { GetProcAddress(synch_dll, b"WaitOnAddress\0".as_ptr() as LPCSTR) };
        if WaitOnAddress.is_null() {
            return None;
        }
        let WakeByAddressSingle =
            unsafe { GetProcAddress(synch_dll, b"WakeByAddressSingle\0".as_ptr() as LPCSTR) };
        if WakeByAddressSingle.is_null() {
            return None;
        }
        Some(WaitAddress {
            WaitOnAddress: unsafe { mem::transmute(WaitOnAddress) },
            WakeByAddressSingle: unsafe { mem::transmute(WakeByAddressSingle) },
        })
    }

    pub fn prepare_park(&'static self, key: &AtomicUsize) {
        key.store(1, Ordering::Relaxed);
    }

    pub fn timed_out(&'static self, key: &AtomicUsize) -> bool {
        key.load(Ordering::Relaxed) != 0
    }

    pub fn park(&'static self, key: &AtomicUsize) {
        while key.load(Ordering::Acquire) != 0 {
            let r = self.wait_on_address(key, INFINITE);
            debug_assert!(r == TRUE);
        }
    }

    pub fn park_until(&'static self, key: &AtomicUsize, timeout: Instant) -> bool {
        while key.load(Ordering::Acquire) != 0 {
            let now = Instant::now();
            if timeout <= now {
                return false;
            }
            let diff = timeout - now;
            let timeout = diff
                .as_secs()
                .checked_mul(1000)
                .and_then(|x| x.checked_add((diff.subsec_nanos() as u64 + 999999) / 1000000))
                .map(|ms| {
                    if ms > <DWORD>::max_value() as u64 {
                        INFINITE
                    } else {
                        ms as DWORD
                    }
                })
                .unwrap_or(INFINITE);
            if self.wait_on_address(key, timeout) == FALSE {
                debug_assert_eq!(unsafe { GetLastError() }, ERROR_TIMEOUT);
            }
        }
        true
    }

    pub fn unpark_lock(&'static self, key: &AtomicUsize) -> UnparkHandle {
        // We don't need to lock anything, just clear the state
        key.store(0, Ordering::Release);

        UnparkHandle {
            key: key,
            waitaddress: self,
        }
    }

    #[inline]
    fn wait_on_address(&'static self, key: &AtomicUsize, timeout: DWORD) -> BOOL {
        let cmp = 1usize;
        (self.WaitOnAddress)(
            key as *const _ as PVOID,
            &cmp as *const _ as PVOID,
            mem::size_of::<usize>() as SIZE_T,
            timeout,
        )
    }
}

// Handle for a thread that is about to be unparked. We need to mark the thread
// as unparked while holding the queue lock, but we delay the actual unparking
// until after the queue lock is released.
pub struct UnparkHandle {
    key: *const AtomicUsize,
    waitaddress: &'static WaitAddress,
}

impl UnparkHandle {
    // Wakes up the parked thread. This should be called after the queue lock is
    // released to avoid blocking the queue for too long.
    pub fn unpark(self) {
        (self.waitaddress.WakeByAddressSingle)(self.key as PVOID);
    }
}
<commit_msg>One unsafe block instead of many small<commit_after>// Copyright 2016 Amanieu d'Antras
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

use std::mem;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::time::Instant;

use winapi::shared::basetsd::SIZE_T;
use winapi::shared::minwindef::{BOOL, DWORD, FALSE, TRUE};
use winapi::shared::winerror::ERROR_TIMEOUT;
use winapi::um::errhandlingapi::GetLastError;
use winapi::um::libloaderapi::{GetModuleHandleA, GetProcAddress};
use winapi::um::winbase::INFINITE;
use winapi::um::winnt::{LPCSTR, PVOID};

#[allow(non_snake_case)]
pub struct WaitAddress {
    WaitOnAddress: extern "system" fn(
        Address: PVOID,
        CompareAddress: PVOID,
        AddressSize: SIZE_T,
        dwMilliseconds: DWORD,
    ) -> BOOL,
    WakeByAddressSingle: extern "system" fn(Address: PVOID),
}

impl WaitAddress {
    #[allow(non_snake_case)]
    pub fn create() -> Option<WaitAddress> {
        unsafe {
            // MSDN claims that that WaitOnAddress and WakeByAddressSingle are
            // located in kernel32.dll, but they are lying...
            let synch_dll =
                GetModuleHandleA(b"api-ms-win-core-synch-l1-2-0.dll\0".as_ptr() as LPCSTR);
            if synch_dll.is_null() {
                return None;
            }

            let WaitOnAddress = GetProcAddress(synch_dll, b"WaitOnAddress\0".as_ptr() as LPCSTR);
            if WaitOnAddress.is_null() {
                return None;
            }
            let WakeByAddressSingle =
                GetProcAddress(synch_dll, b"WakeByAddressSingle\0".as_ptr() as LPCSTR);
            if WakeByAddressSingle.is_null() {
                return None;
            }
            Some(WaitAddress {
                WaitOnAddress: mem::transmute(WaitOnAddress),
                WakeByAddressSingle: mem::transmute(WakeByAddressSingle),
            })
        }
    }

    pub fn prepare_park(&'static self, key: &AtomicUsize) {
        key.store(1, Ordering::Relaxed);
    }

    pub fn timed_out(&'static self, key: &AtomicUsize) -> bool {
        key.load(Ordering::Relaxed) != 0
    }

    pub fn park(&'static self, key: &AtomicUsize) {
        while key.load(Ordering::Acquire) != 0 {
            let r = self.wait_on_address(key, INFINITE);
            debug_assert!(r == TRUE);
        }
    }

    pub fn park_until(&'static self, key: &AtomicUsize, timeout: Instant) -> bool {
        while key.load(Ordering::Acquire) != 0 {
            let now = Instant::now();
            if timeout <= now {
                return false;
            }
            let diff = timeout - now;
            let timeout = diff
                .as_secs()
                .checked_mul(1000)
                .and_then(|x| x.checked_add((diff.subsec_nanos() as u64 + 999999) / 1000000))
                .map(|ms| {
                    if ms > <DWORD>::max_value() as u64 {
                        INFINITE
                    } else {
                        ms as DWORD
                    }
                })
                .unwrap_or(INFINITE);
            if self.wait_on_address(key, timeout) == FALSE {
                debug_assert_eq!(unsafe { GetLastError() }, ERROR_TIMEOUT);
            }
        }
        true
    }

    pub fn unpark_lock(&'static self, key: &AtomicUsize) -> UnparkHandle {
        // We don't need to lock anything, just clear the state
        key.store(0, Ordering::Release);

        UnparkHandle {
            key: key,
            waitaddress: self,
        }
    }

    #[inline]
    fn wait_on_address(&'static self, key: &AtomicUsize, timeout: DWORD) -> BOOL {
        let cmp = 1usize;
        (self.WaitOnAddress)(
            key as *const _ as PVOID,
            &cmp as *const _ as PVOID,
            mem::size_of::<usize>() as SIZE_T,
            timeout,
        )
    }
}

// Handle for a thread that is about to be unparked. We need to mark the thread
// as unparked while holding the queue lock, but we delay the actual unparking
// until after the queue lock is released.
pub struct UnparkHandle {
    key: *const AtomicUsize,
    waitaddress: &'static WaitAddress,
}

impl UnparkHandle {
    // Wakes up the parked thread. This should be called after the queue lock is
    // released to avoid blocking the queue for too long.
    pub fn unpark(self) {
        (self.waitaddress.WakeByAddressSingle)(self.key as PVOID);
    }
}
<|endoftext|>


<commit_before>
#![feature(box_syntax,box_patterns)]
extern crate seax_svm;

use seax_svm::svm::slist::Stack;
use seax_svm::svm::slist::List::{Cons,Nil};
use seax_svm::svm::cell::Atom::*;
use seax_svm::svm::cell::SVMCell::*;
use seax_svm::svm::Inst::*;

macro_rules! list(
    ( $e:expr, $($rest:expr),+ ) => ( Cons($e, Box::new(list!( $( $rest ),+ )) ));
    ( $e:expr ) => ( Cons($e, Box::new(Nil)) );
    () => ( Box::new(Nil) );
);

/// SVM integration tests.
///
/// These are based on the sample programs in Zach Allaun's Clojure SECD
/// [implementation](https://github.com/zachallaun/secd). Each example also
/// provides the source code for the equivalent Lisp program.

/// Test for simple list construction through CONS.
///
/// ```lisp
/// (cons 10 (cons 20 nil))
/// ```
#[test]
fn test_list_creation() {
    let state = seax_svm::svm::eval_program(list!(
        InstCell(NIL),
        InstCell(LDC), AtomCell(SInt(10)), InstCell(CONS),
        InstCell(LDC), AtomCell(SInt(20)), InstCell(CONS)
        ));
    assert_eq!(state.peek(), Some(&ListCell( box list!(AtomCell(SInt(20)), AtomCell(SInt(10))))));
}

/// Test for simple list construction and destructuring
///
/// ```lisp
/// (car (cons 10 (cons 20 nil)))
/// ```
#[test]
fn test_list_car() {
    let state = seax_svm::svm::eval_program(list!(
        InstCell(NIL),
        InstCell(LDC), AtomCell(SInt(10)), InstCell(CONS),
        InstCell(LDC), AtomCell(SInt(20)), InstCell(CONS),
        InstCell(CAR)
        ));
    assert_eq!(state.peek(), Some(&AtomCell(SInt(20))));
}
/// Test for simple list construction and destructuring
///
/// ```lisp
/// (cdr (cons 10 (cons 20 nil)))
/// ```
#[test]
fn test_list_cdr() {
    assert_eq!(
        seax_svm::svm::eval_program(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(10)), InstCell(CONS),
            InstCell(LDC), AtomCell(SInt(20)), InstCell(CONS),
            InstCell(CDR)
            )
        ).peek(),
        Some(&ListCell(box list!(AtomCell(SInt(10)))))
    );
}

/// Test for simple mathematics application
///
/// ```lisp
/// (+ 10 10)
/// ```
#[test]
fn test_simple_add() {
    let state = seax_svm::svm::eval_program(list!(
        InstCell(LDC), AtomCell(SInt(10)),
        InstCell(LDC), AtomCell(SInt(10)),
        InstCell(ADD)
        ));
    assert_eq!(state.peek(), Some(&AtomCell(SInt(20))));
}

/// Test for nested arithmetic
///
/// ```lisp
/// (- 20 (+ 5 5))
/// ```
#[test]
fn test_nested_arith() {
    let state = seax_svm::svm::eval_program(list!(
        InstCell(LDC), AtomCell(SInt(5)),
        InstCell(LDC), AtomCell(SInt(5)),
        InstCell(ADD),
        InstCell(LDC), AtomCell(SInt(20)),
        InstCell(SUB)
        ));
    assert_eq!(state.peek(), Some(&AtomCell(SInt(10))));
}<commit_msg>Added a test for basic branching<commit_after>
#![feature(box_syntax,box_patterns)]
extern crate seax_svm;

use seax_svm::svm::slist::Stack;
use seax_svm::svm::slist::List::{Cons,Nil};
use seax_svm::svm::cell::Atom::*;
use seax_svm::svm::cell::SVMCell::*;
use seax_svm::svm::Inst::*;

macro_rules! list(
    ( $e:expr, $($rest:expr),+ ) => ( Cons($e, Box::new(list!( $( $rest ),+ )) ));
    ( $e:expr ) => ( Cons($e, Box::new(Nil)) );
    () => ( Box::new(Nil) );
);

/// SVM integration tests.
///
/// These are based on the sample programs in Zach Allaun's Clojure SECD
/// [implementation](https://github.com/zachallaun/secd). Each example also
/// provides the source code for the equivalent Lisp program.

/// Test for simple list construction through CONS.
///
/// ```lisp
/// (cons 10 (cons 20 nil))
/// ```
#[test]
fn test_list_creation() {
    let state = seax_svm::svm::eval_program(list!(
        InstCell(NIL),
        InstCell(LDC), AtomCell(SInt(10)), InstCell(CONS),
        InstCell(LDC), AtomCell(SInt(20)), InstCell(CONS)
        ));
    assert_eq!(state.peek(), Some(&ListCell( box list!(AtomCell(SInt(20)), AtomCell(SInt(10))))));
}

/// Test for simple list construction and destructuring
///
/// ```lisp
/// (car (cons 10 (cons 20 nil)))
/// ```
#[test]
fn test_list_car() {
    let state = seax_svm::svm::eval_program(list!(
        InstCell(NIL),
        InstCell(LDC), AtomCell(SInt(10)), InstCell(CONS),
        InstCell(LDC), AtomCell(SInt(20)), InstCell(CONS),
        InstCell(CAR)
        ));
    assert_eq!(state.peek(), Some(&AtomCell(SInt(20))));
}
/// Test for simple list construction and destructuring
///
/// ```lisp
/// (cdr (cons 10 (cons 20 nil)))
/// ```
#[test]
fn test_list_cdr() {
    assert_eq!(
        seax_svm::svm::eval_program(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(10)), InstCell(CONS),
            InstCell(LDC), AtomCell(SInt(20)), InstCell(CONS),
            InstCell(CDR)
            )
        ).peek(),
        Some(&ListCell(box list!(AtomCell(SInt(10)))))
    );
}

/// Test for simple mathematics application
///
/// ```lisp
/// (+ 10 10)
/// ```
#[test]
fn test_simple_add() {
    let state = seax_svm::svm::eval_program(list!(
        InstCell(LDC), AtomCell(SInt(10)),
        InstCell(LDC), AtomCell(SInt(10)),
        InstCell(ADD)
        ));
    assert_eq!(state.peek(), Some(&AtomCell(SInt(20))));
}

/// Test for nested arithmetic
///
/// ```lisp
/// (- 20 (+ 5 5))
/// ```
#[test]
fn test_nested_arith() {
    let state = seax_svm::svm::eval_program(list!(
        InstCell(LDC), AtomCell(SInt(5)),
        InstCell(LDC), AtomCell(SInt(5)),
        InstCell(ADD),
        InstCell(LDC), AtomCell(SInt(20)),
        InstCell(SUB)
        ));
    assert_eq!(state.peek(), Some(&AtomCell(SInt(10))));
}

/// Test for basic branching
///
/// ```lisp
/// ((if (= 0 (- 1 1)) true false)
/// ```
#[test]
fn test_basic_branching() {
    let state = seax_svm::svm::eval_program(list!(
        InstCell(LDC), AtomCell(SInt(1)), InstCell(LDC), AtomCell(SInt(1)),
        InstCell(SUB),
        InstCell(LDC), AtomCell(SInt(0)),
        InstCell(EQ),
        InstCell(SEL),
            ListCell(box list!(InstCell(LDC), AtomCell(SInt(1)), InstCell(JOIN))),
            ListCell(box list!(InstCell(NIL), InstCell(JOIN)))
        ));
    assert_eq!(state.peek(), Some(&AtomCell(SInt(1))));
}
<|endoftext|>


<commit_before>#![cfg(target_os = "macos")]
use crate::{
    ContextError, CreationError, GlAttributes, PixelFormat,
    PixelFormatRequirements, Robustness, Rect,
};

use cgl::{
    kCGLCECrashOnRemovedFunctions, kCGLCPSurfaceOpacity, CGLEnable,
    CGLSetParameter,
};
use cocoa::appkit::{self, NSOpenGLContext, NSOpenGLPixelFormat};
use cocoa::base::{id, nil};
use cocoa::foundation::NSAutoreleasePool;
use core_foundation::base::TCFType;
use core_foundation::bundle::{
    CFBundleGetBundleWithIdentifier, CFBundleGetFunctionPointerForName,
};
use core_foundation::string::CFString;
use objc::runtime::{BOOL, NO};

use crate::platform::macos::WindowExtMacOS;
use winit;
use winit::dpi;
use winit::event_loop::EventLoopWindowTarget;
use winit::window::{Window, WindowBuilder};

use std::ops::Deref;
use std::os::raw;
use std::str::FromStr;

mod helpers;

#[derive(Debug)]
pub enum Context {
    WindowedContext(WindowedContext),
    HeadlessContext(HeadlessContext),
}

#[derive(Debug)]
pub struct WindowedContext {
    // NSOpenGLContext
    context: IdRef,
    pixel_format: PixelFormat,
}

#[derive(Debug)]
pub struct HeadlessContext {
    context: IdRef,
}

impl Context {
    #[inline]
    pub fn new_windowed<T>(
        wb: WindowBuilder,
        el: &EventLoopWindowTarget<T>,
        pf_reqs: &PixelFormatRequirements,
        gl_attr: &GlAttributes<&Context>,
    ) -> Result<(Window, Self), CreationError> {
        let transparent = wb.window.transparent;
        let win = wb.build(el)?;

        let share_ctx = gl_attr.sharing.map_or(nil, |c| *c.get_id());

        match gl_attr.robustness {
            Robustness::RobustNoResetNotification
            | Robustness::RobustLoseContextOnReset => {
                return Err(CreationError::RobustnessNotSupported);
            }
            _ => (),
        }

        let view = win.ns_view() as id;

        let gl_profile = helpers::get_gl_profile(gl_attr, pf_reqs)?;
        let attributes = helpers::build_nsattributes(pf_reqs, gl_profile)?;
        unsafe {
            let pixel_format = IdRef::new(
                NSOpenGLPixelFormat::alloc(nil)
                    .initWithAttributes_(&attributes),
            );
            let pixel_format = match pixel_format.non_nil() {
                None => return Err(CreationError::NoAvailablePixelFormat),
                Some(pf) => pf,
            };

            let gl_context = IdRef::new(
                NSOpenGLContext::alloc(nil)
                    .initWithFormat_shareContext_(*pixel_format, share_ctx),
            );
            let gl_context = match gl_context.non_nil() {
                Some(gl_context) => gl_context,
                None => {
                    return Err(CreationError::NotSupported(
                        "could not open gl context".to_string(),
                    ));
                }
            };

            let pixel_format = {
                let get_attr =
                    |attrib: appkit::NSOpenGLPixelFormatAttribute| -> i32 {
                        let mut value = 0;
                        NSOpenGLPixelFormat::getValues_forAttribute_forVirtualScreen_(
                        *pixel_format,
                        &mut value,
                        attrib,
                        NSOpenGLContext::currentVirtualScreen(*gl_context),
                    );
                        value
                    };

                PixelFormat {
                    hardware_accelerated: get_attr(
                        appkit::NSOpenGLPFAAccelerated,
                    ) != 0,
                    color_bits: (get_attr(appkit::NSOpenGLPFAColorSize)
                        - get_attr(appkit::NSOpenGLPFAAlphaSize))
                        as u8,
                    alpha_bits: get_attr(appkit::NSOpenGLPFAAlphaSize) as u8,
                    depth_bits: get_attr(appkit::NSOpenGLPFADepthSize) as u8,
                    stencil_bits: get_attr(appkit::NSOpenGLPFAStencilSize)
                        as u8,
                    stereoscopy: get_attr(appkit::NSOpenGLPFAStereo) != 0,
                    double_buffer: get_attr(appkit::NSOpenGLPFADoubleBuffer)
                        != 0,
                    multisampling: if get_attr(appkit::NSOpenGLPFAMultisample)
                        > 0
                    {
                        Some(get_attr(appkit::NSOpenGLPFASamples) as u16)
                    } else {
                        None
                    },
                    srgb: true,
                }
            };

            gl_context.setView_(view);
            let value = if gl_attr.vsync { 1 } else { 0 };
            gl_context.setValues_forParameter_(
                &value,
                appkit::NSOpenGLContextParameter::NSOpenGLCPSwapInterval,
            );

            if transparent {
                let mut opacity = 0;
                CGLSetParameter(
                    gl_context.CGLContextObj() as *mut _,
                    kCGLCPSurfaceOpacity,
                    &mut opacity,
                );
            }

            CGLEnable(
                gl_context.CGLContextObj() as *mut _,
                kCGLCECrashOnRemovedFunctions,
            );

            let context = WindowedContext {
                context: gl_context,
                pixel_format: pixel_format,
            };
            Ok((win, Context::WindowedContext(context)))
        }
    }

    #[inline]
    pub fn new_headless<T>(
        _el: &EventLoopWindowTarget<T>,
        pf_reqs: &PixelFormatRequirements,
        gl_attr: &GlAttributes<&Context>,
        _size: dpi::PhysicalSize,
    ) -> Result<Self, CreationError> {
        let gl_profile = helpers::get_gl_profile(gl_attr, pf_reqs)?;
        let attributes = helpers::build_nsattributes(pf_reqs, gl_profile)?;
        let context = unsafe {
            let pixelformat = NSOpenGLPixelFormat::alloc(nil)
                .initWithAttributes_(&attributes);
            if pixelformat == nil {
                return Err(CreationError::OsError(
                    "Could not create the pixel format".to_string(),
                ));
            }
            let context = NSOpenGLContext::alloc(nil)
                .initWithFormat_shareContext_(pixelformat, nil);
            if context == nil {
                return Err(CreationError::OsError(
                    "Could not create the rendering context".to_string(),
                ));
            }

            IdRef::new(context)
        };

        let headless = HeadlessContext { context };

        Ok(Context::HeadlessContext(headless))
    }

    pub fn resize(&self, _width: u32, _height: u32) {
        match *self {
            Context::WindowedContext(ref c) => unsafe { c.context.update() },
            _ => unreachable!(),
        }
    }

    #[inline]
    pub unsafe fn make_current(&self) -> Result<(), ContextError> {
        match *self {
            Context::WindowedContext(ref c) => {
                let _: () = msg_send![*c.context, update];
                c.context.makeCurrentContext();
            }
            Context::HeadlessContext(ref c) => {
                let _: () = msg_send![*c.context, update];
                c.context.makeCurrentContext();
            }
        }
        Ok(())
    }

    #[inline]
    pub unsafe fn make_not_current(&self) -> Result<(), ContextError> {
        if self.is_current() {
            match *self {
                Context::WindowedContext(ref c) => {
                    let _: () = msg_send![*c.context, update];
                    NSOpenGLContext::clearCurrentContext(nil);
                }
                Context::HeadlessContext(ref c) => {
                    let _: () = msg_send![*c.context, update];
                    NSOpenGLContext::clearCurrentContext(nil);
                }
            }
        }
        Ok(())
    }

    #[inline]
    pub fn is_current(&self) -> bool {
        unsafe {
            let context = match *self {
                Context::WindowedContext(ref c) => *c.context,
                Context::HeadlessContext(ref c) => *c.context,
            };

            let pool = NSAutoreleasePool::new(nil);
            let current = NSOpenGLContext::currentContext(nil);
            let res = if current != nil {
                let is_equal: BOOL = msg_send![current, isEqual: context];
                is_equal != NO
            } else {
                false
            };
            let _: () = msg_send![pool, release];
            res
        }
    }

    pub fn get_proc_address(&self, addr: &str) -> *const core::ffi::c_void {
        let symbol_name: CFString = FromStr::from_str(addr).unwrap();
        let framework_name: CFString =
            FromStr::from_str("com.apple.opengl").unwrap();
        let framework = unsafe {
            CFBundleGetBundleWithIdentifier(
                framework_name.as_concrete_TypeRef(),
            )
        };
        let symbol = unsafe {
            CFBundleGetFunctionPointerForName(
                framework,
                symbol_name.as_concrete_TypeRef(),
            )
        };
        symbol as *const _
    }

    #[inline]
    pub fn swap_buffers(&self) -> Result<(), ContextError> {
        unsafe {
            match *self {
                Context::WindowedContext(ref c) => {
                    let pool = NSAutoreleasePool::new(nil);
                    c.context.flushBuffer();
                    let _: () = msg_send![pool, release];
                }
                Context::HeadlessContext(_) => unreachable!(),
            }
        }
        Ok(())
    }

    #[inline]
    pub fn swap_buffers_with_damage(
        &self,
        rects: &[Rect],
    ) -> Result<(), ContextError> {
        Err(ContextError::OsError("buffer damage not suported".to_string()))
    }

    #[inline]
    pub fn swap_buffers_with_damage_supported(&self) -> bool {
        false
    }

    #[inline]
    pub fn get_api(&self) -> crate::Api {
        crate::Api::OpenGl
    }

    #[inline]
    pub fn get_pixel_format(&self) -> PixelFormat {
        match *self {
            Context::WindowedContext(ref c) => c.pixel_format.clone(),
            Context::HeadlessContext(_) => unreachable!(),
        }
    }

    #[inline]
    pub unsafe fn raw_handle(&self) -> *mut raw::c_void {
        match *self {
            Context::WindowedContext(ref c) => *c.context.deref() as *mut _,
            Context::HeadlessContext(ref c) => *c.context.deref() as *mut _,
        }
    }

    #[inline]
    fn get_id(&self) -> IdRef {
        match self {
            Context::WindowedContext(w) => w.context.clone(),
            Context::HeadlessContext(h) => h.context.clone(),
        }
    }
}

#[derive(Debug)]
struct IdRef(id);

impl IdRef {
    fn new(i: id) -> IdRef {
        IdRef(i)
    }

    #[allow(dead_code)]
    fn retain(i: id) -> IdRef {
        if i != nil {
            let _: id = unsafe { msg_send![i, retain] };
        }
        IdRef(i)
    }

    fn non_nil(self) -> Option<IdRef> {
        if self.0 == nil {
            None
        } else {
            Some(self)
        }
    }
}

impl Drop for IdRef {
    fn drop(&mut self) {
        if self.0 != nil {
            let _: () = unsafe { msg_send![self.0, release] };
        }
    }
}

impl Deref for IdRef {
    type Target = id;
    fn deref<'a>(&'a self) -> &'a id {
        &self.0
    }
}

impl Clone for IdRef {
    fn clone(&self) -> IdRef {
        if self.0 != nil {
            let _: id = unsafe { msg_send![self.0, retain] };
        }
        IdRef(self.0)
    }
}

unsafe impl Send for Context {}
unsafe impl Sync for Context {}
<commit_msg>MacOSX's raw_handle trait method returns CGLContext object (#1221)<commit_after>#![cfg(target_os = "macos")]
use crate::{
    ContextError, CreationError, GlAttributes, PixelFormat,
    PixelFormatRequirements, Robustness, Rect,
};

use cgl::{
    kCGLCECrashOnRemovedFunctions, kCGLCPSurfaceOpacity, CGLEnable,
    CGLSetParameter,
};
use cocoa::appkit::{self, NSOpenGLContext, NSOpenGLPixelFormat};
use cocoa::base::{id, nil};
use cocoa::foundation::NSAutoreleasePool;
use core_foundation::base::TCFType;
use core_foundation::bundle::{
    CFBundleGetBundleWithIdentifier, CFBundleGetFunctionPointerForName,
};
use core_foundation::string::CFString;
use objc::runtime::{BOOL, NO};

use crate::platform::macos::WindowExtMacOS;
use winit;
use winit::dpi;
use winit::event_loop::EventLoopWindowTarget;
use winit::window::{Window, WindowBuilder};

use std::ops::Deref;
use std::os::raw;
use std::str::FromStr;

mod helpers;

#[derive(Debug)]
pub enum Context {
    WindowedContext(WindowedContext),
    HeadlessContext(HeadlessContext),
}

#[derive(Debug)]
pub struct WindowedContext {
    // NSOpenGLContext
    context: IdRef,
    pixel_format: PixelFormat,
}

#[derive(Debug)]
pub struct HeadlessContext {
    context: IdRef,
}

impl Context {
    #[inline]
    pub fn new_windowed<T>(
        wb: WindowBuilder,
        el: &EventLoopWindowTarget<T>,
        pf_reqs: &PixelFormatRequirements,
        gl_attr: &GlAttributes<&Context>,
    ) -> Result<(Window, Self), CreationError> {
        let transparent = wb.window.transparent;
        let win = wb.build(el)?;

        let share_ctx = gl_attr.sharing.map_or(nil, |c| *c.get_id());

        match gl_attr.robustness {
            Robustness::RobustNoResetNotification
            | Robustness::RobustLoseContextOnReset => {
                return Err(CreationError::RobustnessNotSupported);
            }
            _ => (),
        }

        let view = win.ns_view() as id;

        let gl_profile = helpers::get_gl_profile(gl_attr, pf_reqs)?;
        let attributes = helpers::build_nsattributes(pf_reqs, gl_profile)?;
        unsafe {
            let pixel_format = IdRef::new(
                NSOpenGLPixelFormat::alloc(nil)
                    .initWithAttributes_(&attributes),
            );
            let pixel_format = match pixel_format.non_nil() {
                None => return Err(CreationError::NoAvailablePixelFormat),
                Some(pf) => pf,
            };

            let gl_context = IdRef::new(
                NSOpenGLContext::alloc(nil)
                    .initWithFormat_shareContext_(*pixel_format, share_ctx),
            );
            let gl_context = match gl_context.non_nil() {
                Some(gl_context) => gl_context,
                None => {
                    return Err(CreationError::NotSupported(
                        "could not open gl context".to_string(),
                    ));
                }
            };

            let pixel_format = {
                let get_attr =
                    |attrib: appkit::NSOpenGLPixelFormatAttribute| -> i32 {
                        let mut value = 0;
                        NSOpenGLPixelFormat::getValues_forAttribute_forVirtualScreen_(
                        *pixel_format,
                        &mut value,
                        attrib,
                        NSOpenGLContext::currentVirtualScreen(*gl_context),
                    );
                        value
                    };

                PixelFormat {
                    hardware_accelerated: get_attr(
                        appkit::NSOpenGLPFAAccelerated,
                    ) != 0,
                    color_bits: (get_attr(appkit::NSOpenGLPFAColorSize)
                        - get_attr(appkit::NSOpenGLPFAAlphaSize))
                        as u8,
                    alpha_bits: get_attr(appkit::NSOpenGLPFAAlphaSize) as u8,
                    depth_bits: get_attr(appkit::NSOpenGLPFADepthSize) as u8,
                    stencil_bits: get_attr(appkit::NSOpenGLPFAStencilSize)
                        as u8,
                    stereoscopy: get_attr(appkit::NSOpenGLPFAStereo) != 0,
                    double_buffer: get_attr(appkit::NSOpenGLPFADoubleBuffer)
                        != 0,
                    multisampling: if get_attr(appkit::NSOpenGLPFAMultisample)
                        > 0
                    {
                        Some(get_attr(appkit::NSOpenGLPFASamples) as u16)
                    } else {
                        None
                    },
                    srgb: true,
                }
            };

            gl_context.setView_(view);
            let value = if gl_attr.vsync { 1 } else { 0 };
            gl_context.setValues_forParameter_(
                &value,
                appkit::NSOpenGLContextParameter::NSOpenGLCPSwapInterval,
            );

            if transparent {
                let mut opacity = 0;
                CGLSetParameter(
                    gl_context.CGLContextObj() as *mut _,
                    kCGLCPSurfaceOpacity,
                    &mut opacity,
                );
            }

            CGLEnable(
                gl_context.CGLContextObj() as *mut _,
                kCGLCECrashOnRemovedFunctions,
            );

            let context = WindowedContext {
                context: gl_context,
                pixel_format: pixel_format,
            };
            Ok((win, Context::WindowedContext(context)))
        }
    }

    #[inline]
    pub fn new_headless<T>(
        _el: &EventLoopWindowTarget<T>,
        pf_reqs: &PixelFormatRequirements,
        gl_attr: &GlAttributes<&Context>,
        _size: dpi::PhysicalSize,
    ) -> Result<Self, CreationError> {
        let gl_profile = helpers::get_gl_profile(gl_attr, pf_reqs)?;
        let attributes = helpers::build_nsattributes(pf_reqs, gl_profile)?;
        let context = unsafe {
            let pixelformat = NSOpenGLPixelFormat::alloc(nil)
                .initWithAttributes_(&attributes);
            if pixelformat == nil {
                return Err(CreationError::OsError(
                    "Could not create the pixel format".to_string(),
                ));
            }
            let context = NSOpenGLContext::alloc(nil)
                .initWithFormat_shareContext_(pixelformat, nil);
            if context == nil {
                return Err(CreationError::OsError(
                    "Could not create the rendering context".to_string(),
                ));
            }

            IdRef::new(context)
        };

        let headless = HeadlessContext { context };

        Ok(Context::HeadlessContext(headless))
    }

    pub fn resize(&self, _width: u32, _height: u32) {
        match *self {
            Context::WindowedContext(ref c) => unsafe { c.context.update() },
            _ => unreachable!(),
        }
    }

    #[inline]
    pub unsafe fn make_current(&self) -> Result<(), ContextError> {
        match *self {
            Context::WindowedContext(ref c) => {
                let _: () = msg_send![*c.context, update];
                c.context.makeCurrentContext();
            }
            Context::HeadlessContext(ref c) => {
                let _: () = msg_send![*c.context, update];
                c.context.makeCurrentContext();
            }
        }
        Ok(())
    }

    #[inline]
    pub unsafe fn make_not_current(&self) -> Result<(), ContextError> {
        if self.is_current() {
            match *self {
                Context::WindowedContext(ref c) => {
                    let _: () = msg_send![*c.context, update];
                    NSOpenGLContext::clearCurrentContext(nil);
                }
                Context::HeadlessContext(ref c) => {
                    let _: () = msg_send![*c.context, update];
                    NSOpenGLContext::clearCurrentContext(nil);
                }
            }
        }
        Ok(())
    }

    #[inline]
    pub fn is_current(&self) -> bool {
        unsafe {
            let context = match *self {
                Context::WindowedContext(ref c) => *c.context,
                Context::HeadlessContext(ref c) => *c.context,
            };

            let pool = NSAutoreleasePool::new(nil);
            let current = NSOpenGLContext::currentContext(nil);
            let res = if current != nil {
                let is_equal: BOOL = msg_send![current, isEqual: context];
                is_equal != NO
            } else {
                false
            };
            let _: () = msg_send![pool, release];
            res
        }
    }

    pub fn get_proc_address(&self, addr: &str) -> *const core::ffi::c_void {
        let symbol_name: CFString = FromStr::from_str(addr).unwrap();
        let framework_name: CFString =
            FromStr::from_str("com.apple.opengl").unwrap();
        let framework = unsafe {
            CFBundleGetBundleWithIdentifier(
                framework_name.as_concrete_TypeRef(),
            )
        };
        let symbol = unsafe {
            CFBundleGetFunctionPointerForName(
                framework,
                symbol_name.as_concrete_TypeRef(),
            )
        };
        symbol as *const _
    }

    #[inline]
    pub fn swap_buffers(&self) -> Result<(), ContextError> {
        unsafe {
            match *self {
                Context::WindowedContext(ref c) => {
                    let pool = NSAutoreleasePool::new(nil);
                    c.context.flushBuffer();
                    let _: () = msg_send![pool, release];
                }
                Context::HeadlessContext(_) => unreachable!(),
            }
        }
        Ok(())
    }

    #[inline]
    pub fn swap_buffers_with_damage(
        &self,
        rects: &[Rect],
    ) -> Result<(), ContextError> {
        Err(ContextError::OsError("buffer damage not suported".to_string()))
    }

    #[inline]
    pub fn swap_buffers_with_damage_supported(&self) -> bool {
        false
    }

    #[inline]
    pub fn get_api(&self) -> crate::Api {
        crate::Api::OpenGl
    }

    #[inline]
    pub fn get_pixel_format(&self) -> PixelFormat {
        match *self {
            Context::WindowedContext(ref c) => c.pixel_format.clone(),
            Context::HeadlessContext(_) => unreachable!(),
        }
    }

    #[inline]
    pub unsafe fn raw_handle(&self) -> *mut raw::c_void {
        match self {
            Context::WindowedContext(c) => {
                c.context.deref().CGLContextObj() as *mut _
            }
            Context::HeadlessContext(c) => {
                c.context.deref().CGLContextObj() as *mut _
            }
        }
    }

    #[inline]
    fn get_id(&self) -> IdRef {
        match self {
            Context::WindowedContext(w) => w.context.clone(),
            Context::HeadlessContext(h) => h.context.clone(),
        }
    }
}

#[derive(Debug)]
struct IdRef(id);

impl IdRef {
    fn new(i: id) -> IdRef {
        IdRef(i)
    }

    #[allow(dead_code)]
    fn retain(i: id) -> IdRef {
        if i != nil {
            let _: id = unsafe { msg_send![i, retain] };
        }
        IdRef(i)
    }

    fn non_nil(self) -> Option<IdRef> {
        if self.0 == nil {
            None
        } else {
            Some(self)
        }
    }
}

impl Drop for IdRef {
    fn drop(&mut self) {
        if self.0 != nil {
            let _: () = unsafe { msg_send![self.0, release] };
        }
    }
}

impl Deref for IdRef {
    type Target = id;
    fn deref<'a>(&'a self) -> &'a id {
        &self.0
    }
}

impl Clone for IdRef {
    fn clone(&self) -> IdRef {
        if self.0 != nil {
            let _: id = unsafe { msg_send![self.0, retain] };
        }
        IdRef(self.0)
    }
}

unsafe impl Send for Context {}
unsafe impl Sync for Context {}
<|endoftext|>


<commit_before>macro_rules! remove_overriden {
    (@remove $_self:ident, $v:ident, $a:ident.$ov:ident) => {
        if let Some(ref ora) = $a.$ov() {
            vec_remove_all!($_self.$v, ora);
        }
    };
    (@arg $_self:ident, $arg:ident) => {
        remove_overriden!(@remove $_self, required, $arg.requires);
        remove_overriden!(@remove $_self, blacklist, $arg.blacklist);
        remove_overriden!(@remove $_self, overrides, $arg.overrides);
    };
    ($_self:ident, $name:expr) => {
        debugln!("macro=remove_overriden!;");
        if let Some(ref o) = $_self.opts.iter().filter(|o| o.b.name == *$name).next() {
            remove_overriden!(@arg $_self, o);
        } else if let Some(ref f) = $_self.flags.iter().filter(|f| f.b.name == *$name).next() {
            remove_overriden!(@arg $_self, f);
        } else if let Some(p) = $_self.positionals.values().filter(|p| p.b.name == *$name).next() {
            remove_overriden!(@arg $_self, p);
        }
    };
}

macro_rules! arg_post_processing {
    ($me:ident, $arg:ident, $matcher:ident) => {
        debugln!("macro=arg_post_processing!;");
        // Handle POSIX overrides
        debug!("Is '{}' in overrides...", $arg.to_string());
        if $me.overrides.contains(&$arg.name()) {
            if let Some(ref name) = find_name_from!($me, &$arg.name(), overrides, $matcher) {
                sdebugln!("Yes by {}", name);
                $matcher.remove(name);
                remove_overriden!($me, name);
            }
        } else { sdebugln!("No"); }

        // Add overrides
        debug!("Does '{}' have overrides...", $arg.to_string());
        if let Some(or) = $arg.overrides() {
            sdebugln!("Yes");
            $matcher.remove_all(or);
            for pa in or { remove_overriden!($me, pa); }
            $me.overrides.extend(or);
            vec_remove_all!($me.required, or);
        } else { sdebugln!("No"); }

        // Handle conflicts
        debug!("Does '{}' have conflicts...", $arg.to_string());
        if let Some(bl) = $arg.blacklist() {
            sdebugln!("Yes");

            for c in bl {
                // Inject two-way conflicts
                debug!("Has '{}' already been matched...", c);
                if $matcher.contains(c) {
                    sdebugln!("Yes");
                    // find who blacklisted us...
                    $me.blacklist.push(&$arg.b.name);
                } else {
                    sdebugln!("No");
                }
            }

            $me.blacklist.extend(bl);
            vec_remove_all!($me.overrides, bl);
            vec_remove_all!($me.required, bl);
        } else { sdebugln!("No"); }

        // Add all required args which aren't already found in matcher to the master
        // list
        debug!("Does '{}' have requirements...", $arg.to_string());
        if let Some(reqs) = $arg.requires() {
            for n in reqs {
                if $matcher.contains(&n) {
                    sdebugln!("\tYes '{}' but it's already met", n);
                    continue;
                } else { sdebugln!("\tYes '{}'", n); }

                $me.required.push(n);
            }
        } else { sdebugln!("No"); }

        _handle_group_reqs!($me, $arg);
    };
}

macro_rules! _handle_group_reqs{
    ($me:ident, $arg:ident) => ({
        use args::AnyArg;
        debugln!("macro=_handle_group_reqs!;");
        for grp in $me.groups.values() {
            let found = if grp.args.contains(&$arg.name()) {
                vec_remove!($me.required, &$arg.name());
                if let Some(ref reqs) = grp.requires {
                    $me.required.extend(reqs);
                }
                if let Some(ref bl) = grp.conflicts {
                    $me.blacklist.extend(bl);
                }
                true // What if arg is in more than one group with different reqs?
            } else {
                false
            };
            debugln!("iter;grp={};found={:?}", grp.name, found);
            if found {
                vec_remove_all!($me.required, &grp.args);
                debugln!("Adding args from group to blacklist...{:?}", grp.args);
                if !grp.multiple {
                    $me.blacklist.extend(&grp.args);
                    vec_remove!($me.blacklist, &$arg.name());
                }
            }
        }
    })
}

macro_rules! validate_multiples {
    ($_self:ident, $a:ident, $m:ident) => {
        debugln!("macro=validate_multiples!;");
        if $m.contains(&$a.b.name) && !$a.b.settings.is_set(ArgSettings::Multiple) {
            // Not the first time, and we don't allow multiples
            return Err(Error::unexpected_multiple_usage($a,
                &*$_self.create_current_usage($m),
                $_self.color()))
        }
    };
}

macro_rules! parse_positional {
    (
        $_self:ident,
        $p:ident,
        $arg_os:ident,
        $pos_counter:ident,
        $matcher:ident
    ) => {
        debugln!("macro=parse_positional!;");
        validate_multiples!($_self, $p, $matcher);

        if !$_self.trailing_vals &&
           ($_self.settings.is_set(AppSettings::TrailingVarArg) &&
            $pos_counter == $_self.positionals.len()) {
            $_self.trailing_vals = true;
        }
        try!($_self.add_val_to_arg($p, &$arg_os, $matcher));

        $matcher.inc_occurrence_of($p.b.name);
        let _ = $_self.groups_for_arg($p.b.name)
                      .and_then(|vec| Some($matcher.inc_occurrences_of(&*vec)));
        arg_post_processing!($_self, $p, $matcher);
        // Only increment the positional counter if it doesn't allow multiples
        if !$p.b.settings.is_set(ArgSettings::Multiple) {
            $pos_counter += 1;
        }
    };
}

macro_rules! find_from {
    ($_self:ident, $arg_name:expr, $from:ident, $matcher:expr) => {{
        let mut ret = None;
        for k in $matcher.arg_names() {
            if let Some(f) = find_by_name!($_self, &k, flags, iter) {
                if let Some(ref v) = f.$from() {
                    if v.contains($arg_name) {
                        ret = Some(f.to_string());
                    }
                }
            }
            if let Some(o) = find_by_name!($_self, &k, opts, iter) {
                if let Some(ref v) = o.$from() {
                    if v.contains(&$arg_name) {
                        ret = Some(o.to_string());
                    }
                }
            }
            if let Some(pos) = find_by_name!($_self, &k, positionals, values) {
                if let Some(ref v) = pos.$from() {
                    if v.contains($arg_name) {
                        ret = Some(pos.b.name.to_owned());
                    }
                }
            }
        }
        ret
    }};
}

macro_rules! find_name_from {
    ($_self:ident, $arg_name:expr, $from:ident, $matcher:expr) => {{
        let mut ret = None;
        for k in $matcher.arg_names() {
            if let Some(f) = find_by_name!($_self, &k, flags, iter) {
                if let Some(ref v) = f.$from() {
                    if v.contains($arg_name) {
                        ret = Some(f.b.name);
                    }
                }
            }
            if let Some(o) = find_by_name!($_self, &k, opts, iter) {
                if let Some(ref v) = o.$from() {
                    if v.contains(&$arg_name) {
                        ret = Some(o.b.name);
                    }
                }
            }
            if let Some(pos) = find_by_name!($_self, &k, positionals, values) {
                if let Some(ref v) = pos.$from() {
                    if v.contains($arg_name) {
                        ret = Some(pos.b.name);
                    }
                }
            }
        }
        ret
    }};
}

// Finds an arg by name
macro_rules! find_by_name {
    ($_self:ident, $name:expr, $what:ident, $how:ident) => {
        $_self.$what.$how().find(|o| &o.b.name == $name)
    }
}

// Finds an option including if it's aliasesed
macro_rules! find_by_long {
    ($_self:ident, $long:expr, $what:ident) => {
        $_self.$what
            .iter()
            .filter(|o| o.s.long.is_some())
            .find(|o| {
                &&o.s.long.unwrap() == &$long ||
                (o.s.aliases.is_some() &&
                 o.s
                    .aliases
                    .as_ref()
                    .unwrap()
                    .iter()
                    .any(|&(alias, _)| &&alias == &$long))
            })
    }
}
<commit_msg>chore: fixes build failure for 1.11.0<commit_after>macro_rules! remove_overriden {
    (@remove $_self:ident, $v:ident, $a:ident.$ov:ident) => {
        if let Some(ref ora) = $a.$ov() {
            vec_remove_all!($_self.$v, ora);
        }
    };
    (@arg $_self:ident, $arg:ident) => {
        remove_overriden!(@remove $_self, required, $arg.requires);
        remove_overriden!(@remove $_self, blacklist, $arg.blacklist);
        remove_overriden!(@remove $_self, overrides, $arg.overrides);
    };
    ($_self:ident, $name:expr) => {
        debugln!("macro=remove_overriden!;");
        if let Some(ref o) = $_self.opts.iter().filter(|o| o.b.name == *$name).next() {
            remove_overriden!(@arg $_self, o);
        } else if let Some(ref f) = $_self.flags.iter().filter(|f| f.b.name == *$name).next() {
            remove_overriden!(@arg $_self, f);
        } else if let Some(p) = $_self.positionals.values().filter(|p| p.b.name == *$name).next() {
            remove_overriden!(@arg $_self, p);
        }
    };
}

macro_rules! arg_post_processing {
    ($me:ident, $arg:ident, $matcher:ident) => {
        debugln!("macro=arg_post_processing!;");
        // Handle POSIX overrides
        debug!("Is '{}' in overrides...", $arg.to_string());
        if $me.overrides.contains(&$arg.name()) {
            if let Some(ref name) = find_name_from!($me, &$arg.name(), overrides, $matcher) {
                sdebugln!("Yes by {}", name);
                $matcher.remove(name);
                remove_overriden!($me, name);
            }
        } else { sdebugln!("No"); }

        // Add overrides
        debug!("Does '{}' have overrides...", $arg.to_string());
        if let Some(or) = $arg.overrides() {
            sdebugln!("Yes");
            $matcher.remove_all(or);
            for pa in or { remove_overriden!($me, pa); }
            $me.overrides.extend(or);
            vec_remove_all!($me.required, or);
        } else { sdebugln!("No"); }

        // Handle conflicts
        debug!("Does '{}' have conflicts...", $arg.to_string());
        if let Some(bl) = $arg.blacklist() {
            sdebugln!("Yes");

            for c in bl {
                // Inject two-way conflicts
                debug!("Has '{}' already been matched...", c);
                if $matcher.contains(c) {
                    sdebugln!("Yes");
                    // find who blacklisted us...
                    $me.blacklist.push(&$arg.b.name);
                } else {
                    sdebugln!("No");
                }
            }

            $me.blacklist.extend(bl);
            vec_remove_all!($me.overrides, bl);
            vec_remove_all!($me.required, bl);
        } else { sdebugln!("No"); }

        // Add all required args which aren't already found in matcher to the master
        // list
        debug!("Does '{}' have requirements...", $arg.to_string());
        if let Some(reqs) = $arg.requires() {
            for n in reqs {
                if $matcher.contains(&n) {
                    sdebugln!("\tYes '{}' but it's already met", n);
                    continue;
                } else { sdebugln!("\tYes '{}'", n); }

                $me.required.push(n);
            }
        } else { sdebugln!("No"); }

        _handle_group_reqs!($me, $arg);
    };
}

macro_rules! _handle_group_reqs{
    ($me:ident, $arg:ident) => ({
        use args::AnyArg;
        debugln!("macro=_handle_group_reqs!;");
        for grp in $me.groups.values() {
            let found = if grp.args.contains(&$arg.name()) {
                vec_remove!($me.required, &$arg.name());
                if let Some(ref reqs) = grp.requires {
                    $me.required.extend(reqs);
                }
                if let Some(ref bl) = grp.conflicts {
                    $me.blacklist.extend(bl);
                }
                true // What if arg is in more than one group with different reqs?
            } else {
                false
            };
            debugln!("iter;grp={};found={:?}", grp.name, found);
            if found {
                vec_remove_all!($me.required, &grp.args);
                debugln!("Adding args from group to blacklist...{:?}", grp.args);
                if !grp.multiple {
                    $me.blacklist.extend(&grp.args);
                    vec_remove!($me.blacklist, &$arg.name());
                }
            }
        }
    })
}

macro_rules! validate_multiples {
    ($_self:ident, $a:ident, $m:ident) => {
        debugln!("macro=validate_multiples!;");
        if $m.contains(&$a.b.name) && !$a.b.settings.is_set(ArgSettings::Multiple) {
            // Not the first time, and we don't allow multiples
            return Err(Error::unexpected_multiple_usage($a,
                &*$_self.create_current_usage($m),
                $_self.color()))
        }
    };
}

macro_rules! parse_positional {
    (
        $_self:ident,
        $p:ident,
        $arg_os:ident,
        $pos_counter:ident,
        $matcher:ident
    ) => {
        debugln!("macro=parse_positional!;");
        validate_multiples!($_self, $p, $matcher);

        if !$_self.trailing_vals &&
           ($_self.settings.is_set(AppSettings::TrailingVarArg) &&
            $pos_counter == $_self.positionals.len()) {
            $_self.trailing_vals = true;
        }
        let _ = try!($_self.add_val_to_arg($p, &$arg_os, $matcher));

        $matcher.inc_occurrence_of($p.b.name);
        let _ = $_self.groups_for_arg($p.b.name)
                      .and_then(|vec| Some($matcher.inc_occurrences_of(&*vec)));
        arg_post_processing!($_self, $p, $matcher);
        // Only increment the positional counter if it doesn't allow multiples
        if !$p.b.settings.is_set(ArgSettings::Multiple) {
            $pos_counter += 1;
        }
    };
}

macro_rules! find_from {
    ($_self:ident, $arg_name:expr, $from:ident, $matcher:expr) => {{
        let mut ret = None;
        for k in $matcher.arg_names() {
            if let Some(f) = find_by_name!($_self, &k, flags, iter) {
                if let Some(ref v) = f.$from() {
                    if v.contains($arg_name) {
                        ret = Some(f.to_string());
                    }
                }
            }
            if let Some(o) = find_by_name!($_self, &k, opts, iter) {
                if let Some(ref v) = o.$from() {
                    if v.contains(&$arg_name) {
                        ret = Some(o.to_string());
                    }
                }
            }
            if let Some(pos) = find_by_name!($_self, &k, positionals, values) {
                if let Some(ref v) = pos.$from() {
                    if v.contains($arg_name) {
                        ret = Some(pos.b.name.to_owned());
                    }
                }
            }
        }
        ret
    }};
}

macro_rules! find_name_from {
    ($_self:ident, $arg_name:expr, $from:ident, $matcher:expr) => {{
        let mut ret = None;
        for k in $matcher.arg_names() {
            if let Some(f) = find_by_name!($_self, &k, flags, iter) {
                if let Some(ref v) = f.$from() {
                    if v.contains($arg_name) {
                        ret = Some(f.b.name);
                    }
                }
            }
            if let Some(o) = find_by_name!($_self, &k, opts, iter) {
                if let Some(ref v) = o.$from() {
                    if v.contains(&$arg_name) {
                        ret = Some(o.b.name);
                    }
                }
            }
            if let Some(pos) = find_by_name!($_self, &k, positionals, values) {
                if let Some(ref v) = pos.$from() {
                    if v.contains($arg_name) {
                        ret = Some(pos.b.name);
                    }
                }
            }
        }
        ret
    }};
}

// Finds an arg by name
macro_rules! find_by_name {
    ($_self:ident, $name:expr, $what:ident, $how:ident) => {
        $_self.$what.$how().find(|o| &o.b.name == $name)
    }
}

// Finds an option including if it's aliasesed
macro_rules! find_by_long {
    ($_self:ident, $long:expr, $what:ident) => {
        $_self.$what
            .iter()
            .filter(|o| o.s.long.is_some())
            .find(|o| {
                &&o.s.long.unwrap() == &$long ||
                (o.s.aliases.is_some() &&
                 o.s
                    .aliases
                    .as_ref()
                    .unwrap()
                    .iter()
                    .any(|&(alias, _)| &&alias == &$long))
            })
    }
}
<|endoftext|>


<commit_before>/*
    Copyright 2017 Andrew Medworth <github@medworth.org.uk>

    This file is part of Dots-and-Boxes Engine.

    Dots-and-Boxes Engine is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Dots-and-Boxes Engine is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with Dots-and-Boxes Engine.  If not, see <http://www.gnu.org/licenses/>.
*/

use game::{Move, Position, Side};
use nimstring;
use std::io::{self, BufRead};
use std::fs::File;
use regex::{Regex, Captures};

#[derive(PartialEq)]
#[derive(Debug)]
enum Command {
    MakeMove(Move),
    UndoMove(Move),
    CalcNimstringValue,
    PrintHelp,
    Quit,
}

impl Command {
    fn execute(self: &Command, pos: &mut Position) {
        match self {
            &Command::MakeMove(m) => {
                if pos.is_legal_move(m.x, m.y, m.side) {
                    pos.make_move(m.x, m.y, m.side);
                }
                else {
                    println!("Not a legal move: {}", m);
                }
            },
            &Command::UndoMove(m) => { pos.undo_move(m.x, m.y, m.side); },
            &Command::CalcNimstringValue => {
                let (val, per_move) = nimstring::calc_value_with_moves(pos);
                println!("Position value is {}", val);
                let mut moves: Vec<&Move> = per_move.keys().collect();
                moves.sort_by(|a, b| a.y.cmp(&b.y).then(a.x.cmp(&b.x)).then(a.side.cmp(&b.side)));
                for &m in &moves {
                    println!("{} {}", m, per_move.get(m).unwrap());
                }
            },
            &Command::PrintHelp => { print_help(); },
            &Command::Quit => { println!("Bye bye!"); },
        }
    }
}

fn print_help() {
    println!("Available commands:");
    println!("x y t/l/b/r - make move (x,y) top/left/bottom/right");
    println!("u x y t/l/b/r - undo move (x,y) top/left/bottom/right");
    println!("nv - calculate Nimstring value of current position");
    println!("help - print this help message");
    println!("quit/exit - exit program");
}

fn parse_side(side_s: &str) -> Option<Side> {
    if side_s == "l" || side_s == "left" { Some(Side::Left) }
    else if side_s == "r" || side_s == "right" { Some(Side::Right) }
    else if side_s == "t" || side_s == "top" { Some(Side::Top) }
    else if side_s == "b" || side_s == "bottom" { Some(Side::Bottom) }
    else { None }
}

fn parse_move(caps: Captures) -> Result<Move, String> {
    let x = caps[1].parse::<usize>().unwrap();
    let y = caps[2].parse::<usize>().unwrap();
    let side_s = caps[3].to_string();
    match parse_side(&side_s) {
        Some(side) => Ok(Move{x: x, y: y, side: side}),
        None => Err(format!("Unrecognised side: [{}]", side_s))
    }
}

fn parse_command(input: &str) -> Result<Command, String> {
    let input = input.to_lowercase();
    let move_re = Regex::new(r"^(\d+) (\d+) ([a-zA-Z]+)$").unwrap();
    if let Some(caps) = move_re.captures(&input) {
        match parse_move(caps) {
            Ok(m) => return Ok(Command::MakeMove(m)),
            Err(e) => return Err(format!("Cannot extract move from [{}]: {}", input, e))
        }
    }
    let undo_move_re = Regex::new(r"^[uU] (\d+) (\d+) ([a-zA-Z]+)$").unwrap();
    if let Some(caps) = undo_move_re.captures(&input) {
        match parse_move(caps) {
            Ok(m) => return Ok(Command::UndoMove(m)),
            Err(e) => return Err(format!("Cannot extract move from [{}]: {}", input, e))
        }
    }
    if "nv" == input {
        return Ok(Command::CalcNimstringValue);
    }
    if "help" == input {
        return Ok(Command::PrintHelp);
    }
    if "exit" == input || "quit" == input {
        return Ok(Command::Quit);
    }
    Err("Unsupported command".to_string())
}

fn get_next_command() -> Command {
    loop {
        let mut input = String::new();
        if let Err(error) = io::stdin().read_line(&mut input) {
            println!("Error reading from standard input: {}", error);
            continue;
        }
        let input = input.trim();
        match parse_command(&input) {
            Ok(command) => return command,
            Err(error) => {
                println!("Cannot execute [{}]: {}", input, error);
                println!("For help, try 'help'");
            }
        }
    }
}

fn main_loop_from(pos: &mut Position) {
    loop {
        println!("{}", pos);
        let command = get_next_command();
        command.execute(pos);
        if command == Command::Quit {
            break;
        }
        println!();
    }
}

// Enter the main loop of the CLI from the start of the game
pub fn main_loop_start(width: usize, height: usize) {
    main_loop_from(&mut Position::new_game(width, height));
}

// Execute a given file of commands (which must have the dimensions of the position on the first line)
// and then enter the CLI main loop.
pub fn main_loop_file(filename: &str) {
    let f = File::open(filename).expect(&format!("Could not open file [{}]", filename));
    let reader = io::BufReader::new(f);
    let mut lines = reader.lines();
    let size_spec = lines.next().expect("Empty file").expect("Could not read board size from first line");
    let size_re = Regex::new(r"^(\d+) (\d+)$").unwrap();
    let size_caps = size_re.captures(&size_spec).expect(&format!("Could not read board size from [{}]", size_spec));
    let width = size_caps[1].parse::<usize>().unwrap();
    let height = size_caps[2].parse::<usize>().unwrap();
    let mut pos = Position::new_game(width, height);
    for line in lines {
        let line = line.expect("Could not read line from file");
        match parse_command(&line) {
            Ok(command) => command.execute(&mut pos),
            Err(error) => panic!("Cannot execute [{}]: {}", line, error),
        }
    }
    main_loop_from(&mut pos);
}

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

    #[test]
    fn parse_make_move_cmd() {
        assert_eq!(Command::MakeMove(Move{x: 3, y: 5, side: Side::Bottom}), parse_command("3 5 b").unwrap());
        assert_eq!(Command::MakeMove(Move{x: 3, y: 5, side: Side::Bottom}), parse_command("3 5 Bottom").unwrap());
    }

    #[test]
    fn parse_undo_move_cmd() {
        assert_eq!(Command::UndoMove(Move{x: 8, y: 6, side: Side::Left}), parse_command("u 8 6 l").unwrap());
        assert_eq!(Command::UndoMove(Move{x: 8, y: 6, side: Side::Left}), parse_command("u 8 6 Left").unwrap());
    }

    #[test]
    fn parse_nimstring_value_cmd() {
        assert_eq!(Command::CalcNimstringValue, parse_command("nv").unwrap());
    }

    #[test]
    fn parse_help_cmd() {
        assert_eq!(Command::PrintHelp, parse_command("help").unwrap());
    }

    #[test]
    fn parse_exit_cmd() {
        assert_eq!(Command::Quit, parse_command("quit").unwrap());
        assert_eq!(Command::Quit, parse_command("exit").unwrap());
    }
}
<commit_msg>Ignore blank lines in command files<commit_after>/*
    Copyright 2017 Andrew Medworth <github@medworth.org.uk>

    This file is part of Dots-and-Boxes Engine.

    Dots-and-Boxes Engine is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Dots-and-Boxes Engine is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with Dots-and-Boxes Engine.  If not, see <http://www.gnu.org/licenses/>.
*/

use game::{Move, Position, Side};
use nimstring;
use std::io::{self, BufRead};
use std::fs::File;
use regex::{Regex, Captures};

#[derive(PartialEq)]
#[derive(Debug)]
enum Command {
    MakeMove(Move),
    UndoMove(Move),
    CalcNimstringValue,
    PrintHelp,
    Quit,
}

impl Command {
    fn execute(self: &Command, pos: &mut Position) {
        match self {
            &Command::MakeMove(m) => {
                if pos.is_legal_move(m.x, m.y, m.side) {
                    pos.make_move(m.x, m.y, m.side);
                }
                else {
                    println!("Not a legal move: {}", m);
                }
            },
            &Command::UndoMove(m) => { pos.undo_move(m.x, m.y, m.side); },
            &Command::CalcNimstringValue => {
                let (val, per_move) = nimstring::calc_value_with_moves(pos);
                println!("Position value is {}", val);
                let mut moves: Vec<&Move> = per_move.keys().collect();
                moves.sort_by(|a, b| a.y.cmp(&b.y).then(a.x.cmp(&b.x)).then(a.side.cmp(&b.side)));
                for &m in &moves {
                    println!("{} {}", m, per_move.get(m).unwrap());
                }
            },
            &Command::PrintHelp => { print_help(); },
            &Command::Quit => { println!("Bye bye!"); },
        }
    }
}

fn print_help() {
    println!("Available commands:");
    println!("x y t/l/b/r - make move (x,y) top/left/bottom/right");
    println!("u x y t/l/b/r - undo move (x,y) top/left/bottom/right");
    println!("nv - calculate Nimstring value of current position");
    println!("help - print this help message");
    println!("quit/exit - exit program");
}

fn parse_side(side_s: &str) -> Option<Side> {
    if side_s == "l" || side_s == "left" { Some(Side::Left) }
    else if side_s == "r" || side_s == "right" { Some(Side::Right) }
    else if side_s == "t" || side_s == "top" { Some(Side::Top) }
    else if side_s == "b" || side_s == "bottom" { Some(Side::Bottom) }
    else { None }
}

fn parse_move(caps: Captures) -> Result<Move, String> {
    let x = caps[1].parse::<usize>().unwrap();
    let y = caps[2].parse::<usize>().unwrap();
    let side_s = caps[3].to_string();
    match parse_side(&side_s) {
        Some(side) => Ok(Move{x: x, y: y, side: side}),
        None => Err(format!("Unrecognised side: [{}]", side_s))
    }
}

fn parse_command(input: &str) -> Result<Command, String> {
    let input = input.to_lowercase();
    let move_re = Regex::new(r"^(\d+) (\d+) ([a-zA-Z]+)$").unwrap();
    if let Some(caps) = move_re.captures(&input) {
        match parse_move(caps) {
            Ok(m) => return Ok(Command::MakeMove(m)),
            Err(e) => return Err(format!("Cannot extract move from [{}]: {}", input, e))
        }
    }
    let undo_move_re = Regex::new(r"^[uU] (\d+) (\d+) ([a-zA-Z]+)$").unwrap();
    if let Some(caps) = undo_move_re.captures(&input) {
        match parse_move(caps) {
            Ok(m) => return Ok(Command::UndoMove(m)),
            Err(e) => return Err(format!("Cannot extract move from [{}]: {}", input, e))
        }
    }
    if "nv" == input {
        return Ok(Command::CalcNimstringValue);
    }
    if "help" == input {
        return Ok(Command::PrintHelp);
    }
    if "exit" == input || "quit" == input {
        return Ok(Command::Quit);
    }
    Err("Unsupported command".to_string())
}

fn get_next_command() -> Command {
    loop {
        let mut input = String::new();
        if let Err(error) = io::stdin().read_line(&mut input) {
            println!("Error reading from standard input: {}", error);
            continue;
        }
        let input = input.trim();
        match parse_command(&input) {
            Ok(command) => return command,
            Err(error) => {
                println!("Cannot execute [{}]: {}", input, error);
                println!("For help, try 'help'");
            }
        }
    }
}

fn main_loop_from(pos: &mut Position) {
    loop {
        println!("{}", pos);
        let command = get_next_command();
        command.execute(pos);
        if command == Command::Quit {
            break;
        }
        println!();
    }
}

// Enter the main loop of the CLI from the start of the game
pub fn main_loop_start(width: usize, height: usize) {
    main_loop_from(&mut Position::new_game(width, height));
}

// Execute a given file of commands (which must have the dimensions of the position on the first line)
// and then enter the CLI main loop.
pub fn main_loop_file(filename: &str) {
    let f = File::open(filename).expect(&format!("Could not open file [{}]", filename));
    let reader = io::BufReader::new(f);
    let mut lines = reader.lines();
    let size_spec = lines.next().expect("Empty file").expect("Could not read board size from first line");
    let size_re = Regex::new(r"^(\d+) (\d+)$").unwrap();
    let size_caps = size_re.captures(&size_spec).expect(&format!("Could not read board size from [{}]", size_spec));
    let width = size_caps[1].parse::<usize>().unwrap();
    let height = size_caps[2].parse::<usize>().unwrap();
    let mut pos = Position::new_game(width, height);
    for line in lines {
        let line = line.expect("Could not read line from file");
        if line.trim().len() == 0 {
            continue;
        }
        match parse_command(&line) {
            Ok(command) => command.execute(&mut pos),
            Err(error) => panic!("Cannot execute [{}]: {}", line, error),
        }
    }
    main_loop_from(&mut pos);
}

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

    #[test]
    fn parse_make_move_cmd() {
        assert_eq!(Command::MakeMove(Move{x: 3, y: 5, side: Side::Bottom}), parse_command("3 5 b").unwrap());
        assert_eq!(Command::MakeMove(Move{x: 3, y: 5, side: Side::Bottom}), parse_command("3 5 Bottom").unwrap());
    }

    #[test]
    fn parse_undo_move_cmd() {
        assert_eq!(Command::UndoMove(Move{x: 8, y: 6, side: Side::Left}), parse_command("u 8 6 l").unwrap());
        assert_eq!(Command::UndoMove(Move{x: 8, y: 6, side: Side::Left}), parse_command("u 8 6 Left").unwrap());
    }

    #[test]
    fn parse_nimstring_value_cmd() {
        assert_eq!(Command::CalcNimstringValue, parse_command("nv").unwrap());
    }

    #[test]
    fn parse_help_cmd() {
        assert_eq!(Command::PrintHelp, parse_command("help").unwrap());
    }

    #[test]
    fn parse_exit_cmd() {
        assert_eq!(Command::Quit, parse_command("quit").unwrap());
        assert_eq!(Command::Quit, parse_command("exit").unwrap());
    }
}
<|endoftext|>


<commit_before>#[cfg(feature = "readline")]
extern crate readline;
extern crate lambed;

#[cfg(feature = "readline")]
use std::ffi::CString;

#[cfg(feature = "readline")]
fn main() {
    let prompt = CString::new("> ").unwrap();
    while let Ok(s) = readline::readline(&prompt) {
        let bytes = s.to_bytes();
        let string = String::from_utf8_lossy(bytes).into_owned().to_string();
        match lambed::parser::parse_string(&string) {
            Err(err) => println!("{:?}", err),
            Ok((term, _)) => {
                let mut context = lambed::eval::Context::new();
                let result = lambed::eval::eval(&mut context, term);
                match result {
                    Ok(term) => println!("{:?}", term),
                    Err(err) => println!("{:?}", err)
                }
            }
        }
    }
}
<commit_msg>print parsed term in repl<commit_after>#[cfg(feature = "readline")]
extern crate readline;
extern crate lambed;

#[cfg(feature = "readline")]
use std::ffi::CString;

#[cfg(feature = "readline")]
fn main() {
    let prompt = CString::new("> ").unwrap();
    while let Ok(s) = readline::readline(&prompt) {
        let bytes = s.to_bytes();
        let string = String::from_utf8_lossy(bytes).into_owned().to_string();
        match lambed::parser::parse_string(&string) {
            Err(err) => println!("{:?}", err),
            Ok((term, _)) => {
                println!("{:?}", term);
                let mut context = lambed::eval::Context::new();
                let result = lambed::eval::eval(&mut context, term);
                match result {
                    Ok(term) => println!("{:?}", term),
                    Err(err) => println!("{:?}", err)
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::fmt;

use bytes::{Buf, Bytes};

/// A piece of a message body.
///
/// These are returned by [`Body`](::Body). It is an efficient buffer type.
///
/// A `Chunk` can be easily created by many of Rust's standard types that
/// represent a collection of bytes, using `Chunk::from`.
pub struct Chunk {
    /// The buffer of bytes making up this body.
    bytes: Bytes,
}

// An unexported type to prevent locking `Chunk::into_iter()` to `Bytes::into_iter()`.
#[derive(Debug)]
pub struct IntoIter {
    inner: <Bytes as IntoIterator>::IntoIter,
}

impl Chunk {
    /// Converts this `Chunk` directly into the `Bytes` type without copies.
    ///
    /// This is simply an inherent alias for `Bytes::from(chunk)`, which exists,
    /// but doesn't appear in rustdocs.
    #[inline]
    pub fn into_bytes(self) -> Bytes {
        self.into()
    }
}

impl Buf for Chunk {
    #[inline]
    fn remaining(&self) -> usize {
        self.bytes.len()
    }

    #[inline]
    fn bytes(&self) -> &[u8] {
        &self.bytes
    }

    #[inline]
    fn advance(&mut self, cnt: usize) {
        self.bytes.advance(cnt);
    }
}

impl From<Vec<u8>> for Chunk {
    #[inline]
    fn from(v: Vec<u8>) -> Chunk {
        Chunk::from(Bytes::from(v))
    }
}

impl From<&'static [u8]> for Chunk {
    #[inline]
    fn from(slice: &'static [u8]) -> Chunk {
        Chunk::from(Bytes::from_static(slice))
    }
}

impl From<String> for Chunk {
    #[inline]
    fn from(s: String) -> Chunk {
        s.into_bytes().into()
    }
}

impl From<&'static str> for Chunk {
    #[inline]
    fn from(slice: &'static str) -> Chunk {
        slice.as_bytes().into()
    }
}

impl From<Bytes> for Chunk {
    #[inline]
    fn from(bytes: Bytes) -> Chunk {
        Chunk {
            bytes: bytes,
        }
    }
}

impl From<Chunk> for Bytes {
    #[inline]
    fn from(chunk: Chunk) -> Bytes {
        chunk.bytes
    }
}

impl ::std::ops::Deref for Chunk {
    type Target = [u8];

    #[inline]
    fn deref(&self) -> &Self::Target {
        self.as_ref()
    }
}

impl AsRef<[u8]> for Chunk {
    #[inline]
    fn as_ref(&self) -> &[u8] {
        &self.bytes
    }
}

impl fmt::Debug for Chunk {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(self.as_ref(), f)
    }
}

impl Default for Chunk {
    #[inline]
    fn default() -> Chunk {
        Chunk::from(Bytes::new())
    }
}

impl IntoIterator for Chunk {
    type Item = u8;
    type IntoIter = IntoIter;

    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        IntoIter {
            inner: self.bytes.into_iter(),
        }
    }
}

impl Extend<u8> for Chunk {
    #[inline]
    fn extend<T>(&mut self, iter: T) where T: IntoIterator<Item=u8> {
        self.bytes.extend(iter)
    }
}

impl Iterator for IntoIter {
    type Item = u8;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.inner.next()
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.inner.size_hint()
    }
}

impl ExactSizeIterator for IntoIter {}

<commit_msg>perf(chunk): use faster length check in Chunk::remaining<commit_after>use std::fmt;

use bytes::{Buf, Bytes};

/// A piece of a message body.
///
/// These are returned by [`Body`](::Body). It is an efficient buffer type.
///
/// A `Chunk` can be easily created by many of Rust's standard types that
/// represent a collection of bytes, using `Chunk::from`.
pub struct Chunk {
    /// The buffer of bytes making up this body.
    bytes: Bytes,
}

// An unexported type to prevent locking `Chunk::into_iter()` to `Bytes::into_iter()`.
#[derive(Debug)]
pub struct IntoIter {
    inner: <Bytes as IntoIterator>::IntoIter,
}

impl Chunk {
    /// Converts this `Chunk` directly into the `Bytes` type without copies.
    ///
    /// This is simply an inherent alias for `Bytes::from(chunk)`, which exists,
    /// but doesn't appear in rustdocs.
    #[inline]
    pub fn into_bytes(self) -> Bytes {
        self.into()
    }
}

impl Buf for Chunk {
    #[inline]
    fn remaining(&self) -> usize {
        //perf: Bytes::len() isn't inline yet,
        //so it's slightly slower than checking
        //the length of the slice.
        self.bytes().len()
    }

    #[inline]
    fn bytes(&self) -> &[u8] {
        &self.bytes
    }

    #[inline]
    fn advance(&mut self, cnt: usize) {
        self.bytes.advance(cnt);
    }
}

impl From<Vec<u8>> for Chunk {
    #[inline]
    fn from(v: Vec<u8>) -> Chunk {
        Chunk::from(Bytes::from(v))
    }
}

impl From<&'static [u8]> for Chunk {
    #[inline]
    fn from(slice: &'static [u8]) -> Chunk {
        Chunk::from(Bytes::from_static(slice))
    }
}

impl From<String> for Chunk {
    #[inline]
    fn from(s: String) -> Chunk {
        s.into_bytes().into()
    }
}

impl From<&'static str> for Chunk {
    #[inline]
    fn from(slice: &'static str) -> Chunk {
        slice.as_bytes().into()
    }
}

impl From<Bytes> for Chunk {
    #[inline]
    fn from(bytes: Bytes) -> Chunk {
        Chunk {
            bytes: bytes,
        }
    }
}

impl From<Chunk> for Bytes {
    #[inline]
    fn from(chunk: Chunk) -> Bytes {
        chunk.bytes
    }
}

impl ::std::ops::Deref for Chunk {
    type Target = [u8];

    #[inline]
    fn deref(&self) -> &Self::Target {
        self.as_ref()
    }
}

impl AsRef<[u8]> for Chunk {
    #[inline]
    fn as_ref(&self) -> &[u8] {
        &self.bytes
    }
}

impl fmt::Debug for Chunk {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(self.as_ref(), f)
    }
}

impl Default for Chunk {
    #[inline]
    fn default() -> Chunk {
        Chunk::from(Bytes::new())
    }
}

impl IntoIterator for Chunk {
    type Item = u8;
    type IntoIter = IntoIter;

    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        IntoIter {
            inner: self.bytes.into_iter(),
        }
    }
}

impl Extend<u8> for Chunk {
    #[inline]
    fn extend<T>(&mut self, iter: T) where T: IntoIterator<Item=u8> {
        self.bytes.extend(iter)
    }
}

impl Iterator for IntoIter {
    type Item = u8;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.inner.next()
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.inner.size_hint()
    }
}

impl ExactSizeIterator for IntoIter {}

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

    #[cfg(feature = "nightly")]
    use test::Bencher;

    #[cfg(feature = "nightly")]
    #[bench]
    fn bench_chunk_static_buf(b: &mut Bencher) {
        use bytes::BufMut;

        let s = "Hello, World!";
        b.bytes = s.len() as u64;

        let mut dst = Vec::with_capacity(128);

        b.iter(|| {
            let chunk = Chunk::from(s);
            dst.put(chunk);
            ::test::black_box(&dst);
            unsafe { dst.set_len(0); }
        })
    }
}

<|endoftext|>


<commit_before>#[crate_id(name="truncate", vers="1.0.0", author="Arcterus")];

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Arcterus <arcterus@mail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern mod extra;

use std::io::{stderr, io_error, File, Open, ReadWrite, Writer, SeekEnd, SeekSet};
use std::os;
use std::u64;
use extra::getopts::groups;

#[deriving(Eq)]
enum TruncateMode {
    Reference,
    Extend,
    Reduce,
    AtMost,
    AtLeast,
    RoundDown,
    RoundUp
}

fn main() {
    let args = os::args();
    let program = args[0].clone();

    let opts = ~[
        groups::optflag("c", "no-create", "do not create files that do not exist"),
        groups::optflag("o", "io-blocks", "treat SIZE as the number of I/O blocks of the file rather than bytes (NOT IMPLEMENTED)"),
        groups::optopt("r", "reference", "base the size of each file on the size of RFILE", "RFILE"),
        groups::optopt("s", "size", "set or adjust the size of each file according to SIZE, which is in bytes unless --io-blocks is specified", "SIZE"),
        groups::optflag("h", "help", "display this help and exit"),
        groups::optflag("V", "version", "output version information and exit")
    ];
    let matches = match groups::getopts(args.tail(), opts) {
        Ok(m) => m,
        Err(f) => {
            writeln!(&mut stderr() as &mut Writer, "{}", f.to_err_msg());
            os::set_exit_status(1);
            return
        }
    };

    if matches.opt_present("help") {
        println!("truncate 1.0.0");
        println!("");
        println!("Usage:");
        println!("  {0:s} [OPTION]... FILE...", program);
        println!("");
        print!("{}", groups::usage("Shrink or extend the size of each file to the specified size.", opts));
        println!("");
        println!("SIZE is an integer with an optional prefix and optional unit.");
        println!("The available units (K, M, G, T, P, E, Z, and Y) use the following format:");
        println!("\t'KB' =>           1000 (kilobytes)");
        println!("\t'K'  =>           1024 (kibibytes)");
        println!("\t'MB' =>      1000*1000 (megabytes)");
        println!("\t'M'  =>      1024*1024 (mebibytes)");
        println!("\t'GB' => 1000*1000*1000 (gigabytes)");
        println!("\t'G'  => 1024*1024*1024 (gibibytes)");
        println!("SIZE may also be prefixed by one of the following to adjust the size of each");
        println!("file based on its current size:");
        println!("\t'+'  => extend by");
        println!("\t'-'  => reduce by");
        println!("\t'<'  => at most");
        println!("\t'>'  => at least");
        println!("\t'/'  => round down to multiple of");
        println!("\t'%'  => round up to multiple of");
    } else if matches.opt_present("version") {
        println!("truncate 1.0.0");
    } else if matches.free.is_empty() {
        writeln!(&mut stderr() as &mut Writer, "Missing an argument");
        writeln!(&mut stderr() as &mut Writer,
                 "For help, try '{0:s} --help'", program);
        os::set_exit_status(1);
    } else {
        let no_create = matches.opt_present("no-create");
        let io_blocks = matches.opt_present("io-blocks");
        let reference = matches.opt_str("reference");
        let size = matches.opt_str("size");
        if reference.is_none() && size.is_none() {
            writeln!(&mut stderr() as &mut Writer, "You must specify either --reference or --size.");
            os::set_exit_status(1);
        } else {
            truncate(no_create, io_blocks, reference, size, matches.free);
        }
    }
}

fn truncate(no_create: bool, io_blocks: bool, reference: Option<~str>, size: Option<~str>, filenames: ~[~str]) {
    let (refsize, mode) = match reference {
        Some(rfilename) => {
            io_error::cond.trap(|err| {
                writeln!(&mut stderr() as &mut Writer, "{}", err.to_str());
                os::set_exit_status(1);
            }).inside(|| {
                let mut rfile = File::open(&Path::new(rfilename.clone()));
                rfile.seek(0, SeekEnd);
                (rfile.tell(), Reference)
            })
        }
        None => {
            match parse_size(size.unwrap()) {
                Ok(szpair) => szpair,
                Err(()) => return
            }
        }
    };
    for filename in filenames.iter() {
        let filename: &str = *filename;
        let path = Path::new(filename);
        if !path.exists() && !no_create {
            io_error::cond.trap(|_| {
                writeln!(&mut stderr() as &mut Writer,
                         "Failed to create the file '{}'", filename);
                os::set_exit_status(1);
            }).inside(|| {
                File::create(&path);
            });
        }
        io_error::cond.trap(|err| {
            writeln!(&mut stderr() as &mut Writer, "{}", err.to_str());
        }).inside(|| {
            match File::open_mode(&path, Open, ReadWrite) {
                Some(mut file) => {
                    file.seek(0, SeekEnd);
                    let fsize = file.tell();
                    file.seek(0, SeekSet);
                    let tsize = match mode {
                        Reference => refsize,
                        Extend => fsize + refsize,
                        Reduce => fsize - refsize,
                        AtMost => if fsize > refsize { refsize } else { fsize },
                        AtLeast => if fsize < refsize { refsize } else { fsize },
                        RoundDown => fsize - fsize % refsize,
                        RoundUp => fsize + fsize % refsize
                    };
                    file.truncate(tsize as i64);
                }
                None => {
                    writeln!(&mut stderr() as &mut Writer,
                             "Failed to open the file '{}'", filename);
                    os::set_exit_status(1);
                }
            }
        });
    }
}

fn parse_size(size: ~str) -> Result<(u64, TruncateMode), ()> {
    let mut err = false;
    let mode = match size.char_at(0) {
        '+' => Extend,
        '-' => Reduce,
        '<' => AtMost,
        '>' => AtLeast,
        '/' => RoundDown,
        '*' => RoundUp,
        _ => Reference /* assume that the size is just a number */
    };
    let bytes = {
        let mut slice =
            if mode == Reference {
                let size: &str = size;
                size
            } else {
                size.slice_from(1)
            };
        if slice.char_at(slice.len() - 1).is_alphabetic() {
            slice = slice.slice_to(slice.len() - 1);
            if slice.len() > 0 && slice.char_at(slice.len() - 1).is_alphabetic() {
                slice = slice.slice_to(slice.len() - 1);
            }
        }
        slice
    }.bytes().to_owned_vec();
    let mut number = match u64::parse_bytes(bytes, 10) {
        Some(num) => num,
        None => {
            writeln!(&mut stderr() as &mut Writer,
                     "'{}' is not a valid number.", size);
            os::set_exit_status(1);
            err = true;
            0
        }
    };
    if !err && size.char_at(size.len() - 1).is_alphabetic() {
        number *= match size.char_at(size.len() - 1).to_ascii().to_upper().to_char() {
            'B' => match size.char_at(size.len() - 2).to_ascii().to_upper().to_char() {
                'K' => 1000,
                'M' => 1000 * 1000,
                'G' => 1000 * 1000 * 1000,
                'T' => 1000 * 1000 * 1000 * 1000,
                'P' => 1000 * 1000 * 1000 * 1000 * 1000,
                'E' => 1000 * 1000 * 1000 * 1000 * 1000 * 1000,
                'Z' => 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000,
                'Y' => 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000,
                letter => {
                    writeln!(&mut stderr() as &mut Writer,
                             "'{}B' is not a valid suffix.", letter);
                    os::set_exit_status(1);
                    err = true;
                    1
                }
            },
            'K' => 1024,
            'M' => 1024 * 1024,
            'G' => 1024 * 1024 * 1024,
            'T' => 1024 * 1024 * 1024 * 1024,
            'P' => 1024 * 1024 * 1024 * 1024 * 1024,
            'E' => 1024 * 1024 * 1024 * 1024 * 1024 * 1024,
            'Z' => 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024,
            'Y' => 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024,
            letter => {
                writeln!(&mut stderr() as &mut Writer,
                         "'{}' is not a valid suffix.", letter);
                os::set_exit_status(1);
                err = true;
                1
            }
        };
    }
    if err {
        Err(())
    } else {
        Ok((number, mode))
    }
}

<commit_msg>Properly support --no-create for truncate<commit_after>#[crate_id(name="truncate", vers="1.0.0", author="Arcterus")];

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Arcterus <arcterus@mail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern mod extra;

use std::io::{stderr, io_error, File, Open, ReadWrite, Writer, SeekEnd, SeekSet};
use std::os;
use std::u64;
use extra::getopts::groups;

#[deriving(Eq)]
enum TruncateMode {
    Reference,
    Extend,
    Reduce,
    AtMost,
    AtLeast,
    RoundDown,
    RoundUp
}

fn main() {
    let args = os::args();
    let program = args[0].clone();

    let opts = ~[
        groups::optflag("c", "no-create", "do not create files that do not exist"),
        groups::optflag("o", "io-blocks", "treat SIZE as the number of I/O blocks of the file rather than bytes (NOT IMPLEMENTED)"),
        groups::optopt("r", "reference", "base the size of each file on the size of RFILE", "RFILE"),
        groups::optopt("s", "size", "set or adjust the size of each file according to SIZE, which is in bytes unless --io-blocks is specified", "SIZE"),
        groups::optflag("h", "help", "display this help and exit"),
        groups::optflag("V", "version", "output version information and exit")
    ];
    let matches = match groups::getopts(args.tail(), opts) {
        Ok(m) => m,
        Err(f) => {
            writeln!(&mut stderr() as &mut Writer, "{}", f.to_err_msg());
            os::set_exit_status(1);
            return
        }
    };

    if matches.opt_present("help") {
        println!("truncate 1.0.0");
        println!("");
        println!("Usage:");
        println!("  {0:s} [OPTION]... FILE...", program);
        println!("");
        print!("{}", groups::usage("Shrink or extend the size of each file to the specified size.", opts));
        println!("");
        println!("SIZE is an integer with an optional prefix and optional unit.");
        println!("The available units (K, M, G, T, P, E, Z, and Y) use the following format:");
        println!("\t'KB' =>           1000 (kilobytes)");
        println!("\t'K'  =>           1024 (kibibytes)");
        println!("\t'MB' =>      1000*1000 (megabytes)");
        println!("\t'M'  =>      1024*1024 (mebibytes)");
        println!("\t'GB' => 1000*1000*1000 (gigabytes)");
        println!("\t'G'  => 1024*1024*1024 (gibibytes)");
        println!("SIZE may also be prefixed by one of the following to adjust the size of each");
        println!("file based on its current size:");
        println!("\t'+'  => extend by");
        println!("\t'-'  => reduce by");
        println!("\t'<'  => at most");
        println!("\t'>'  => at least");
        println!("\t'/'  => round down to multiple of");
        println!("\t'%'  => round up to multiple of");
    } else if matches.opt_present("version") {
        println!("truncate 1.0.0");
    } else if matches.free.is_empty() {
        writeln!(&mut stderr() as &mut Writer, "Missing an argument");
        writeln!(&mut stderr() as &mut Writer,
                 "For help, try '{0:s} --help'", program);
        os::set_exit_status(1);
    } else {
        let no_create = matches.opt_present("no-create");
        let io_blocks = matches.opt_present("io-blocks");
        let reference = matches.opt_str("reference");
        let size = matches.opt_str("size");
        if reference.is_none() && size.is_none() {
            writeln!(&mut stderr() as &mut Writer, "You must specify either --reference or --size.");
            os::set_exit_status(1);
        } else {
            truncate(no_create, io_blocks, reference, size, matches.free);
        }
    }
}

fn truncate(no_create: bool, io_blocks: bool, reference: Option<~str>, size: Option<~str>, filenames: ~[~str]) {
    let (refsize, mode) = match reference {
        Some(rfilename) => {
            io_error::cond.trap(|err| {
                writeln!(&mut stderr() as &mut Writer, "{}", err.to_str());
                os::set_exit_status(1);
            }).inside(|| {
                let mut rfile = File::open(&Path::new(rfilename.clone()));
                rfile.seek(0, SeekEnd);
                (rfile.tell(), Reference)
            })
        }
        None => {
            match parse_size(size.unwrap()) {
                Ok(szpair) => szpair,
                Err(()) => return
            }
        }
    };
    for filename in filenames.iter() {
        let filename: &str = *filename;
        let path = Path::new(filename);
        io_error::cond.trap(|err| {
            writeln!(&mut stderr() as &mut Writer, "{}", err.to_str());
        }).inside(|| {
            if path.exists() || !no_create {
                match File::open_mode(&path, Open, ReadWrite) {
                    Some(mut file) => {
                        file.seek(0, SeekEnd);
                        let fsize = file.tell();
                        file.seek(0, SeekSet);
                            let tsize = match mode {
                            Reference => refsize,
                            Extend => fsize + refsize,
                            Reduce => fsize - refsize,
                            AtMost => if fsize > refsize { refsize } else { fsize },
                            AtLeast => if fsize < refsize { refsize } else { fsize },
                            RoundDown => fsize - fsize % refsize,
                            RoundUp => fsize + fsize % refsize
                        };
                        file.truncate(tsize as i64);
                    }
                    None => {
                        writeln!(&mut stderr() as &mut Writer,
                                 "Failed to open the file '{}'", filename);
                        os::set_exit_status(1);
                    }
                }
            }
        });
    }
}

fn parse_size(size: ~str) -> Result<(u64, TruncateMode), ()> {
    let mut err = false;
    let mode = match size.char_at(0) {
        '+' => Extend,
        '-' => Reduce,
        '<' => AtMost,
        '>' => AtLeast,
        '/' => RoundDown,
        '*' => RoundUp,
        _ => Reference /* assume that the size is just a number */
    };
    let bytes = {
        let mut slice =
            if mode == Reference {
                let size: &str = size;
                size
            } else {
                size.slice_from(1)
            };
        if slice.char_at(slice.len() - 1).is_alphabetic() {
            slice = slice.slice_to(slice.len() - 1);
            if slice.len() > 0 && slice.char_at(slice.len() - 1).is_alphabetic() {
                slice = slice.slice_to(slice.len() - 1);
            }
        }
        slice
    }.bytes().to_owned_vec();
    let mut number = match u64::parse_bytes(bytes, 10) {
        Some(num) => num,
        None => {
            writeln!(&mut stderr() as &mut Writer,
                     "'{}' is not a valid number.", size);
            os::set_exit_status(1);
            err = true;
            0
        }
    };
    if !err && size.char_at(size.len() - 1).is_alphabetic() {
        number *= match size.char_at(size.len() - 1).to_ascii().to_upper().to_char() {
            'B' => match size.char_at(size.len() - 2).to_ascii().to_upper().to_char() {
                'K' => 1000,
                'M' => 1000 * 1000,
                'G' => 1000 * 1000 * 1000,
                'T' => 1000 * 1000 * 1000 * 1000,
                'P' => 1000 * 1000 * 1000 * 1000 * 1000,
                'E' => 1000 * 1000 * 1000 * 1000 * 1000 * 1000,
                'Z' => 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000,
                'Y' => 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000,
                letter => {
                    writeln!(&mut stderr() as &mut Writer,
                             "'{}B' is not a valid suffix.", letter);
                    os::set_exit_status(1);
                    err = true;
                    1
                }
            },
            'K' => 1024,
            'M' => 1024 * 1024,
            'G' => 1024 * 1024 * 1024,
            'T' => 1024 * 1024 * 1024 * 1024,
            'P' => 1024 * 1024 * 1024 * 1024 * 1024,
            'E' => 1024 * 1024 * 1024 * 1024 * 1024 * 1024,
            'Z' => 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024,
            'Y' => 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024,
            letter => {
                writeln!(&mut stderr() as &mut Writer,
                         "'{}' is not a valid suffix.", letter);
                os::set_exit_status(1);
                err = true;
                1
            }
        };
    }
    if err {
        Err(())
    } else {
        Ok((number, mode))
    }
}

<|endoftext|>