<commit_before>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (eliza@elizas.website)
//
//  Copyright (c) 2016 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Macros for kernel-level logging

#[macro_export]
macro_rules! attempt {
    ($task:expr => $msg:expr, dots: $dots:expr) => {
        {
            print!("{}{}", $dots, $msg);
            match $task {
               Ok(result) => {
                    println!( "{:indent$}{res:}"
                            , ""
                            , indent = 70 - concat!($dots,$msg).len()
                            , res = "[ OKAY ]");
                    info!("{} [ OKAY ]", $msg);
                    result
                }
              , Err(why) => {
                    println!( "{:indent$}{res:}"
                              , ""
                              , indent = 70 - concat!($dots,$msg).len()
                              , res = "[ FAIL ]");
                    panic!("{:?}", why);
              }
            }
        }

    };
}

#[macro_export]
macro_rules! kinfo {
    ( dots: $dots:expr, target: $target:expr, $status:expr ) => {
        // {
        //     use core::fmt::Write;
        //
        //     // suppress warnings because we don't care if there's no serial port
        //     let _ = write!( $crate::arch::drivers::serial::COM1.lock()
        //                   , "[info] {}: {} {}"
        //                   , module_path!()
        //                   , $msg, $status);
            print!("{:<38}{:>40}", concat!($dots, $target), $status );
            info!(target: $target, $status);
        // }
    };
    ( dots: $dots:expr, $($args:tt)* ) => {
        // {
        //     use core::fmt::Write;
        //
        //     // suppress warnings because we don't care if there's no serial port
        //     let _ = write!( $crate::arch::drivers::serial::COM1.lock()
        //                   , "[info] {}: {}"
        //                   , module_path!()
        //                   , format_args!($($args)*));
            print!("{}{}", $dots, format_args!($($args)*));
            info!( ($args)* );
        // }
    };
    ( $($args:tt)* ) => {
    //     {
    //         use core::fmt::Write;
    //
    //         // suppress warnings because we don't care if there's no serial port
    //         let _ = write!( $crate::arch::drivers::serial::COM1.lock()
    //                       , "[info] {}: {}"
    //                       , module_path!()
    //                       , format_args!($($args)*));
            print!( $($args)* );
            info!( $($args)* );
        // }
    };
}
#[macro_export]
macro_rules! kinfoln {
    ( dots: $dots:expr, target: $target:expr, $status:expr ) => {
        // {
        //     use core::fmt::Write;
        //
        //     // suppress warnings because we don't care if there's no serial port
        //     let _ = write!( $crate::arch::drivers::serial::COM1.lock()
        //                   , "[info] {}: {} {}"
        //                   , module_path!()
        //                   , $msg, $status);
            println!("{:<38}{:>40}", concat!($dots, $target), $status );
            info!(target: $target, $status);
        // }
    };
    ( dots: $dots:expr, $($args:tt)* ) => {
        // {
        //     use core::fmt::Write;
        //
        //     // suppress warnings because we don't care if there's no serial port
        //     let _ = write!( $crate::arch::drivers::serial::COM1.lock()
        //                   , "[info] {}: {}"
        //                   , module_path!()
        //                   , format_args!($($args)*));
            println!("{}{}", $dots, format_args!($($args)*));
            info!( $($args)* );
        // }
    };
    ( $($args:tt)* ) => {
    //     {
    //         use core::fmt::Write;
    //
    //         // suppress warnings because we don't care if there's no serial port
    //         let _ = write!( $crate::arch::drivers::serial::COM1.lock()
    //                       , "[info] {}: {}"
    //                       , module_path!()
    //                       , format_args!($($args)*));
            println!( $($args)* );
            info!( $($args)* );
        // }
    };
}
<commit_msg>feat(vga::kinfo::attempt): attempt!() can now accept format args!<commit_after>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (eliza@elizas.website)
//
//  Copyright (c) 2016 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Macros for kernel-level logging

#[macro_export]
macro_rules! attempt {
    ($task:expr => dots: $dots:expr, $msg:expr ) => {
            print!("{}{:<indent$}"
                    , $dots
                    , $msg
                    , indent = 70 - $dots.len());
            match $task {
               Ok(result) => {
                    println!("[ OKAY ]");
                    info!("{} [ OKAY ]", $msg);
                    result
                }
              , Err(why) => {
                    println!("[ FAIL ]");
                    panic!("{:?}", why);
              }
        }
    };
    ($task:expr => dots: $dots:expr, $($msg:tt)* ) => {
            print!("{}{:<indent$}"
                    , $dots
                    , format_args!($($msg)*)
                    , indent = 70 - $dots.len());
            match $task {
               Ok(result) => {
                    println!("[ OKAY ]");
                    info!("{} [ OKAY ]", format_args!($($msg)*));
                    result
                }
              , Err(why) => {
                    println!("[ FAIL ]");
                    panic!("{:?}", why);
              }
        }
    };

}

#[macro_export]
macro_rules! kinfo {
    ( dots: $dots:expr, target: $target:expr, $status:expr ) => {
        // {
        //     use core::fmt::Write;
        //
        //     // suppress warnings because we don't care if there's no serial port
        //     let _ = write!( $crate::arch::drivers::serial::COM1.lock()
        //                   , "[info] {}: {} {}"
        //                   , module_path!()
        //                   , $msg, $status);
            print!("{:<38}{:>40}", concat!($dots, $target), $status );
            info!(target: $target, $status);
        // }
    };
    ( dots: $dots:expr, $($args:tt)* ) => {
        // {
        //     use core::fmt::Write;
        //
        //     // suppress warnings because we don't care if there's no serial port
        //     let _ = write!( $crate::arch::drivers::serial::COM1.lock()
        //                   , "[info] {}: {}"
        //                   , module_path!()
        //                   , format_args!($($args)*));
            print!("{}{}", $dots, format_args!($($args)*));
            info!( ($args)* );
        // }
    };
    ( $($args:tt)* ) => {
    //     {
    //         use core::fmt::Write;
    //
    //         // suppress warnings because we don't care if there's no serial port
    //         let _ = write!( $crate::arch::drivers::serial::COM1.lock()
    //                       , "[info] {}: {}"
    //                       , module_path!()
    //                       , format_args!($($args)*));
            print!( $($args)* );
            info!( $($args)* );
        // }
    };
}
#[macro_export]
macro_rules! kinfoln {
    ( dots: $dots:expr, target: $target:expr, $status:expr ) => {
        // {
        //     use core::fmt::Write;
        //
        //     // suppress warnings because we don't care if there's no serial port
        //     let _ = write!( $crate::arch::drivers::serial::COM1.lock()
        //                   , "[info] {}: {} {}"
        //                   , module_path!()
        //                   , $msg, $status);
            println!("{:<38}{:>40}", concat!($dots, $target), $status );
            info!(target: $target, $status);
        // }
    };
    ( dots: $dots:expr, $($args:tt)* ) => {
        // {
        //     use core::fmt::Write;
        //
        //     // suppress warnings because we don't care if there's no serial port
        //     let _ = write!( $crate::arch::drivers::serial::COM1.lock()
        //                   , "[info] {}: {}"
        //                   , module_path!()
        //                   , format_args!($($args)*));
            println!("{}{}", $dots, format_args!($($args)*));
            info!( $($args)* );
        // }
    };
    ( $($args:tt)* ) => {
    //     {
    //         use core::fmt::Write;
    //
    //         // suppress warnings because we don't care if there's no serial port
    //         let _ = write!( $crate::arch::drivers::serial::COM1.lock()
    //                       , "[info] {}: {}"
    //                       , module_path!()
    //                       , format_args!($($args)*));
            println!( $($args)* );
            info!( $($args)* );
        // }
    };
}
<|endoftext|>


<commit_before>use std::sync::{ Once, ONCE_INIT };
use std::intrinsics::abort;
use std::{ mem, ptr };
use rand::{ thread_rng, Rng, OsRng };

const GARBAGE_VALUE: u8 = 0xd0;
const CANARY_SIZE: usize = 16;
static ALLOC_INIT: Once = ONCE_INIT;
static mut PAGE_SIZE: usize = 0;
static mut CANARY: [u8; CANARY_SIZE] = [0; CANARY_SIZE];

// -- alloc init --

unsafe fn alloc_init() {
    #[cfg(unix)] {
        let page_size = ::libc::sysconf(::libc::_SC_PAGESIZE);
        if page_size > 0 {
            PAGE_SIZE = page_size as usize;
        }
    }

    #[cfg(windows)] {
        let si = mem::uninitialized();
        ::kernel32::GetSystemInfo(si);
        PAGE_SIZE = ptr::read(si).dwPageSize as usize;
    }

    if PAGE_SIZE < CANARY_SIZE || PAGE_SIZE < mem::size_of::<usize>() {
        abort();
    }

    match OsRng::new() {
        Ok(mut rng) => rng.fill_bytes(&mut CANARY),
        Err(_) => thread_rng().fill_bytes(&mut CANARY)
    }
}

// -- aligned alloc / aligned free --

#[cfg(unix)]
unsafe fn alloc_aligned<T>(size: usize) -> Option<*mut T> {
    let mut memptr = mem::uninitialized();
    match ::libc::posix_memalign(&mut memptr, PAGE_SIZE, size) {
        0 => Some(memptr as *mut T),
        ::libc::EINVAL => panic!("EINVAL: invalid alignmen. {}", PAGE_SIZE),
        ::libc::ENOMEM => None,
        _ => unreachable!()
    }
}

#[cfg(windows)]
unsafe fn alloc_aligned<T>(size: usize) -> Option<*mut T> {
    Some(::kernel32::VirtualAlloc(
        ptr::null_mut(),
        size as ::winapi::SIZE_T,
        ::winapi::MEM_COMMIT | ::winapi::MEM_RESERVE,
        ::winapi::PAGE_READWRITE
    ) as *mut T)
}

#[cfg(unix)]
unsafe fn free_aligned<T>(memptr: *mut T) {
    ::libc::free(memptr as *mut ::libc::c_void);
}

#[cfg(windows)]
unsafe fn free_aligned<T>(memptr: *mut T) {
    ::kernel32::VirtualFree(memptr as ::winapi::LPVOID, 0, ::winapi::MEM_RELEASE);
}

// -- malloc / free --

#[inline]
unsafe fn page_round(size: usize) -> usize {
    let page_mask = PAGE_SIZE - 1;
    (size + page_mask) & (!page_mask)
}

unsafe fn unprotected_ptr_from_user_ptr<T>(memptr: *const T) -> *mut T {
    let canary_ptr = memptr.offset(-(mem::size_of_val(&CANARY) as isize));
    let page_mask = PAGE_SIZE - 1;
    let unprotected_ptr_u = canary_ptr as usize & !page_mask;
    if unprotected_ptr_u <= PAGE_SIZE * 2 {
        abort();
    }
    unprotected_ptr_u as *mut T
}

unsafe fn _malloc<T>(size: usize) -> Option<*mut T> {
    ALLOC_INIT.call_once(|| alloc_init());

    if size >= ::std::usize::MAX - PAGE_SIZE * 4 {
        return None;
    }
    if PAGE_SIZE <= mem::size_of_val(&CANARY) || PAGE_SIZE < mem::size_of::<usize>() {
        abort();
    }

    // aligned alloc ptr
    let size_with_canary = mem::size_of_val(&CANARY) + size;
    let unprotected_size = page_round(size_with_canary);
    let total_size = PAGE_SIZE + PAGE_SIZE + unprotected_size + PAGE_SIZE;
    let base_ptr = match alloc_aligned(total_size) {
        Some(memptr) => memptr,
        None => return None
    };

    // canary offset
    let unprotected_ptr = base_ptr.offset(PAGE_SIZE as isize * 2);
    ::mprotect(base_ptr.offset(PAGE_SIZE as isize), PAGE_SIZE, ::Prot::NoAccess);
    ptr::copy(
        CANARY.as_ptr(),
        unprotected_ptr.offset(unprotected_size as isize) as *mut u8,
        mem::size_of_val(&CANARY)
    );

    // mprotect ptr
    ::mprotect(unprotected_ptr.offset(unprotected_size as isize), PAGE_SIZE, ::Prot::NoAccess);
    ::mlock(unprotected_ptr, unprotected_size);
    let canary_ptr = unprotected_ptr
        .offset(page_round(size_with_canary) as isize)
        .offset(-(size_with_canary as isize));
    let user_ptr = canary_ptr.offset(mem::size_of_val(&CANARY) as isize);
    ptr::copy(CANARY.as_ptr(), canary_ptr as *mut u8, mem::size_of_val(&CANARY));
    ptr::write(base_ptr as *mut usize, unprotected_size);
    ::mprotect(base_ptr, PAGE_SIZE, ::Prot::ReadOnly);

    debug_assert_eq!(unprotected_ptr_from_user_ptr(user_ptr), unprotected_ptr);

    Some(user_ptr)
}

/// Secure malloc.
pub unsafe fn malloc<T>(size: usize) -> Option<*mut T> {
    _malloc(size)
        .map(|memptr| {
            ::memset(memptr, GARBAGE_VALUE as i32, size);
            memptr
        })
}

/// Alloc array.
///
/// ```
/// use std::{ slice, mem };
/// use memsec::{ allocarray, free, memzero, memset, memcmp };
///
/// let memptr: *mut u8 = unsafe { allocarray(8).unwrap() };
/// let array = unsafe { slice::from_raw_parts_mut(memptr, 8) };
/// assert_eq!(array, [0xd0; 8]);
/// unsafe { memzero(memptr, 8) };
/// assert_eq!(array, [0; 8]);
/// array[0] = 1;
/// assert_eq!(unsafe { memcmp(memptr, [1, 0, 0, 0, 0, 0, 0, 0].as_ptr(), 8) }, 0);
/// unsafe { free(memptr) };
/// ```
pub unsafe fn allocarray<T>(count: usize) -> Option<*mut T> {
    let size = mem::size_of::<T>();
    if count > mem::size_of::<usize>() && size >= ::std::usize::MAX / count {
        None
    } else {
        malloc(count * size)
    }
}

/// Secure free.
pub unsafe fn free<T>(memptr: *mut T) {
    if memptr.is_null() { return () };

    // get unprotected ptr
    let canary_ptr = memptr.offset(-(mem::size_of_val(&CANARY) as isize));
    let unprotected_ptr = unprotected_ptr_from_user_ptr(memptr);
    let base_ptr = unprotected_ptr.offset(-(PAGE_SIZE as isize * 2));
    let unprotected_size = ptr::read(base_ptr as *const usize);
    let total_size = PAGE_SIZE + PAGE_SIZE + unprotected_size + PAGE_SIZE;
    ::mprotect(base_ptr, total_size, ::Prot::ReadWrite);

    // check
    debug_assert_eq!(::memcmp(canary_ptr as *const u8, CANARY.as_ptr(), mem::size_of_val(&CANARY)), 0);
    debug_assert_eq!(::memcmp(
        unprotected_ptr.offset(unprotected_size as isize) as *const u8,
        CANARY.as_ptr(),
        mem::size_of_val(&CANARY)
    ), 0);

    // free
    ::munlock(unprotected_ptr, unprotected_size);
    free_aligned(base_ptr);
}

// -- unprotected mprotect --

/// Secure mprotect.
pub unsafe fn unprotected_mprotect<T>(ptr: *mut T, prot: ::Prot) -> bool {
    let unprotected_ptr = unprotected_ptr_from_user_ptr(ptr);
    let base_ptr = unprotected_ptr.offset(-(PAGE_SIZE as isize * 2));
    let unprotected_size = ptr::read(base_ptr as *const usize);
    ::mprotect(unprotected_ptr, unprotected_size, prot)
}

#[cfg(all(unix, test))]
mod test {
    use std::mem;

    #[should_panic]
    #[test]
    fn mprotect_test() {
        use nix::sys::signal;

        super::ALLOC_INIT.call_once(|| unsafe { super::alloc_init() });

        extern fn sigsegv(_: i32) { panic!() }
        let sigaction = signal::SigAction::new(
            signal::SigHandler::Handler(sigsegv),
            signal::SA_SIGINFO,
            signal::SigSet::empty(),
        );
        unsafe { signal::sigaction(signal::SIGSEGV, &sigaction).ok() };

        let x: *mut u8 = unsafe { super::alloc_aligned(16 * mem::size_of::<u8>()).unwrap() };
        unsafe { ::mprotect(x, 16 * mem::size_of::<u8>(), ::Prot::NoAccess) };

        unsafe { ::memzero(x, 16 * mem::size_of::<u8>()) }; // SIGSEGV!
    }
}

#[test]
fn alloc_free_aligned() {
    ALLOC_INIT.call_once(|| unsafe { alloc_init() });

    let x: *mut u8 = unsafe { alloc_aligned(16 * mem::size_of::<u8>()).unwrap() };
    unsafe { ::memzero(x, 16 * mem::size_of::<u8>()) };
    assert!(unsafe { ::mprotect(x, 16 * mem::size_of::<u8>(), ::Prot::ReadOnly) });
    assert_eq!(unsafe { ::memcmp(x, [0; 16].as_ptr(), 16 * mem::size_of::<u8>()) }, 0);
    assert!(unsafe { ::mprotect(x, 16 * mem::size_of::<u8>(), ::Prot::NoAccess) });
    assert!(unsafe { ::mprotect(x, 16 * mem::size_of::<u8>(), ::Prot::ReadWrite) });
    unsafe { ::memzero(x, 16 * mem::size_of::<u8>()) };
    unsafe { free_aligned(x) };
}
<commit_msg>alloc: Calculate PAGE_MASK when alloc_init()<commit_after>use std::sync::{ Once, ONCE_INIT };
use std::intrinsics::abort;
use std::{ mem, ptr };
use rand::{ thread_rng, Rng, OsRng };

const GARBAGE_VALUE: u8 = 0xd0;
const CANARY_SIZE: usize = 16;
static ALLOC_INIT: Once = ONCE_INIT;
static mut PAGE_SIZE: usize = 0;
static mut PAGE_MASK: usize = 0;
static mut CANARY: [u8; CANARY_SIZE] = [0; CANARY_SIZE];

// -- alloc init --

unsafe fn alloc_init() {
    #[cfg(unix)] {
        let page_size = ::libc::sysconf(::libc::_SC_PAGESIZE);
        if page_size > 0 {
            PAGE_SIZE = page_size as usize;
        }
    }

    #[cfg(windows)] {
        let si = mem::uninitialized();
        ::kernel32::GetSystemInfo(si);
        PAGE_SIZE = ptr::read(si).dwPageSize as usize;
    }

    if PAGE_SIZE < CANARY_SIZE || PAGE_SIZE < mem::size_of::<usize>() {
        abort();
    }

    PAGE_MASK = PAGE_SIZE - 1;

    match OsRng::new() {
        Ok(mut rng) => rng.fill_bytes(&mut CANARY),
        Err(_) => thread_rng().fill_bytes(&mut CANARY)
    }
}

// -- aligned alloc / aligned free --

#[cfg(unix)]
unsafe fn alloc_aligned<T>(size: usize) -> Option<*mut T> {
    let mut memptr = mem::uninitialized();
    match ::libc::posix_memalign(&mut memptr, PAGE_SIZE, size) {
        0 => Some(memptr as *mut T),
        ::libc::EINVAL => panic!("EINVAL: invalid alignmen. {}", PAGE_SIZE),
        ::libc::ENOMEM => None,
        _ => unreachable!()
    }
}

#[cfg(windows)]
unsafe fn alloc_aligned<T>(size: usize) -> Option<*mut T> {
    Some(::kernel32::VirtualAlloc(
        ptr::null_mut(),
        size as ::winapi::SIZE_T,
        ::winapi::MEM_COMMIT | ::winapi::MEM_RESERVE,
        ::winapi::PAGE_READWRITE
    ) as *mut T)
}

#[cfg(unix)]
unsafe fn free_aligned<T>(memptr: *mut T) {
    ::libc::free(memptr as *mut ::libc::c_void);
}

#[cfg(windows)]
unsafe fn free_aligned<T>(memptr: *mut T) {
    ::kernel32::VirtualFree(memptr as ::winapi::LPVOID, 0, ::winapi::MEM_RELEASE);
}

// -- malloc / free --

#[inline]
unsafe fn page_round(size: usize) -> usize {
    (size + PAGE_MASK) & (!PAGE_MASK)
}

unsafe fn unprotected_ptr_from_user_ptr<T>(memptr: *const T) -> *mut T {
    let canary_ptr = memptr.offset(-(mem::size_of_val(&CANARY) as isize));
    let unprotected_ptr_u = canary_ptr as usize & !PAGE_MASK;
    if unprotected_ptr_u <= PAGE_SIZE * 2 {
        abort();
    }
    unprotected_ptr_u as *mut T
}

unsafe fn _malloc<T>(size: usize) -> Option<*mut T> {
    ALLOC_INIT.call_once(|| alloc_init());

    if size >= ::std::usize::MAX - PAGE_SIZE * 4 {
        return None;
    }
    if PAGE_SIZE <= mem::size_of_val(&CANARY) || PAGE_SIZE < mem::size_of::<usize>() {
        abort();
    }

    // aligned alloc ptr
    let size_with_canary = mem::size_of_val(&CANARY) + size;
    let unprotected_size = page_round(size_with_canary);
    let total_size = PAGE_SIZE + PAGE_SIZE + unprotected_size + PAGE_SIZE;
    let base_ptr = match alloc_aligned(total_size) {
        Some(memptr) => memptr,
        None => return None
    };

    // canary offset
    let unprotected_ptr = base_ptr.offset(PAGE_SIZE as isize * 2);
    ::mprotect(base_ptr.offset(PAGE_SIZE as isize), PAGE_SIZE, ::Prot::NoAccess);
    ptr::copy(
        CANARY.as_ptr(),
        unprotected_ptr.offset(unprotected_size as isize) as *mut u8,
        mem::size_of_val(&CANARY)
    );

    // mprotect ptr
    ::mprotect(unprotected_ptr.offset(unprotected_size as isize), PAGE_SIZE, ::Prot::NoAccess);
    ::mlock(unprotected_ptr, unprotected_size);
    let canary_ptr = unprotected_ptr
        .offset(page_round(size_with_canary) as isize)
        .offset(-(size_with_canary as isize));
    let user_ptr = canary_ptr.offset(mem::size_of_val(&CANARY) as isize);
    ptr::copy(CANARY.as_ptr(), canary_ptr as *mut u8, mem::size_of_val(&CANARY));
    ptr::write(base_ptr as *mut usize, unprotected_size);
    ::mprotect(base_ptr, PAGE_SIZE, ::Prot::ReadOnly);

    debug_assert_eq!(unprotected_ptr_from_user_ptr(user_ptr), unprotected_ptr);

    Some(user_ptr)
}

/// Secure malloc.
pub unsafe fn malloc<T>(size: usize) -> Option<*mut T> {
    _malloc(size)
        .map(|memptr| {
            ::memset(memptr, GARBAGE_VALUE as i32, size);
            memptr
        })
}

/// Alloc array.
///
/// ```
/// use std::{ slice, mem };
/// use memsec::{ allocarray, free, memzero, memset, memcmp };
///
/// let memptr: *mut u8 = unsafe { allocarray(8).unwrap() };
/// let array = unsafe { slice::from_raw_parts_mut(memptr, 8) };
/// assert_eq!(array, [0xd0; 8]);
/// unsafe { memzero(memptr, 8) };
/// assert_eq!(array, [0; 8]);
/// array[0] = 1;
/// assert_eq!(unsafe { memcmp(memptr, [1, 0, 0, 0, 0, 0, 0, 0].as_ptr(), 8) }, 0);
/// unsafe { free(memptr) };
/// ```
pub unsafe fn allocarray<T>(count: usize) -> Option<*mut T> {
    let size = mem::size_of::<T>();
    if count > mem::size_of::<usize>() && size >= ::std::usize::MAX / count {
        None
    } else {
        malloc(count * size)
    }
}

/// Secure free.
pub unsafe fn free<T>(memptr: *mut T) {
    if memptr.is_null() { return () };

    // get unprotected ptr
    let canary_ptr = memptr.offset(-(mem::size_of_val(&CANARY) as isize));
    let unprotected_ptr = unprotected_ptr_from_user_ptr(memptr);
    let base_ptr = unprotected_ptr.offset(-(PAGE_SIZE as isize * 2));
    let unprotected_size = ptr::read(base_ptr as *const usize);
    let total_size = PAGE_SIZE + PAGE_SIZE + unprotected_size + PAGE_SIZE;
    ::mprotect(base_ptr, total_size, ::Prot::ReadWrite);

    // check
    debug_assert_eq!(::memcmp(canary_ptr as *const u8, CANARY.as_ptr(), mem::size_of_val(&CANARY)), 0);
    debug_assert_eq!(::memcmp(
        unprotected_ptr.offset(unprotected_size as isize) as *const u8,
        CANARY.as_ptr(),
        mem::size_of_val(&CANARY)
    ), 0);

    // free
    ::munlock(unprotected_ptr, unprotected_size);
    free_aligned(base_ptr);
}

// -- unprotected mprotect --

/// Secure mprotect.
pub unsafe fn unprotected_mprotect<T>(ptr: *mut T, prot: ::Prot) -> bool {
    let unprotected_ptr = unprotected_ptr_from_user_ptr(ptr);
    let base_ptr = unprotected_ptr.offset(-(PAGE_SIZE as isize * 2));
    let unprotected_size = ptr::read(base_ptr as *const usize);
    ::mprotect(unprotected_ptr, unprotected_size, prot)
}

#[cfg(all(unix, test))]
mod test {
    use std::mem;

    #[should_panic]
    #[test]
    fn mprotect_test() {
        use nix::sys::signal;

        super::ALLOC_INIT.call_once(|| unsafe { super::alloc_init() });

        extern fn sigsegv(_: i32) { panic!() }
        let sigaction = signal::SigAction::new(
            signal::SigHandler::Handler(sigsegv),
            signal::SA_SIGINFO,
            signal::SigSet::empty(),
        );
        unsafe { signal::sigaction(signal::SIGSEGV, &sigaction).ok() };

        let x: *mut u8 = unsafe { super::alloc_aligned(16 * mem::size_of::<u8>()).unwrap() };
        unsafe { ::mprotect(x, 16 * mem::size_of::<u8>(), ::Prot::NoAccess) };

        unsafe { ::memzero(x, 16 * mem::size_of::<u8>()) }; // SIGSEGV!
    }
}

#[test]
fn alloc_free_aligned() {
    ALLOC_INIT.call_once(|| unsafe { alloc_init() });

    let x: *mut u8 = unsafe { alloc_aligned(16 * mem::size_of::<u8>()).unwrap() };
    unsafe { ::memzero(x, 16 * mem::size_of::<u8>()) };
    assert!(unsafe { ::mprotect(x, 16 * mem::size_of::<u8>(), ::Prot::ReadOnly) });
    assert_eq!(unsafe { ::memcmp(x, [0; 16].as_ptr(), 16 * mem::size_of::<u8>()) }, 0);
    assert!(unsafe { ::mprotect(x, 16 * mem::size_of::<u8>(), ::Prot::NoAccess) });
    assert!(unsafe { ::mprotect(x, 16 * mem::size_of::<u8>(), ::Prot::ReadWrite) });
    unsafe { ::memzero(x, 16 * mem::size_of::<u8>()) };
    unsafe { free_aligned(x) };
}
<|endoftext|>


<commit_before>use std::io::{self, Read};
use std::sync::mpsc;
use std::thread;

use tty;

/// Construct an asynchronous handle to the TTY standard input.
///
/// This allows you to read from standard input _without blocking_ the current thread.
/// Specifically, it works by firing up another thread to handle the event stream, which will then
/// be buffered in a mpsc queue, which will eventually be read by the current thread.
///
/// This will not read the piped standard input, but rather read from the TTY device, since reading
/// asyncronized from piped input would rarely make sense. In other words, if you pipe standard
/// output from another process, it won't be reflected in the stream returned by this function, as
/// this represents the TTY device, and not the piped standard input.
pub fn async_stdin() -> AsyncReader {
    let (send, recv) = mpsc::channel();

    thread::spawn(move || {
        for i in tty::get_tty().unwrap().bytes() {
            if send.send(i).is_err() {
                return;
            }
        }
    });

    AsyncReader {
        recv: recv,
    }
}

/// An asynchronous reader.
///
/// This acts as any other stream, with the exception that reading from it won't block. Instead,
/// the buffer will only be partially updated based on how much the internal buffer holds.
pub struct AsyncReader {
    /// The underlying mpsc receiver.
    recv: mpsc::Receiver<io::Result<u8>>,
}

// FIXME: Allow constructing an async reader from an arbitrary stream.

impl Read for AsyncReader {
    /// Read from the byte stream.
    ///
    /// This will never block, but try to drain the event queue until empty. If the total number of
    /// bytes written is lower than the buffer's length, the event queue is empty or that the event
    /// stream halted.
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let mut total = 0;

        loop {
            match self.recv.try_recv() {
                Ok(Ok(b)) => {
                    buf[total] = b;
                    total += 1;

                    if total == buf.len() {
                        break;
                    }
                },
                Ok(Err(e)) => return Err(e),
                Err(_) => break,
            }
        }

        Ok(total)
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::io::Read;

    #[test]
    fn test_async_stdin() {
        let stdin = async_stdin();
        stdin.bytes().next();
    }
}
<commit_msg>Protects AsyncReader::read against empty buffer. (#65)<commit_after>use std::io::{self, Read};
use std::sync::mpsc;
use std::thread;

use tty;

/// Construct an asynchronous handle to the TTY standard input.
///
/// This allows you to read from standard input _without blocking_ the current thread.
/// Specifically, it works by firing up another thread to handle the event stream, which will then
/// be buffered in a mpsc queue, which will eventually be read by the current thread.
///
/// This will not read the piped standard input, but rather read from the TTY device, since reading
/// asyncronized from piped input would rarely make sense. In other words, if you pipe standard
/// output from another process, it won't be reflected in the stream returned by this function, as
/// this represents the TTY device, and not the piped standard input.
pub fn async_stdin() -> AsyncReader {
    let (send, recv) = mpsc::channel();

    thread::spawn(move || {
        for i in tty::get_tty().unwrap().bytes() {
            if send.send(i).is_err() {
                return;
            }
        }
    });

    AsyncReader {
        recv: recv,
    }
}

/// An asynchronous reader.
///
/// This acts as any other stream, with the exception that reading from it won't block. Instead,
/// the buffer will only be partially updated based on how much the internal buffer holds.
pub struct AsyncReader {
    /// The underlying mpsc receiver.
    recv: mpsc::Receiver<io::Result<u8>>,
}

// FIXME: Allow constructing an async reader from an arbitrary stream.

impl Read for AsyncReader {
    /// Read from the byte stream.
    ///
    /// This will never block, but try to drain the event queue until empty. If the total number of
    /// bytes written is lower than the buffer's length, the event queue is empty or that the event
    /// stream halted.
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let mut total = 0;

        loop {
            if total >= buf.len() {
                break;
            }

            match self.recv.try_recv() {
                Ok(Ok(b)) => {
                    buf[total] = b;
                    total += 1;
                },
                Ok(Err(e)) => return Err(e),
                Err(_) => break,
            }
        }

        Ok(total)
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::io::Read;

    #[test]
    fn test_async_stdin() {
        let stdin = async_stdin();
        stdin.bytes().next();
    }
}
<|endoftext|>


<commit_before>use core::*;

#[derive(Debug, PartialEq, Clone)]
pub struct Board {
    pieces: [Bitboard;12],
    occupied: [Bitboard;2],
    unoccupied: Bitboard,
}

impl Board {
    pub fn starting_position() -> Board {
        return Board {
            pieces: [ Bitboard::new(0x000000000000FF00), Bitboard::new(71776119061217280),
                      Bitboard::new(0x0000000000000042), Bitboard::new(0x4200000000000000),
                      Bitboard::new(0x0000000000000024), Bitboard::new(0x2400000000000000),
                      Bitboard::new(0x0000000000000081), Bitboard::new(0x8100000000000000),
                      Bitboard::new(0x0000000000000008), Bitboard::new(0x0800000000000000),
                      Bitboard::new(0x0000000000000010), Bitboard::new(0x1000000000000000)],
            occupied: [ Bitboard::new(0x000000000000FFFF), Bitboard::new(0xFFFF000000000000) ],
            unoccupied: Bitboard::new(0x0000FFFFFFFF0000)
        }
    }

    pub fn get_pieces(&self, color: Color, ptype: PieceType) -> Bitboard {
        let idx = 2 * ptype as usize + color as usize;
        return self.pieces[idx];
    }

    pub fn occupied_by(&self, color: Color) -> Bitboard {
        return self.occupied[color as usize];
    }

    pub fn occupied(&self) -> Bitboard {
        return self.occupied[0] | self.occupied[1];
    }

    pub fn unoccupied(&self) -> Bitboard {
        return self.unoccupied;
    }

    // pub fn update(&mut self, color: Color, ptype: PieceType, newBB: Bitboard) {
    //     let idx = 2 * (ptype as usize) + (color as usize);
    //     self.0[idx] = newBB;
    // }

    pub fn color_at(&self, sq: Square) -> Option<Color> {
        let bit = sq.bitrep();

        if (bit & self.occupied()).empty() { return None }

        if (bit & self.occupied_by(Color::White)).nonempty() {
            return Some(Color::White);
        } else {
            return Some(Color::Black);
        };
    }

    pub fn piece_at(&self, sq: Square) -> Option<Piece> {

        match self.color_at(sq) {
            None => return None,
            Some(col) => {
                let bit = sq.bitrep();
                for pt in PieceType::all() {
                    if (bit & self.get_pieces(col, *pt)).nonempty() {
                        return Some(Piece { ptype: *pt, color: col });
                    }
                }
            }
        }

        //TODO: Warning
        return None;
    }

    pub fn get_king_square(&self, color: Color) -> Square {
        self.get_pieces(color, PieceType::King).bitscan_forward()
    }

    pub fn is_square_attacked_by(&self, square: Square, color: Color) -> bool {
        return false;
    }

}
<commit_msg>added function to test if square on board is attacked by any piece of a specific color<commit_after>use core::*;
use tables::*;

#[derive(Debug, PartialEq, Clone)]
pub struct Board {
    pieces: [Bitboard;12],
    occupied: [Bitboard;2],
    unoccupied: Bitboard,
}

impl Board {
    pub fn starting_position() -> Board {
        return Board {
            pieces: [ Bitboard::new(0x000000000000FF00), Bitboard::new(71776119061217280),
                      Bitboard::new(0x0000000000000042), Bitboard::new(0x4200000000000000),
                      Bitboard::new(0x0000000000000024), Bitboard::new(0x2400000000000000),
                      Bitboard::new(0x0000000000000081), Bitboard::new(0x8100000000000000),
                      Bitboard::new(0x0000000000000008), Bitboard::new(0x0800000000000000),
                      Bitboard::new(0x0000000000000010), Bitboard::new(0x1000000000000000)],
            occupied: [ Bitboard::new(0x000000000000FFFF), Bitboard::new(0xFFFF000000000000) ],
            unoccupied: Bitboard::new(0x0000FFFFFFFF0000)
        }
    }

    pub fn get_pieces(&self, color: Color, ptype: PieceType) -> Bitboard {
        let idx = 2 * ptype as usize + color as usize;
        return self.pieces[idx];
    }

    pub fn occupied_by(&self, color: Color) -> Bitboard {
        return self.occupied[color as usize];
    }

    pub fn occupied(&self) -> Bitboard {
        return self.occupied[0] | self.occupied[1];
    }

    pub fn unoccupied(&self) -> Bitboard {
        return self.unoccupied;
    }

    // pub fn update(&mut self, color: Color, ptype: PieceType, newBB: Bitboard) {
    //     let idx = 2 * (ptype as usize) + (color as usize);
    //     self.0[idx] = newBB;
    // }

    pub fn color_at(&self, sq: Square) -> Option<Color> {
        let bit = sq.bitrep();

        if (bit & self.occupied()).empty() { return None }

        if (bit & self.occupied_by(Color::White)).nonempty() {
            return Some(Color::White);
        } else {
            return Some(Color::Black);
        };
    }

    pub fn piece_at(&self, sq: Square) -> Option<Piece> {

        match self.color_at(sq) {
            None => return None,
            Some(col) => {
                let bit = sq.bitrep();
                for pt in PieceType::all() {
                    if (bit & self.get_pieces(col, *pt)).nonempty() {
                        return Some(Piece { ptype: *pt, color: col });
                    }
                }
            }
        }

        //TODO: Warning
        return None;
    }

    pub fn get_king_square(&self, color: Color) -> Square {
        self.get_pieces(color, PieceType::King).bitscan_forward()
    }

    pub fn is_square_attacked_by(&self, square: Square, color: Color) -> bool {

        use PieceType::*;

        if (PAWN_ATTACKS[!color as usize][square.idx()] & self.get_pieces(color, Pawn)).nonempty() {
            return true;
        } else if (KNIGHT_TABLE[square.idx()] & self.get_pieces(color, Knight)).nonempty() {
            return true;
        } else if (KING_TABLE[square.idx()] & self.get_pieces(color, King)).nonempty() {
            return true;
        }

        let occupied = self.occupied();

        let bishops_queens = self.get_pieces(color, Queen) | self.get_pieces(color, Bishop);
        if (get_bishop_rays(square, occupied) & bishops_queens).nonempty() {
            return true;
        }

        let rooks_queens = self.get_pieces(color, Queen) | self.get_pieces(color, Rook);
        if (get_rook_rays(square, occupied) & rooks_queens).nonempty() {
            return true;
        }

        return false;
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::ffi::OsString;
use std::fs::File;
use std::fs;
use std::env;
use std::os::unix::fs::PermissionsExt;
use std::io::{Write,BufReader};
use std::io::BufRead;
use std::process::Command;
use std::path::Path;

const SNAPPY_VERSION: &'static str  = "1.1.2";
const LEVELDB_VERSION: &'static str = "1.18";

fn build_snappy(is_freebsd: bool) {
    // Step 1: Build snappy
    // ----------------------------------------------------------------------
    let snappy_path = Path::new("deps")
                           .join(format!("snappy-{}", SNAPPY_VERSION));
    let make = if is_freebsd { "gmake" } else { "make" };

    // Clean the build directory first.
    println!("[snappy] Cleaning");
    Command::new(make).args(&["-C", snappy_path.to_str().unwrap()])
                        .arg("distclean")
                        .status().ok().expect("make distclean failed");

    // Configure the build
    println!("[snappy] Configuring");
    Command::new("./configure").current_dir(&snappy_path)
                               .arg("--disable-shared")
                               .status().ok().expect("configure failed");

    // Call "make" to build the C library
    println!("[snappy] Building");
    Command::new(make).args(&["-C", snappy_path.to_str().unwrap()])
                        .status().ok().expect("make failed");

    // Step 2: Copy to output directories
    // ----------------------------------------------------------------------
    let env_var = &env::var("OUT_DIR").unwrap();
    let out_dir = Path::new(env_var);

    println!("[build] Copying output files");
    let res = fs::copy(&snappy_path.join(".libs").join("libsnappy.a"), &out_dir.join("libsnappy.a"));
    res.ok().expect("copy of output files failed");
}

fn build_leveldb(with_snappy: bool, is_freebsd: bool) {
    // Step 1: Build LevelDB
    // ----------------------------------------------------------------------
    let leveldb_path = Path::new("deps")
                            .join(format!("leveldb-{}", LEVELDB_VERSION));
    let make = if is_freebsd { "gmake" } else { "make" };

    // Clean the build directory first.
    println!("[leveldb] Cleaning");
    Command::new(make).args(&["-C", leveldb_path.to_str().unwrap()])
                        .arg("clean")
                        .status().ok().expect("clean failed");

    // Set up the process environment.  We essentially clone the existing
    // environment, and, if we're including Snappy, also include the appropriate
    // CXXFLAGS and LDFLAGS variables.
    let mut env_map: HashMap<OsString, OsString> = env::vars().map(|(k, v)| {
        (
            k.into(),
            v.into()
        )
    }).collect();

    if with_snappy {
        let linker_path = env::var("OUT_DIR").unwrap();
        env_map.insert(
            "LDFLAGS".into(),
            format!("-L{}", linker_path).into()
        );

        let snappy_path = Path::new("deps")
                               .join(format!("snappy-{}", SNAPPY_VERSION));
        env_map.insert(
            "CXXFLAGS".into(),
            format!("-I{} -fPIC", snappy_path.to_str().unwrap()).into()
        );
    } else {
        env_map.insert(
            "CXXFLAGS".into(),
            format!("-fPIC").into()
        );
    }

    let mut cmd = Command::new(make);

    println!("[leveldb] Building command");

    // Convert to the format that `env_set_all` is expecting.
    for (k,v) in env_map.into_iter() {
        cmd.env(k,v);
    }

    let path_arg = leveldb_path.to_str().expect("leveldb path is not a string");

    // Build the library
    println!("[leveldb] Building");
    cmd.args(&["-C", path_arg])
       .status().ok().expect("leveldb build failed");

    println!("[leveldb] Build finished");
    // Step 2: Copy to output directories
    // ----------------------------------------------------------------------
    let env_var = &env::var("OUT_DIR").unwrap();
    let out_dir = Path::new(env_var);

    println!("[build] Copying output files");
    let res = fs::copy(&leveldb_path.join("libleveldb.a"), &out_dir.join("libleveldb.a"));
    res.ok().expect("copy of output files failed");
}

fn main() {
    println!("[build] Started");

    let have_snappy = env::var("CARGO_FEATURE_SNAPPY").is_ok();
    let is_freebsd = env::var("TARGET").unwrap().ends_with("freebsd");

    // If we have the appropriate feature, then we build snappy.
    if have_snappy {
        build_snappy(is_freebsd);
    }

    // Copy the build_detect_platform file into the appropriate place.
    let template_path = Path::new("deps")
                             .join("build_detect_platform");
    let detect_path = Path::new("deps")
                           .join(format!("leveldb-{}", LEVELDB_VERSION))
                           .join("build_detect_platform");
    if have_snappy {
        println!("[build] Copying the `build_detect_platform` template");
        fs::copy(&template_path, &detect_path).unwrap();
    } else {
        println!("[build] Patching the `build_detect_platform` template");

        // If we aren't using snappy, remove the lines from
        // build_detect_platform that enable Snappy.  This prevents us from
        // picking up a system-local copy of Snappy.
        let new_lines: Vec<String> = {
            let file = File::open(&template_path).unwrap();
            let reader = BufReader::new(file);

            reader.lines().map(|line| {
                let line = line.unwrap();
                if line.contains("-DSNAPPY") || line.contains("-lsnappy") {
                    let mut tmp = String::new();
                    tmp.push_str("true   #");
                    tmp.push_str(line.as_ref());
                    tmp.push_str("\n");
                    tmp
                } else {
                    line
                }
            }).collect()
        };

        let mut f = File::create(&detect_path).unwrap();
        for line in new_lines.iter() {
            f.write_all(line.as_ref()).ok().expect("writing a line failed");
            f.write_all("\n".as_bytes()).ok().expect("writing a line failed");
        }

        println!("[build] Patching complete");
    }

    // Set executable bits on the file

    let mut perms = fs::metadata(&detect_path).ok().expect("metadata missing").permissions();
    let current_mode = perms.mode();
    perms.set_mode(0o100 | current_mode);
    fs::set_permissions(&detect_path, perms).ok().expect("permissions could not be set");

    // Build LevelDB
    build_leveldb(have_snappy, is_freebsd);

    // Print the appropriate linker flags
    let out_dir = env::var("OUT_DIR").ok().expect("OUT_DIR missing");
    let linker_flags = if have_snappy {
        "-l static=snappy -l static=leveldb"
    } else {
        "-l static=leveldb"
    };
    println!("cargo:rustc-flags=-L native={} {}", out_dir, linker_flags);

    let target = env::var("TARGET").unwrap();
    if target.contains("apple") {
        println!("cargo:rustc-link-lib=c++");
    } else if target.contains("gnu") {
        println!("cargo:rustc-link-lib=stdc++");
    }

    println!("[build] Finished");
}
<commit_msg>Relax TARGET check to support all BSD<commit_after>use std::collections::HashMap;
use std::ffi::OsString;
use std::fs::File;
use std::fs;
use std::env;
use std::os::unix::fs::PermissionsExt;
use std::io::{Write,BufReader};
use std::io::BufRead;
use std::process::Command;
use std::path::Path;

const SNAPPY_VERSION: &'static str  = "1.1.2";
const LEVELDB_VERSION: &'static str = "1.18";

fn build_snappy(is_bsd: bool) {
    // Step 1: Build snappy
    // ----------------------------------------------------------------------
    let snappy_path = Path::new("deps")
                           .join(format!("snappy-{}", SNAPPY_VERSION));
    let make = if is_bsd { "gmake" } else { "make" };

    // Clean the build directory first.
    println!("[snappy] Cleaning");
    Command::new(make).args(&["-C", snappy_path.to_str().unwrap()])
                        .arg("distclean")
                        .status().ok().expect("make distclean failed");

    // Configure the build
    println!("[snappy] Configuring");
    Command::new("./configure").current_dir(&snappy_path)
                               .arg("--disable-shared")
                               .status().ok().expect("configure failed");

    // Call "make" to build the C library
    println!("[snappy] Building");
    Command::new(make).args(&["-C", snappy_path.to_str().unwrap()])
                        .status().ok().expect("make failed");

    // Step 2: Copy to output directories
    // ----------------------------------------------------------------------
    let env_var = &env::var("OUT_DIR").unwrap();
    let out_dir = Path::new(env_var);

    println!("[build] Copying output files");
    let res = fs::copy(&snappy_path.join(".libs").join("libsnappy.a"), &out_dir.join("libsnappy.a"));
    res.ok().expect("copy of output files failed");
}

fn build_leveldb(with_snappy: bool, is_bsd: bool) {
    // Step 1: Build LevelDB
    // ----------------------------------------------------------------------
    let leveldb_path = Path::new("deps")
                            .join(format!("leveldb-{}", LEVELDB_VERSION));
    let make = if is_bsd { "gmake" } else { "make" };

    // Clean the build directory first.
    println!("[leveldb] Cleaning");
    Command::new(make).args(&["-C", leveldb_path.to_str().unwrap()])
                        .arg("clean")
                        .status().ok().expect("clean failed");

    // Set up the process environment.  We essentially clone the existing
    // environment, and, if we're including Snappy, also include the appropriate
    // CXXFLAGS and LDFLAGS variables.
    let mut env_map: HashMap<OsString, OsString> = env::vars().map(|(k, v)| {
        (
            k.into(),
            v.into()
        )
    }).collect();

    if with_snappy {
        let linker_path = env::var("OUT_DIR").unwrap();
        env_map.insert(
            "LDFLAGS".into(),
            format!("-L{}", linker_path).into()
        );

        let snappy_path = Path::new("deps")
                               .join(format!("snappy-{}", SNAPPY_VERSION));
        env_map.insert(
            "CXXFLAGS".into(),
            format!("-I{} -fPIC", snappy_path.to_str().unwrap()).into()
        );
    } else {
        env_map.insert(
            "CXXFLAGS".into(),
            format!("-fPIC").into()
        );
    }

    let mut cmd = Command::new(make);

    println!("[leveldb] Building command");

    // Convert to the format that `env_set_all` is expecting.
    for (k,v) in env_map.into_iter() {
        cmd.env(k,v);
    }

    let path_arg = leveldb_path.to_str().expect("leveldb path is not a string");

    // Build the library
    println!("[leveldb] Building");
    cmd.args(&["-C", path_arg])
       .status().ok().expect("leveldb build failed");

    println!("[leveldb] Build finished");
    // Step 2: Copy to output directories
    // ----------------------------------------------------------------------
    let env_var = &env::var("OUT_DIR").unwrap();
    let out_dir = Path::new(env_var);

    println!("[build] Copying output files");
    let res = fs::copy(&leveldb_path.join("libleveldb.a"), &out_dir.join("libleveldb.a"));
    res.ok().expect("copy of output files failed");
}

fn main() {
    println!("[build] Started");

    let have_snappy = env::var("CARGO_FEATURE_SNAPPY").is_ok();
    let is_bsd = env::var("TARGET").unwrap().ends_with("bsd");

    // If we have the appropriate feature, then we build snappy.
    if have_snappy {
        build_snappy(is_bsd);
    }

    // Copy the build_detect_platform file into the appropriate place.
    let template_path = Path::new("deps")
                             .join("build_detect_platform");
    let detect_path = Path::new("deps")
                           .join(format!("leveldb-{}", LEVELDB_VERSION))
                           .join("build_detect_platform");
    if have_snappy {
        println!("[build] Copying the `build_detect_platform` template");
        fs::copy(&template_path, &detect_path).unwrap();
    } else {
        println!("[build] Patching the `build_detect_platform` template");

        // If we aren't using snappy, remove the lines from
        // build_detect_platform that enable Snappy.  This prevents us from
        // picking up a system-local copy of Snappy.
        let new_lines: Vec<String> = {
            let file = File::open(&template_path).unwrap();
            let reader = BufReader::new(file);

            reader.lines().map(|line| {
                let line = line.unwrap();
                if line.contains("-DSNAPPY") || line.contains("-lsnappy") {
                    let mut tmp = String::new();
                    tmp.push_str("true   #");
                    tmp.push_str(line.as_ref());
                    tmp.push_str("\n");
                    tmp
                } else {
                    line
                }
            }).collect()
        };

        let mut f = File::create(&detect_path).unwrap();
        for line in new_lines.iter() {
            f.write_all(line.as_ref()).ok().expect("writing a line failed");
            f.write_all("\n".as_bytes()).ok().expect("writing a line failed");
        }

        println!("[build] Patching complete");
    }

    // Set executable bits on the file

    let mut perms = fs::metadata(&detect_path).ok().expect("metadata missing").permissions();
    let current_mode = perms.mode();
    perms.set_mode(0o100 | current_mode);
    fs::set_permissions(&detect_path, perms).ok().expect("permissions could not be set");

    // Build LevelDB
    build_leveldb(have_snappy, is_bsd);

    // Print the appropriate linker flags
    let out_dir = env::var("OUT_DIR").ok().expect("OUT_DIR missing");
    let linker_flags = if have_snappy {
        "-l static=snappy -l static=leveldb"
    } else {
        "-l static=leveldb"
    };
    println!("cargo:rustc-flags=-L native={} {}", out_dir, linker_flags);

    let target = env::var("TARGET").unwrap();
    if target.contains("apple") {
        println!("cargo:rustc-link-lib=c++");
    } else if target.contains("gnu") {
        println!("cargo:rustc-link-lib=stdc++");
    }

    println!("[build] Finished");
}
<|endoftext|>


<commit_before>use nalgebra;
use num::Num;
use std::cmp;
use std::convert::From;
use std::marker::PhantomData;
use std::ops;

use math::Clamp;

pub trait ClampedRange<T> {
    fn max_value() -> T;
    fn min_value() -> T;
}

pub struct Clamped<T, R>(T, PhantomData<R>)
    where T: Copy + Num + cmp::PartialOrd,
          R: ClampedRange<T>;

impl<T, R> Clamped<T, R>
    where T: Copy + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    pub fn new(value: T) -> Self {
        Clamped(nalgebra::clamp(value, R::min_value(), R::max_value()),
                PhantomData)
    }

    pub fn max_value() -> Self {
        Clamped(R::max_value(), PhantomData)
    }

    pub fn max_inner_value() -> T {
        R::max_value()
    }

    pub fn min_value() -> Self {
        Clamped(R::min_value(), PhantomData)
    }

    pub fn min_inner_value() -> T {
        R::min_value()
    }

    pub fn to_inner(&self) -> T {
        self.0
    }
}

impl<T, R> Clamp<Clamped<T, R>> for Clamped<T, R>
    where T: Copy + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    fn clamp(&self, min: Self, max: Self) -> Self {
        nalgebra::clamp(*self, min, max)
    }
}

impl<T, R> Clone for Clamped<T, R>
    where T: Copy + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    fn clone(&self) -> Self {
        Clamped(self.0, PhantomData)
    }
}

impl<T, R> Copy for Clamped<T, R>
    where T: Copy + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
}

impl<T, R> From<T> for Clamped<T, R>
    where T: Copy + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    fn from(value: T) -> Self {
        Self::new(value)
    }
}

impl<T, R> cmp::Eq for Clamped<T, R>
    where T: Copy + cmp::Eq + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
}

impl<T, R> cmp::Ord for Clamped<T, R>
    where T: Copy + Num + cmp::Ord + cmp::PartialOrd,
          R: ClampedRange<T>
{
    fn cmp(&self, other: &Self) -> cmp::Ordering {
        self.0.cmp(&other.0)
    }
}

impl<T, R> cmp::PartialEq for Clamped<T, R>
    where T: Copy + Num + cmp::PartialEq + cmp::PartialOrd,
          R: ClampedRange<T>
{
    fn eq(&self, other: &Self) -> bool {
        self.0.eq(&other.0)
    }
}

impl<T, R> cmp::PartialEq<T> for Clamped<T, R>
    where T: Copy + Num + cmp::PartialEq + cmp::PartialOrd,
          R: ClampedRange<T>
{
    fn eq(&self, other: &T) -> bool {
        self.0.eq(other)
    }
}

impl<T, R> cmp::PartialOrd for Clamped<T, R>
    where T: Copy + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
        self.0.partial_cmp(&other.0)
    }
}

impl<T, R> cmp::PartialOrd<T> for Clamped<T, R>
    where T: Copy + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    fn partial_cmp(&self, other: &T) -> Option<cmp::Ordering> {
        self.0.partial_cmp(other)
    }
}

impl<T, R> ops::Add for Clamped<T, R>
    where T: ops::Add<Output = T> + Copy + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    type Output = Self;

    fn add(self, other: Self) -> Self::Output {
        Self::new(self.0.add(other.0))
    }
}

impl<T, R> ops::Add<T> for Clamped<T, R>
    where T: ops::Add<Output = T> + Copy + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    type Output = Self;

    fn add(self, other: T) -> Self::Output {
        Self::new(self.0.add(other))
    }
}

impl<T, R> ops::Deref for Clamped<T, R>
    where T: Copy + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl<T, R> ops::Div for Clamped<T, R>
    where T: Copy + ops::Div<Output = T> + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    type Output = Self;

    fn div(self, other: Self) -> Self::Output {
        Self::new(self.0.div(other.0))
    }
}

impl<T, R> ops::Div<T> for Clamped<T, R>
    where T: Copy + ops::Div<Output = T> + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    type Output = Self;

    fn div(self, other: T) -> Self::Output {
        Self::new(self.0.div(other))
    }
}

impl<T, R> ops::Mul for Clamped<T, R>
    where T: Copy + ops::Mul<Output = T> + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    type Output = Self;

    fn mul(self, other: Self) -> Self::Output {
        Self::new(self.0.mul(other.0))
    }
}

impl<T, R> ops::Mul<T> for Clamped<T, R>
    where T: Copy + ops::Mul<Output = T> + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    type Output = Self;

    fn mul(self, other: T) -> Self::Output {
        Self::new(self.0.mul(other))
    }
}

impl<T, R> ops::Neg for Clamped<T, R>
    where T: Copy + ops::Neg<Output = T> + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    type Output = Self;

    fn neg(self) -> Self::Output {
        Self::new(self.0.neg())
    }
}

impl<T, R> ops::Sub for Clamped<T, R>
    where T: Copy + Num + ops::Sub<Output = T> + cmp::PartialOrd,
          R: ClampedRange<T>
{
    type Output = Self;

    fn sub(self, other: Self) -> Self::Output {
        Self::new(self.0.sub(other.0))
    }
}

impl<T, R> ops::Sub<T> for Clamped<T, R>
    where T: Copy + Num + ops::Sub<Output = T> + cmp::PartialOrd,
          R: ClampedRange<T>
{
    type Output = Self;

    fn sub(self, other: T) -> Self::Output {
        Self::new(self.0.sub(other))
    }
}
<commit_msg>Remove unneeded `cmp` module prefixes.<commit_after>use nalgebra;
use num::Num;
use std::cmp::Ordering;
use std::convert::From;
use std::marker::PhantomData;
use std::ops;

use math::Clamp;

pub trait ClampedRange<T> {
    fn max_value() -> T;
    fn min_value() -> T;
}

pub struct Clamped<T, R>(T, PhantomData<R>)
    where T: Copy + Num + PartialOrd,
          R: ClampedRange<T>;

impl<T, R> Clamped<T, R>
    where T: Copy + Num + PartialOrd,
          R: ClampedRange<T>
{
    pub fn new(value: T) -> Self {
        Clamped(nalgebra::clamp(value, R::min_value(), R::max_value()),
                PhantomData)
    }

    pub fn max_value() -> Self {
        Clamped(R::max_value(), PhantomData)
    }

    pub fn max_inner_value() -> T {
        R::max_value()
    }

    pub fn min_value() -> Self {
        Clamped(R::min_value(), PhantomData)
    }

    pub fn min_inner_value() -> T {
        R::min_value()
    }

    pub fn to_inner(&self) -> T {
        self.0
    }
}

impl<T, R> Clamp<Clamped<T, R>> for Clamped<T, R>
    where T: Copy + Num + PartialOrd,
          R: ClampedRange<T>
{
    fn clamp(&self, min: Self, max: Self) -> Self {
        nalgebra::clamp(*self, min, max)
    }
}

impl<T, R> Clone for Clamped<T, R>
    where T: Copy + Num + PartialOrd,
          R: ClampedRange<T>
{
    fn clone(&self) -> Self {
        Clamped(self.0, PhantomData)
    }
}

impl<T, R> Copy for Clamped<T, R>
    where T: Copy + Num + PartialOrd,
          R: ClampedRange<T>
{
}

impl<T, R> From<T> for Clamped<T, R>
    where T: Copy + Num + PartialOrd,
          R: ClampedRange<T>
{
    fn from(value: T) -> Self {
        Self::new(value)
    }
}

impl<T, R> Eq for Clamped<T, R>
    where T: Copy + Eq + Num + PartialOrd,
          R: ClampedRange<T>
{
}

impl<T, R> Ord for Clamped<T, R>
    where T: Copy + Num + Ord + PartialOrd,
          R: ClampedRange<T>
{
    fn cmp(&self, other: &Self) -> Ordering {
        self.0.cmp(&other.0)
    }
}

impl<T, R> PartialEq for Clamped<T, R>
    where T: Copy + Num + PartialEq + PartialOrd,
          R: ClampedRange<T>
{
    fn eq(&self, other: &Self) -> bool {
        self.0.eq(&other.0)
    }
}

impl<T, R> PartialEq<T> for Clamped<T, R>
    where T: Copy + Num + PartialEq + PartialOrd,
          R: ClampedRange<T>
{
    fn eq(&self, other: &T) -> bool {
        self.0.eq(other)
    }
}

impl<T, R> PartialOrd for Clamped<T, R>
    where T: Copy + Num + PartialOrd,
          R: ClampedRange<T>
{
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.0.partial_cmp(&other.0)
    }
}

impl<T, R> PartialOrd<T> for Clamped<T, R>
    where T: Copy + Num + PartialOrd,
          R: ClampedRange<T>
{
    fn partial_cmp(&self, other: &T) -> Option<Ordering> {
        self.0.partial_cmp(other)
    }
}

impl<T, R> ops::Add for Clamped<T, R>
    where T: ops::Add<Output = T> + Copy + Num + PartialOrd,
          R: ClampedRange<T>
{
    type Output = Self;

    fn add(self, other: Self) -> Self::Output {
        Self::new(self.0.add(other.0))
    }
}

impl<T, R> ops::Add<T> for Clamped<T, R>
    where T: ops::Add<Output = T> + Copy + Num + PartialOrd,
          R: ClampedRange<T>
{
    type Output = Self;

    fn add(self, other: T) -> Self::Output {
        Self::new(self.0.add(other))
    }
}

impl<T, R> ops::Deref for Clamped<T, R>
    where T: Copy + Num + PartialOrd,
          R: ClampedRange<T>
{
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl<T, R> ops::Div for Clamped<T, R>
    where T: Copy + ops::Div<Output = T> + Num + PartialOrd,
          R: ClampedRange<T>
{
    type Output = Self;

    fn div(self, other: Self) -> Self::Output {
        Self::new(self.0.div(other.0))
    }
}

impl<T, R> ops::Div<T> for Clamped<T, R>
    where T: Copy + ops::Div<Output = T> + Num + PartialOrd,
          R: ClampedRange<T>
{
    type Output = Self;

    fn div(self, other: T) -> Self::Output {
        Self::new(self.0.div(other))
    }
}

impl<T, R> ops::Mul for Clamped<T, R>
    where T: Copy + ops::Mul<Output = T> + Num + PartialOrd,
          R: ClampedRange<T>
{
    type Output = Self;

    fn mul(self, other: Self) -> Self::Output {
        Self::new(self.0.mul(other.0))
    }
}

impl<T, R> ops::Mul<T> for Clamped<T, R>
    where T: Copy + ops::Mul<Output = T> + Num + PartialOrd,
          R: ClampedRange<T>
{
    type Output = Self;

    fn mul(self, other: T) -> Self::Output {
        Self::new(self.0.mul(other))
    }
}

impl<T, R> ops::Neg for Clamped<T, R>
    where T: Copy + ops::Neg<Output = T> + Num + PartialOrd,
          R: ClampedRange<T>
{
    type Output = Self;

    fn neg(self) -> Self::Output {
        Self::new(self.0.neg())
    }
}

impl<T, R> ops::Sub for Clamped<T, R>
    where T: Copy + Num + ops::Sub<Output = T> + PartialOrd,
          R: ClampedRange<T>
{
    type Output = Self;

    fn sub(self, other: Self) -> Self::Output {
        Self::new(self.0.sub(other.0))
    }
}

impl<T, R> ops::Sub<T> for Clamped<T, R>
    where T: Copy + Num + ops::Sub<Output = T> + PartialOrd,
          R: ClampedRange<T>
{
    type Output = Self;

    fn sub(self, other: T) -> Self::Output {
        Self::new(self.0.sub(other))
    }
}
<|endoftext|>


<commit_before>extern crate ocl;
#[allow(non_camel_case_types)]
#[allow(non_upper_case_globals)]
#[allow(non_snake_case)]
pub mod ffi;
use std::mem;
pub use ffi::clfftSetupData;

macro_rules! clfft_try {
    ( $result_expr: expr) => {
        let result = $result_expr;
        if result != ffi::clfftStatus::CLFFT_SUCCESS {
            let error_code: i32 = unsafe { mem::transmute(result) };
            return ocl::Error::err(format!("FOREIGN_CLFFT_ERROR {}\nSee http://clmathlibraries.github.io/clFFT/clFFT_8h.html#a74e303bed132064cfa22c1cce96d2bce for further information", error_code));
        }
    }
}

macro_rules! clfft_panic {
    ( $result_expr: expr) => {
        let result = $result_expr;
        if result != ffi::clfftStatus::CLFFT_SUCCESS {
            panic!("Unexpeced error in foreign library: {:?}", result);
        }
    }
}

/// Initialize the internal FFT resources such as FFT implementation caches kernels, programs, and buffers.
pub fn init_lib() -> ffi::clfftSetupData {
    let mut major: ocl::ffi::cl_uint = 0;
    let mut minor: ocl::ffi::cl_uint = 0;
    let mut patch: ocl::ffi::cl_uint = 0;
    clfft_panic!( unsafe { ffi::clfftGetVersion(&mut major, &mut minor, &mut patch) } );
    let data = ffi::clfftSetupData {
        major: major,
        minor: minor,
        patch: patch,
        debugFlags: 0,
    };

    clfft_panic!(unsafe { ffi::clfftSetup(&data) });
    data
}

/// Release all internal resources acquired during `init_lib`.
pub fn drop_lib() {
    unsafe { ffi::clfftTeardown() };
}

fn translate_to_fft_dim(dims: ocl::SpatialDims) -> ffi::clfftDim {
    match dims.dim_count() {
        1 => ffi::clfftDim::CLFFT_1D,
        2 => ffi::clfftDim::CLFFT_2D,
        3 => ffi::clfftDim::CLFFT_3D,
        n => panic!("Number of dimensions must be 1, 2 or 3, but it is {}", n)
    }
}

pub struct FftPlanBuilder {
    handle: ffi::clfftPlanHandle
}

/// Specify the expected precision of each FFT.
pub enum Precision {
    Single,
    Double,
    SingleFast,
    DoubleFast
}

fn translate_precision(precision: Precision) -> ffi::clfftPrecision {
    match precision {
        Precision::Single => ffi::clfftPrecision::CLFFT_SINGLE,
        Precision::Double => ffi::clfftPrecision::CLFFT_DOUBLE,
        Precision::SingleFast => ffi::clfftPrecision::CLFFT_SINGLE_FAST,
        Precision::DoubleFast => ffi::clfftPrecision::CLFFT_DOUBLE_FAST
    }
}

fn translate_precision_back(precision: ffi::clfftPrecision) -> Precision {
    match precision {
        ffi::clfftPrecision::CLFFT_SINGLE => Precision::Single,
        ffi::clfftPrecision::CLFFT_DOUBLE => Precision::Double,
        ffi::clfftPrecision::CLFFT_SINGLE_FAST => Precision::SingleFast,
        ffi::clfftPrecision::CLFFT_DOUBLE_FAST => Precision::DoubleFast,
        ffi::clfftPrecision::ENDPRECISION => panic!("ENDPRECISION should never be returned")
    }
}

/// Specify the expected layouts of the buffers.
pub enum Layout {
    ComplexInterleaved,
    ComplexPlanar,
    HermitianInterleaved,
    HermitianPlanar,
    Real
}

fn translate_layout(layout: Layout) -> ffi::clfftLayout {
    match layout {
        Layout::ComplexInterleaved => ffi::clfftLayout::CLFFT_COMPLEX_INTERLEAVED,
        Layout::ComplexPlanar => ffi::clfftLayout::CLFFT_COMPLEX_PLANAR,
        Layout::HermitianInterleaved => ffi::clfftLayout::CLFFT_HERMITIAN_INTERLEAVED,
        Layout::HermitianPlanar => ffi::clfftLayout::CLFFT_HERMITIAN_PLANAR,
        Layout::Real => ffi::clfftLayout::CLFFT_REAL
    }
}

fn translate_layout_back(layout: ffi::clfftLayout) -> Layout {
    match layout {
        ffi::clfftLayout::CLFFT_COMPLEX_INTERLEAVED => Layout::ComplexInterleaved,
        ffi::clfftLayout::CLFFT_COMPLEX_PLANAR => Layout::ComplexPlanar,
        ffi::clfftLayout::CLFFT_HERMITIAN_INTERLEAVED => Layout::HermitianInterleaved,
        ffi::clfftLayout::CLFFT_HERMITIAN_PLANAR => Layout::HermitianPlanar,
        ffi::clfftLayout::CLFFT_REAL => Layout::Real,
        ffi::clfftLayout::ENDLAYOUT => panic!("ENDLAYOUT should never be returned")
    }
}

/// Specify the expected direction of each FFT, time or the frequency domains
pub enum Direction {
    Forward,
    Backward
}

fn translate_direction(direction: Direction) -> ffi::clfftDirection {
    match direction {
        Direction::Forward => ffi::clfftDirection::CLFFT_FORWARD,
        Direction::Backward => ffi::clfftDirection::CLFFT_BACKWARD
    }
}

fn translate_direction_back(direction: ffi::clfftDirection) -> Direction {
    match direction {
        ffi::clfftDirection::CLFFT_FORWARD => Direction::Forward,
        ffi::clfftDirection::CLFFT_BACKWARD => Direction::Backward,
        ffi::clfftDirection::ENDDIRECTION => panic!("ENDDIRECTION should never be returned")
    }
}

/// pecify wheter the input buffers are overwritten with results
pub enum Location {
    Inplace,
    OutOfPlace
}

fn translate_location(location: Location) -> ffi::clfftResultLocation {
    match location {
        Location::Inplace => ffi::clfftResultLocation::CLFFT_INPLACE,
        Location::OutOfPlace => ffi::clfftResultLocation::CLFFT_OUTOFPLACE
    }
}

fn translate_location_back(location: ffi::clfftResultLocation) -> Location {
    match location {
        ffi::clfftResultLocation::CLFFT_INPLACE => Location::Inplace,
        ffi::clfftResultLocation::CLFFT_OUTOFPLACE => Location::OutOfPlace,
        ffi::clfftResultLocation::ENDPLACE => panic!("ENDPLACE should never be returned")
    }
}

impl FftPlanBuilder {
    /// Create a plan object initialized entirely with default values.
    ///
    /// A plan is a repository of state for calculating FFT's.  Allows the runtime to pre-calculate kernels, programs
    /// and buffers and associate them with buffers of specified dimensions.
    pub fn default<D: Into<ocl::SpatialDims>>(pro_que: &ocl::ProQue, dims: D)
        -> ocl::Result<FftPlanBuilder> {
        let context = unsafe { pro_que.context().core_as_ref().as_ptr() };
        let dims = dims.into();
        let dim = translate_to_fft_dim(dims);
        let lengths = try!(dims.to_lens());
        let mut plan: ffi::clfftPlanHandle = 0;
        clfft_try!( unsafe { ffi::clfftCreateDefaultPlan(&mut plan, context, dim, &lengths as *const usize) } );
        Ok(FftPlanBuilder {  handle: plan })
    }

    /// Returns the native clFFT plan handle.
    pub fn plan_handle(&self) -> ffi::clfftPlanHandle {
        self.handle
    }

    /// Set the floating point precision of the FFT data
    pub fn set_precision(&mut self, precision: Precision) -> ocl::Result<()> {
        let precision = translate_precision(precision);
        clfft_try!(unsafe { ffi::clfftSetPlanPrecision(self.handle, precision) });
        Ok(())
    }

    pub fn get_precision(&self) -> ocl::Result<Precision> {
        let mut precision = ffi::clfftPrecision::CLFFT_SINGLE;
        clfft_try!(unsafe { ffi::clfftGetPlanPrecision(self.handle, &mut precision) });
        Ok(translate_precision_back(precision))
    }

    /// Set the expected layout of the input and output buffers
    pub fn set_layout(&mut self, input_layout: Layout, output_layout: Layout) -> ocl::Result<()> {
        let input_layout = translate_layout(input_layout);
        let output_layout = translate_layout(output_layout);
        clfft_try!(unsafe { ffi::clfftSetLayout(self.handle, input_layout, output_layout) });
        Ok(())
    }

    pub fn get_layout(&self) -> ocl::Result<(Layout, Layout)> {
        let mut input_layout = ffi::clfftLayout::CLFFT_COMPLEX_INTERLEAVED;
        let mut output_layout = ffi::clfftLayout::CLFFT_COMPLEX_INTERLEAVED;
        clfft_try!(unsafe { ffi::clfftGetLayout(self.handle, &mut input_layout, &mut output_layout) });
        Ok((translate_layout_back(input_layout), translate_layout_back(output_layout)))
    }

    /// Set whether the input buffers are to be overwritten with results
    pub fn set_result_location(&mut self, location: Location) -> ocl::Result<()> {
        let location = translate_location(location);
        clfft_try!(unsafe { ffi::clfftSetResultLocation(self.handle, location) });
        Ok(())
    }

    pub fn get_result_location(&self) -> ocl::Result<Location> {
        let mut location = ffi::clfftResultLocation::CLFFT_INPLACE;
        clfft_try!(unsafe { ffi::clfftGetResultLocation(self.handle, &mut location) });
        Ok(translate_location_back(location))
    }
}

impl std::ops::Drop for FftPlanBuilder {
    fn drop(&mut self) {
        if self.handle != 0 {
            unsafe { ffi::clfftDestroyPlan(&mut self.handle) };
            self.handle = 0;
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use ocl::{ProQue};
    use ocl::builders::ProgramBuilder;

    #[test]
    pub fn fft_test() {
        init_lib();
        let prog_bldr = ProgramBuilder::new();
        let ocl_pq = ProQue::builder()
            .prog_bldr(prog_bldr)
            .build()
            .expect("Building ProQue");
        FftPlan::default(&ocl_pq, [1000]);
        drop_lib();
    }
}<commit_msg>Translated the clFFT example into a test, so far the test fails with a crash<commit_after>extern crate ocl;
#[allow(non_camel_case_types)]
#[allow(non_upper_case_globals)]
#[allow(non_snake_case)]
pub mod ffi;
use std::mem;
pub use ffi::clfftSetupData;

macro_rules! clfft_try {
    ( $result_expr: expr) => {
        let result = $result_expr;
        if result != ffi::clfftStatus::CLFFT_SUCCESS {
            let error_code: i32 = unsafe { mem::transmute(result) };
            return ocl::Error::err(format!("FOREIGN_CLFFT_ERROR {}\nSee http://clmathlibraries.github.io/clFFT/clFFT_8h.html#a74e303bed132064cfa22c1cce96d2bce for further information", error_code));
        }
    }
}

macro_rules! clfft_panic {
    ( $result_expr: expr) => {
        let result = $result_expr;
        if result != ffi::clfftStatus::CLFFT_SUCCESS {
            panic!("Unexpeced error in foreign library: {:?}", result);
        }
    }
}

/// Initialize the internal FFT resources such as FFT implementation caches kernels, programs, and buffers.
pub fn init_lib() -> ffi::clfftSetupData {
    let mut major: ocl::ffi::cl_uint = 0;
    let mut minor: ocl::ffi::cl_uint = 0;
    let mut patch: ocl::ffi::cl_uint = 0;
    clfft_panic!( unsafe { ffi::clfftGetVersion(&mut major, &mut minor, &mut patch) } );
    let data = ffi::clfftSetupData {
        major: major,
        minor: minor,
        patch: patch,
        debugFlags: 0,
    };

    clfft_panic!(unsafe { ffi::clfftSetup(&data) });
    data
}

/// Release all internal resources acquired during `init_lib`.
pub fn drop_lib() {
    unsafe { ffi::clfftTeardown() };
}

fn translate_to_fft_dim(dims: ocl::SpatialDims) -> ffi::clfftDim {
    match dims.dim_count() {
        1 => ffi::clfftDim::CLFFT_1D,
        2 => ffi::clfftDim::CLFFT_2D,
        3 => ffi::clfftDim::CLFFT_3D,
        n => panic!("Number of dimensions must be 1, 2 or 3, but it is {}", n)
    }
}

pub struct FftPlanBuilder {
    handle: ffi::clfftPlanHandle
}

/// Specify the expected precision of each FFT.
pub enum Precision {
    Single,
    Double,
    SingleFast,
    DoubleFast
}

fn translate_precision(precision: Precision) -> ffi::clfftPrecision {
    match precision {
        Precision::Single => ffi::clfftPrecision::CLFFT_SINGLE,
        Precision::Double => ffi::clfftPrecision::CLFFT_DOUBLE,
        Precision::SingleFast => ffi::clfftPrecision::CLFFT_SINGLE_FAST,
        Precision::DoubleFast => ffi::clfftPrecision::CLFFT_DOUBLE_FAST
    }
}

fn translate_precision_back(precision: ffi::clfftPrecision) -> Precision {
    match precision {
        ffi::clfftPrecision::CLFFT_SINGLE => Precision::Single,
        ffi::clfftPrecision::CLFFT_DOUBLE => Precision::Double,
        ffi::clfftPrecision::CLFFT_SINGLE_FAST => Precision::SingleFast,
        ffi::clfftPrecision::CLFFT_DOUBLE_FAST => Precision::DoubleFast,
        ffi::clfftPrecision::ENDPRECISION => panic!("ENDPRECISION should never be returned")
    }
}

/// Specify the expected layouts of the buffers.
pub enum Layout {
    ComplexInterleaved,
    ComplexPlanar,
    HermitianInterleaved,
    HermitianPlanar,
    Real
}

fn translate_layout(layout: Layout) -> ffi::clfftLayout {
    match layout {
        Layout::ComplexInterleaved => ffi::clfftLayout::CLFFT_COMPLEX_INTERLEAVED,
        Layout::ComplexPlanar => ffi::clfftLayout::CLFFT_COMPLEX_PLANAR,
        Layout::HermitianInterleaved => ffi::clfftLayout::CLFFT_HERMITIAN_INTERLEAVED,
        Layout::HermitianPlanar => ffi::clfftLayout::CLFFT_HERMITIAN_PLANAR,
        Layout::Real => ffi::clfftLayout::CLFFT_REAL
    }
}

fn translate_layout_back(layout: ffi::clfftLayout) -> Layout {
    match layout {
        ffi::clfftLayout::CLFFT_COMPLEX_INTERLEAVED => Layout::ComplexInterleaved,
        ffi::clfftLayout::CLFFT_COMPLEX_PLANAR => Layout::ComplexPlanar,
        ffi::clfftLayout::CLFFT_HERMITIAN_INTERLEAVED => Layout::HermitianInterleaved,
        ffi::clfftLayout::CLFFT_HERMITIAN_PLANAR => Layout::HermitianPlanar,
        ffi::clfftLayout::CLFFT_REAL => Layout::Real,
        ffi::clfftLayout::ENDLAYOUT => panic!("ENDLAYOUT should never be returned")
    }
}

/// Specify the expected direction of each FFT, time or the frequency domains
pub enum Direction {
    Forward,
    Backward
}

fn translate_direction(direction: Direction) -> ffi::clfftDirection {
    match direction {
        Direction::Forward => ffi::clfftDirection::CLFFT_FORWARD,
        Direction::Backward => ffi::clfftDirection::CLFFT_BACKWARD
    }
}

/// pecify wheter the input buffers are overwritten with results
pub enum Location {
    Inplace,
    OutOfPlace
}

fn translate_location(location: Location) -> ffi::clfftResultLocation {
    match location {
        Location::Inplace => ffi::clfftResultLocation::CLFFT_INPLACE,
        Location::OutOfPlace => ffi::clfftResultLocation::CLFFT_OUTOFPLACE
    }
}

fn translate_location_back(location: ffi::clfftResultLocation) -> Location {
    match location {
        ffi::clfftResultLocation::CLFFT_INPLACE => Location::Inplace,
        ffi::clfftResultLocation::CLFFT_OUTOFPLACE => Location::OutOfPlace,
        ffi::clfftResultLocation::ENDPLACE => panic!("ENDPLACE should never be returned")
    }
}

impl FftPlanBuilder {
    /// Create a plan object initialized entirely with default values.
    ///
    /// A plan is a repository of state for calculating FFT's.  Allows the runtime to pre-calculate kernels, programs
    /// and buffers and associate them with buffers of specified dimensions.
    pub fn default<D: Into<ocl::SpatialDims>>(pro_que: &ocl::ProQue, dims: D)
        -> ocl::Result<FftPlanBuilder> {
        let context = unsafe { pro_que.context().core_as_ref().as_ptr() };
        let dims = dims.into();
        let dim = translate_to_fft_dim(dims);
        let lengths = try!(dims.to_lens());
        let mut plan: ffi::clfftPlanHandle = 0;
        clfft_try!( unsafe { ffi::clfftCreateDefaultPlan(&mut plan, context, dim, &lengths as *const usize) } );
        Ok(FftPlanBuilder {  handle: plan })
    }

    /// Returns the native clFFT plan handle.
    pub fn plan_handle(&self) -> ffi::clfftPlanHandle {
        self.handle
    }

    /// Set the floating point precision of the FFT data
    pub fn set_precision(&mut self, precision: Precision) -> ocl::Result<()> {
        let precision = translate_precision(precision);
        clfft_try!(unsafe { ffi::clfftSetPlanPrecision(self.handle, precision) });
        Ok(())
    }

    pub fn get_precision(&self) -> ocl::Result<Precision> {
        let mut precision = ffi::clfftPrecision::CLFFT_SINGLE;
        clfft_try!(unsafe { ffi::clfftGetPlanPrecision(self.handle, &mut precision) });
        Ok(translate_precision_back(precision))
    }

    /// Set the expected layout of the input and output buffers
    pub fn set_layout(&mut self, input_layout: Layout, output_layout: Layout) -> ocl::Result<()> {
        let input_layout = translate_layout(input_layout);
        let output_layout = translate_layout(output_layout);
        clfft_try!(unsafe { ffi::clfftSetLayout(self.handle, input_layout, output_layout) });
        Ok(())
    }

    pub fn get_layout(&self) -> ocl::Result<(Layout, Layout)> {
        let mut input_layout = ffi::clfftLayout::CLFFT_COMPLEX_INTERLEAVED;
        let mut output_layout = ffi::clfftLayout::CLFFT_COMPLEX_INTERLEAVED;
        clfft_try!(unsafe { ffi::clfftGetLayout(self.handle, &mut input_layout, &mut output_layout) });
        Ok((translate_layout_back(input_layout), translate_layout_back(output_layout)))
    }

    /// Set whether the input buffers are to be overwritten with results
    pub fn set_result_location(&mut self, location: Location) -> ocl::Result<()> {
        let location = translate_location(location);
        clfft_try!(unsafe { ffi::clfftSetResultLocation(self.handle, location) });
        Ok(())
    }

    pub fn get_result_location(&self) -> ocl::Result<Location> {
        let mut location = ffi::clfftResultLocation::CLFFT_INPLACE;
        clfft_try!(unsafe { ffi::clfftGetResultLocation(self.handle, &mut location) });
        Ok(translate_location_back(location))
    }

    pub fn build(mut self, pro_que: &mut ocl::ProQue) -> ocl::Result<FftPlan> {
        let mut queue = unsafe { pro_que.queue().core_as_ref().as_ptr() };
        clfft_try!(unsafe {ffi::clfftBakePlan(self.handle, 1, &mut queue, None, 0 as *mut ::std::os::raw::c_void)});
        let plan = FftPlan { handle: self.handle };
        self.handle = 0;
        Ok(plan)
    }
}

pub struct FftPlan {
    handle: ffi::clfftPlanHandle
}

impl FftPlan {
    pub fn enqueue<T: ocl::traits::OclPrm>(
            &self,
            direction: Direction,
            pro_que: &mut ocl::ProQue,
            buffer: &mut ocl::Buffer<T>,
            result: Option<&mut ocl::Buffer<T>>) -> ocl::Result<()> {
        let mut queue = unsafe { pro_que.queue().core_as_ref().as_ptr() };
        let mut buffer = unsafe { buffer.core_as_ref().as_ptr() };
        let mut result = match result {
            None => 0 as ocl::ffi::cl_mem,
            Some(res) => unsafe { res.core_as_ref().as_ptr() }
        };
        let direction = translate_direction(direction);
        clfft_try!(
            unsafe {
                ffi::clfftEnqueueTransform(
                    self.handle,
                    direction,
                    1,
                    &mut queue,
                    0,
                    0 as *const ocl::ffi::cl_event,
                    0 as *mut ocl::ffi::cl_event,
                    &mut buffer,
                    &mut result,
                    0 as ocl::ffi::cl_mem)
            });
        Ok(())
    }
}

impl std::ops::Drop for FftPlanBuilder {
    fn drop(&mut self) {
        if self.handle != 0 {
            // unsafe { ffi::clfftDestroyPlan(&mut self.handle) };
            self.handle = 0;
        }
    }
}

impl std::ops::Drop for FftPlan {
    fn drop(&mut self) {
        if self.handle != 0 {
            // unsafe { ffi::clfftDestroyPlan(&mut self.handle) };
            self.handle = 0;
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use ocl::{ProQue, Buffer};
    use ocl::builders::ProgramBuilder;
    use ocl::flags;
    use std;

    #[test]
    pub fn fft_test() {
        init_lib();
        let mut source = vec![0.0; 100];
        for i in 0..source.len() {
            let x = 10.0 * i as f64 / source.len() as f64;
            source[i] = (std::f64::consts::PI * x).sin();
        }
        let prog_bldr = ProgramBuilder::new();
        let mut ocl_pq = ProQue::builder()
            .prog_bldr(prog_bldr)
            .dims([source.len()])
            .build()
            .expect("Building ProQue");

        let mut in_buffer =
            Buffer::new(
                ocl_pq.queue().clone(),
                Some(flags::MEM_READ_WRITE |
                     flags::MEM_COPY_HOST_PTR),
                ocl_pq.dims().clone(),
                Some(&source))
                .expect("Failed to create GPU input buffer");

        let mut builder = FftPlanBuilder::default(&ocl_pq, [1000]).unwrap();
        builder.set_precision(Precision::Single).unwrap();
        builder.set_layout(Layout::ComplexInterleaved, Layout::ComplexInterleaved).unwrap();
        builder.set_result_location(Location::Inplace).unwrap();
        let plan = builder.build(&mut ocl_pq).unwrap();
        plan.enqueue(Direction::Forward, &mut ocl_pq, &mut in_buffer, None).unwrap();
        ocl_pq.queue().finish();
        drop_lib();
    }
}<|endoftext|>


<commit_before>use std::error::Error;
use std::io::{BufRead, Write};
use std::thread;
use std::net::{TcpListener, TcpStream};
use std::io::BufReader;

use ::page;

/// modified from gkbrk's demo:
/// https://gist.github.com/gkbrk/bea6dee7c0478395b718

fn handle_client(mut stream: TcpStream) {
let mut reader = BufReader::new(stream.try_clone().unwrap());
    stream.write("220 urdict 0.1.0\r\n".as_bytes()).unwrap();
    loop {
        let mut line = String::new();
        let line_len = reader.read_line(&mut line).unwrap();
        if line_len > 0{
            let pieces: Vec<&str> = line.trim().split(" ").collect();
            match pieces[0].to_lowercase().as_ref() {
                "define" => {
                    let word = pieces[2].replace("\"", "");

                    if let Some(def) = page::find_on_urban_dict(&word) {
                        stream.write(format!("150 {} definitions retrieved\r\n", 1).as_bytes()).unwrap();

                        stream.write(format!("151 \"{}\" urdict", def.word).as_bytes()).unwrap();
                        stream.write(format!(" \"Urban Dictionary {} {}\"\r\n", def.contributor, def.date).as_bytes()).unwrap();
                        stream.write(format!("{}\r\n.\r\n", def.def).as_bytes()).unwrap();
                    } else {
                        stream.write(format!("150 0 definitions retrieved\r\n").as_bytes()).unwrap();
                    }
                    stream.write("250 ok\r\n".as_bytes()).unwrap();
                },
                "match" => {
                    let word = pieces[3].replace("\"", "");
                    if let Some(def) = page::find_on_urban_dict(&word) {
                        if let Some(similars) = def.similars {
                            stream.write(format!("152 {} matches found\r\n", similars.len()).as_bytes()).unwrap();
                            for s in similars {
                                stream.write(format!("urdict \"{}\"\r\n", s).as_bytes()).unwrap();
                            }
                            stream.write(".\r\n".as_bytes()).unwrap();
                        } else {
                            stream.write("152 0 matches found\r\n".as_bytes()).unwrap();
                        }
                    } else {
                        stream.write("152 0 matches found\r\n".as_bytes()).unwrap();
                    }

                    stream.write("250 ok\r\n".as_bytes()).unwrap();
                }
                "quit" => {
                    stream.write("221 bye\r\n".as_bytes()).unwrap();
                    break;
                },
                "client" => {
                    stream.write("250 ok\r\n".as_bytes()).unwrap();
                }
                _ => {
                    println!("{}", line.trim());
                }
            }
        }else{
            println!("Client disconnected");
            break;
        }
    }
}

pub fn start_server(host: &str, port: u16) {
    let listener = TcpListener::bind(&(host, port)).unwrap();
    for stream in listener.incoming() {
        match stream {
            Ok(stream) => {
                thread::spawn(move|| {
                    handle_client(stream);
                });
            },
            Err(e) => {
                println!("{}", e.description());
            }
        }
    }
}
<commit_msg>(feat) implement SHOW DB [#9]<commit_after>use std::error::Error;
use std::io::{BufRead, Write};
use std::thread;
use std::net::{TcpListener, TcpStream};
use std::io::BufReader;

use ::page;

/// modified from gkbrk's demo:
/// https://gist.github.com/gkbrk/bea6dee7c0478395b718

fn handle_client(mut stream: TcpStream) {
let mut reader = BufReader::new(stream.try_clone().unwrap());
    stream.write("220 urdict 0.1.0\r\n".as_bytes()).unwrap();
    loop {
        let mut line = String::new();
        let line_len = reader.read_line(&mut line).unwrap();
        if line_len > 0{
            let pieces: Vec<&str> = line.trim().split(" ").collect();
            match pieces[0].to_lowercase().as_ref() {
                "define" => {
                    let word = pieces[2].replace("\"", "");

                    if let Some(def) = page::find_on_urban_dict(&word) {
                        stream.write(format!("150 {} definitions retrieved\r\n", 1).as_bytes()).unwrap();

                        stream.write(format!("151 \"{}\" urdict", def.word).as_bytes()).unwrap();
                        stream.write(format!(" \"Urban Dictionary {} {}\"\r\n", def.contributor, def.date).as_bytes()).unwrap();
                        stream.write(format!("{}\r\n.\r\n", def.def).as_bytes()).unwrap();
                    } else {
                        stream.write(format!("150 0 definitions retrieved\r\n").as_bytes()).unwrap();
                    }
                    stream.write("250 ok\r\n".as_bytes()).unwrap();
                },
                "match" => {
                    let word = pieces[3].replace("\"", "");
                    if let Some(def) = page::find_on_urban_dict(&word) {
                        if let Some(similars) = def.similars {
                            stream.write(format!("152 {} matches found\r\n", similars.len()).as_bytes()).unwrap();
                            for s in similars {
                                stream.write(format!("urdict \"{}\"\r\n", s).as_bytes()).unwrap();
                            }
                            stream.write(".\r\n".as_bytes()).unwrap();
                        } else {
                            stream.write("152 0 matches found\r\n".as_bytes()).unwrap();
                        }
                    } else {
                        stream.write("152 0 matches found\r\n".as_bytes()).unwrap();
                    }

                    stream.write("250 ok\r\n".as_bytes()).unwrap();
                }
                "quit" => {
                    stream.write("221 bye\r\n".as_bytes()).unwrap();
                    break;
                },
                "client" => {
                    stream.write("250 ok\r\n".as_bytes()).unwrap();
                },
                "show" => {
                    match pieces[1].to_lowercase().as_ref() {
                        "db" => {
                            stream.write("110 1 database present\r\n".as_bytes()).unwrap();
                            stream.write("urdict \"Urban Dictionary\"\r\n".as_bytes()).unwrap();
                            stream.write(".\r\n".as_bytes()).unwrap();
                            stream.write("250 ok\r\n".as_bytes()).unwrap();
                        },
                        _ => {
                            println!("{}", line.trim());
                        }
                    }

                }
                _ => {
                    println!("{}", line.trim());
                }
            }
        }else{
            println!("Client disconnected");
            break;
        }
    }
}

pub fn start_server(host: &str, port: u16) {
    let listener = TcpListener::bind(&(host, port)).unwrap();
    for stream in listener.incoming() {
        match stream {
            Ok(stream) => {
                thread::spawn(move|| {
                    handle_client(stream);
                });
            },
            Err(e) => {
                println!("{}", e.description());
            }
        }
    }
}
<|endoftext|>


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

use super::stream::SBStream;
use super::ErrorType;
use std::fmt;
use std::{error::Error, ffi::CStr};
use sys;

/// A container for holding any error code.
pub struct SBError {
    /// The underlying raw `SBErrorRef`.
    pub raw: sys::SBErrorRef,
}

impl SBError {
    /// Construct a new `SBError`.
    pub fn new() -> SBError {
        SBError::wrap(unsafe { sys::CreateSBError() })
    }

    /// Construct a new `SBError`.
    pub fn wrap(raw: sys::SBErrorRef) -> SBError {
        SBError { raw }
    }

    /// Construct a new `Some(SBError)` or `None`.
    pub fn maybe_wrap(raw: sys::SBErrorRef) -> Option<SBError> {
        if unsafe { sys::SBErrorIsValid(raw) != 0 } {
            Some(SBError { raw })
        } else {
            None
        }
    }

    /// Check whether or not this is a valid `SBError` value.
    pub fn is_valid(&self) -> bool {
        unsafe { sys::SBErrorIsValid(self.raw) != 0 }
    }

    /// Any textual error message associated with the error.
    pub fn error_string(&self) -> &str {
        unsafe {
            match CStr::from_ptr(sys::SBErrorGetCString(self.raw)).to_str() {
                Ok(s) => s,
                _ => panic!("Invalid string?"),
            }
        }
    }

    /// Does this error represent a failure?
    pub fn is_failure(&self) -> bool {
        unsafe { sys::SBErrorFail(self.raw) != 0 }
    }

    /// Does this error represent a success?
    pub fn is_success(&self) -> bool {
        unsafe { sys::SBErrorSuccess(self.raw) != 0 }
    }

    /// The underlying error code. Must be interpreted in conjunction
    /// with the error type.
    pub fn error(&self) -> u32 {
        unsafe { sys::SBErrorGetError(self.raw) }
    }

    /// What type of error is this?
    pub fn error_type(&self) -> ErrorType {
        unsafe { sys::SBErrorGetType(self.raw) }
    }
}

impl Clone for SBError {
    fn clone(&self) -> SBError {
        SBError {
            raw: unsafe { sys::CloneSBError(self.raw) },
        }
    }
}

impl Default for SBError {
    fn default() -> SBError {
        SBError::new()
    }
}

impl fmt::Debug for SBError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let stream = SBStream::new();
        unsafe { sys::SBErrorGetDescription(self.raw, stream.raw) };
        write!(fmt, "SBError {{ {} }}", stream.data())
    }
}

impl fmt::Display for SBError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        if !self.is_valid() {
            write!(f, "Invalid SBError")
        } else if !self.is_failure() {
            write!(f, "SBError representing success")
        } else {
            write!(f, "SBError: {}", self.error_string())
        }
    }
}

impl Error for SBError {}

impl Drop for SBError {
    fn drop(&mut self) {
        unsafe { sys::DisposeSBError(self.raw) };
    }
}

unsafe impl Send for SBError {}
unsafe impl Sync for SBError {}
<commit_msg>Add helper for SBError -> Result<(), SBError><commit_after>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use super::stream::SBStream;
use super::ErrorType;
use std::fmt;
use std::{error::Error, ffi::CStr};
use sys;

/// A container for holding any error code.
pub struct SBError {
    /// The underlying raw `SBErrorRef`.
    pub raw: sys::SBErrorRef,
}

impl SBError {
    /// Construct a new `SBError`.
    pub fn new() -> SBError {
        SBError::wrap(unsafe { sys::CreateSBError() })
    }

    /// Construct a new `SBError`.
    pub fn wrap(raw: sys::SBErrorRef) -> SBError {
        SBError { raw }
    }

    /// Construct a new `Some(SBError)` or `None`.
    pub fn maybe_wrap(raw: sys::SBErrorRef) -> Option<SBError> {
        if unsafe { sys::SBErrorIsValid(raw) != 0 } {
            Some(SBError { raw })
        } else {
            None
        }
    }

    /// Check whether or not this is a valid `SBError` value.
    pub fn is_valid(&self) -> bool {
        unsafe { sys::SBErrorIsValid(self.raw) != 0 }
    }

    /// Any textual error message associated with the error.
    pub fn error_string(&self) -> &str {
        unsafe {
            match CStr::from_ptr(sys::SBErrorGetCString(self.raw)).to_str() {
                Ok(s) => s,
                _ => panic!("Invalid string?"),
            }
        }
    }

    /// Does this error represent a failure?
    pub fn is_failure(&self) -> bool {
        unsafe { sys::SBErrorFail(self.raw) != 0 }
    }

    /// Does this error represent a success?
    pub fn is_success(&self) -> bool {
        unsafe { sys::SBErrorSuccess(self.raw) != 0 }
    }

    /// The underlying error code. Must be interpreted in conjunction
    /// with the error type.
    pub fn error(&self) -> u32 {
        unsafe { sys::SBErrorGetError(self.raw) }
    }

    /// What type of error is this?
    pub fn error_type(&self) -> ErrorType {
        unsafe { sys::SBErrorGetType(self.raw) }
    }

    /// Convert to a Result<(), SBError>
    ///
    /// SBErrors represent either a success or a failure. This method converts
    /// the success variant to Ok(()) and the error variant to Err(SBError).
    pub fn into_result(self) -> Result<(), SBError> {
        if self.is_success() {
            Ok(())
        } else {
            Err(self)
        }
    }
}

impl Clone for SBError {
    fn clone(&self) -> SBError {
        SBError {
            raw: unsafe { sys::CloneSBError(self.raw) },
        }
    }
}

impl Default for SBError {
    fn default() -> SBError {
        SBError::new()
    }
}

impl fmt::Debug for SBError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let stream = SBStream::new();
        unsafe { sys::SBErrorGetDescription(self.raw, stream.raw) };
        write!(fmt, "SBError {{ {} }}", stream.data())
    }
}

impl fmt::Display for SBError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        if !self.is_valid() {
            write!(f, "Invalid SBError")
        } else if !self.is_failure() {
            write!(f, "SBError representing success")
        } else {
            write!(f, "SBError: {}", self.error_string())
        }
    }
}

impl Error for SBError {}

impl Drop for SBError {
    fn drop(&mut self) {
        unsafe { sys::DisposeSBError(self.raw) };
    }
}

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