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

// FIXME: #13996: mark the `allocate` and `reallocate` return value as `noalias`

/// Returns a pointer to `size` bytes of memory.
///
/// Behavior is undefined if the requested size is 0 or the alignment is not a
/// power of 2. The alignment must be no larger than the largest supported page
/// size on the platform.
#[inline]
pub unsafe fn allocate(size: uint, align: uint) -> *mut u8 {
    imp::allocate(size, align)
}

/// Extends or shrinks the allocation referenced by `ptr` to `size` bytes of
/// memory.
///
/// Behavior is undefined if the requested size is 0 or the alignment is not a
/// power of 2. The alignment must be no larger than the largest supported page
/// size on the platform.
///
/// The `old_size` and `align` parameters are the parameters that were used to
/// create the allocation referenced by `ptr`. The `old_size` parameter may also
/// be the value returned by `usable_size` for the requested size.
#[inline]
pub unsafe fn reallocate(ptr: *mut u8, old_size: uint, size: uint, align: uint) -> *mut u8 {
    imp::reallocate(ptr, old_size, size, align)
}

/// Extends or shrinks the allocation referenced by `ptr` to `size` bytes of
/// memory in-place.
///
/// Returns true if successful, otherwise false if the allocation was not
/// altered.
///
/// Behavior is undefined if the requested size is 0 or the alignment is not a
/// power of 2. The alignment must be no larger than the largest supported page
/// size on the platform.
///
/// The `old_size` and `align` parameters are the parameters that were used to
/// create the allocation referenced by `ptr`. The `old_size` parameter may be
/// any value in range_inclusive(requested_size, usable_size).
#[inline]
pub unsafe fn reallocate_inplace(ptr: *mut u8, old_size: uint, size: uint, align: uint) -> bool {
    imp::reallocate_inplace(ptr, old_size, size, align)
}

/// Deallocates the memory referenced by `ptr`.
///
/// The `ptr` parameter must not be null.
///
/// The `size` and `align` parameters are the parameters that were used to
/// create the allocation referenced by `ptr`. The `size` parameter may also be
/// the value returned by `usable_size` for the requested size.
#[inline]
pub unsafe fn deallocate(ptr: *mut u8, size: uint, align: uint) {
    imp::deallocate(ptr, size, align)
}

/// Returns the usable size of an allocation created with the specified the
/// `size` and `align`.
#[inline]
pub fn usable_size(size: uint, align: uint) -> uint {
    imp::usable_size(size, align)
}

/// Prints implementation-defined allocator statistics.
///
/// These statistics may be inconsistent if other threads use the allocator
/// during the call.
#[unstable]
pub fn stats_print() {
    imp::stats_print();
}

/// An arbitrary non-null address to represent zero-size allocations.
///
/// This preserves the non-null invariant for types like `Box<T>`. The address may overlap with
/// non-zero-size memory allocations.
pub const EMPTY: *mut () = 0x1 as *mut ();

/// The allocator for unique pointers.
#[cfg(not(test))]
#[lang="exchange_malloc"]
#[inline]
unsafe fn exchange_malloc(size: uint, align: uint) -> *mut u8 {
    if size == 0 {
        EMPTY as *mut u8
    } else {
        allocate(size, align)
    }
}

#[cfg(not(test))]
#[lang="exchange_free"]
#[inline]
unsafe fn exchange_free(ptr: *mut u8, size: uint, align: uint) {
    deallocate(ptr, size, align);
}

// The minimum alignment guaranteed by the architecture. This value is used to
// add fast paths for low alignment values. In practice, the alignment is a
// constant at the call site and the branch will be optimized out.
#[cfg(any(target_arch = "arm",
          target_arch = "mips",
          target_arch = "mipsel"))]
const MIN_ALIGN: uint = 8;
#[cfg(any(target_arch = "x86",
          target_arch = "x86_64"))]
const MIN_ALIGN: uint = 16;

#[cfg(jemalloc)]
mod imp {
    use core::option::{None, Option};
    use core::ptr::{RawPtr, null_mut, null};
    use core::num::Int;
    use libc::{c_char, c_int, c_void, size_t};
    use super::MIN_ALIGN;

    #[link(name = "jemalloc", kind = "static")]
    #[cfg(not(test))]
    extern {}

    extern {
        fn je_mallocx(size: size_t, flags: c_int) -> *mut c_void;
        fn je_rallocx(ptr: *mut c_void, size: size_t,
                      flags: c_int) -> *mut c_void;
        fn je_xallocx(ptr: *mut c_void, size: size_t, extra: size_t,
                      flags: c_int) -> size_t;
        fn je_sdallocx(ptr: *mut c_void, size: size_t, flags: c_int);
        fn je_nallocx(size: size_t, flags: c_int) -> size_t;
        fn je_malloc_stats_print(write_cb: Option<extern "C" fn(cbopaque: *mut c_void,
                                                                *const c_char)>,
                                 cbopaque: *mut c_void,
                                 opts: *const c_char);
    }

    // -lpthread needs to occur after -ljemalloc, the earlier argument isn't enough
    #[cfg(all(not(windows), not(target_os = "android")))]
    #[link(name = "pthread")]
    extern {}

    // MALLOCX_ALIGN(a) macro
    #[inline(always)]
    fn mallocx_align(a: uint) -> c_int { a.trailing_zeros() as c_int }

    #[inline(always)]
    fn align_to_flags(align: uint) -> c_int {
        if align <= MIN_ALIGN { 0 } else { mallocx_align(align) }
    }

    #[inline]
    pub unsafe fn allocate(size: uint, align: uint) -> *mut u8 {
        let flags = align_to_flags(align);
        let ptr = je_mallocx(size as size_t, flags) as *mut u8;
        if ptr.is_null() {
            ::oom()
        }
        ptr
    }

    #[inline]
    pub unsafe fn reallocate(ptr: *mut u8, _old_size: uint, size: uint, align: uint) -> *mut u8 {
        let flags = align_to_flags(align);
        let ptr = je_rallocx(ptr as *mut c_void, size as size_t, flags) as *mut u8;
        if ptr.is_null() {
            ::oom()
        }
        ptr
    }

    #[inline]
    pub unsafe fn reallocate_inplace(ptr: *mut u8, old_size: uint, size: uint,
                                     align: uint) -> bool {
        let flags = align_to_flags(align);
        let new_size = je_xallocx(ptr as *mut c_void, size as size_t, 0, flags) as uint;
        // checking for failure to shrink is tricky
        if size < old_size {
            usable_size(size, align) == new_size as uint
        } else {
            new_size >= size
        }
    }

    #[inline]
    pub unsafe fn deallocate(ptr: *mut u8, size: uint, align: uint) {
        let flags = align_to_flags(align);
        je_sdallocx(ptr as *mut c_void, size as size_t, flags)
    }

    #[inline]
    pub fn usable_size(size: uint, align: uint) -> uint {
        let flags = align_to_flags(align);
        unsafe { je_nallocx(size as size_t, flags) as uint }
    }

    pub fn stats_print() {
        unsafe {
            je_malloc_stats_print(None, null_mut(), null())
        }
    }
}

#[cfg(all(not(jemalloc), unix))]
mod imp {
    use core::cmp;
    use core::ptr;
    use core::ptr::RawPtr;
    use libc;
    use super::MIN_ALIGN;

    extern {
        fn posix_memalign(memptr: *mut *mut libc::c_void,
                          align: libc::size_t,
                          size: libc::size_t) -> libc::c_int;
    }

    #[inline]
    pub unsafe fn allocate(size: uint, align: uint) -> *mut u8 {
        if align <= MIN_ALIGN {
            let ptr = libc::malloc(size as libc::size_t);
            if ptr.is_null() {
                ::oom();
            }
            ptr as *mut u8
        } else {
            let mut out = 0 as *mut libc::c_void;
            let ret = posix_memalign(&mut out,
                                     align as libc::size_t,
                                     size as libc::size_t);
            if ret != 0 {
                ::oom();
            }
            out as *mut u8
        }
    }

    #[inline]
    pub unsafe fn reallocate(ptr: *mut u8, old_size: uint, size: uint, align: uint) -> *mut u8 {
        if align <= MIN_ALIGN {
            let ptr = libc::realloc(ptr as *mut libc::c_void, size as libc::size_t);
            if ptr.is_null() {
                ::oom();
            }
            ptr as *mut u8
        } else {
            let new_ptr = allocate(size, align);
            ptr::copy_memory(new_ptr, ptr as *const u8, cmp::min(size, old_size));
            deallocate(ptr, old_size, align);
            new_ptr
        }
    }

    #[inline]
    pub unsafe fn reallocate_inplace(_ptr: *mut u8, old_size: uint, size: uint,
                                     _align: uint) -> bool {
        size == old_size
    }

    #[inline]
    pub unsafe fn deallocate(ptr: *mut u8, _size: uint, _align: uint) {
        libc::free(ptr as *mut libc::c_void)
    }

    #[inline]
    pub fn usable_size(size: uint, _align: uint) -> uint {
        size
    }

    pub fn stats_print() {}
}

#[cfg(all(not(jemalloc), windows))]
mod imp {
    use libc::{c_void, size_t};
    use libc;
    use core::ptr::RawPtr;
    use super::MIN_ALIGN;

    extern {
        fn _aligned_malloc(size: size_t, align: size_t) -> *mut c_void;
        fn _aligned_realloc(block: *mut c_void, size: size_t,
                            align: size_t) -> *mut c_void;
        fn _aligned_free(ptr: *mut c_void);
    }

    #[inline]
    pub unsafe fn allocate(size: uint, align: uint) -> *mut u8 {
        if align <= MIN_ALIGN {
            let ptr = libc::malloc(size as size_t);
            if ptr.is_null() {
                ::oom();
            }
            ptr as *mut u8
        } else {
            let ptr = _aligned_malloc(size as size_t, align as size_t);
            if ptr.is_null() {
                ::oom();
            }
            ptr as *mut u8
        }
    }

    #[inline]
    pub unsafe fn reallocate(ptr: *mut u8, _old_size: uint, size: uint, align: uint) -> *mut u8 {
        if align <= MIN_ALIGN {
            let ptr = libc::realloc(ptr as *mut c_void, size as size_t);
            if ptr.is_null() {
                ::oom();
            }
            ptr as *mut u8
        } else {
            let ptr = _aligned_realloc(ptr as *mut c_void, size as size_t,
                                       align as size_t);
            if ptr.is_null() {
                ::oom();
            }
            ptr as *mut u8
        }
    }

    #[inline]
    pub unsafe fn reallocate_inplace(_ptr: *mut u8, old_size: uint, size: uint,
                                     _align: uint) -> bool {
        size == old_size
    }

    #[inline]
    pub unsafe fn deallocate(ptr: *mut u8, _size: uint, align: uint) {
        if align <= MIN_ALIGN {
            libc::free(ptr as *mut libc::c_void)
        } else {
            _aligned_free(ptr as *mut c_void)
        }
    }

    #[inline]
    pub fn usable_size(size: uint, _align: uint) -> uint {
        size
    }

    pub fn stats_print() {}
}

#[cfg(test)]
mod test {
    extern crate test;
    use self::test::Bencher;
    use heap;

    #[test]
    fn basic_reallocate_inplace_noop() {
        unsafe {
            let size = 4000;
            let ptr = heap::allocate(size, 8);
            let ret = heap::reallocate_inplace(ptr, size, size, 8);
            heap::deallocate(ptr, size, 8);
            assert!(ret);
        }
    }

    #[bench]
    fn alloc_owned_small(b: &mut Bencher) {
        b.iter(|| {
            box 10i
        })
    }
}
<commit_msg>return the new usable size from reallocate_inplace<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// FIXME: #13996: mark the `allocate` and `reallocate` return value as `noalias`

/// Returns a pointer to `size` bytes of memory.
///
/// Behavior is undefined if the requested size is 0 or the alignment is not a
/// power of 2. The alignment must be no larger than the largest supported page
/// size on the platform.
#[inline]
pub unsafe fn allocate(size: uint, align: uint) -> *mut u8 {
    imp::allocate(size, align)
}

/// Extends or shrinks the allocation referenced by `ptr` to `size` bytes of
/// memory.
///
/// Behavior is undefined if the requested size is 0 or the alignment is not a
/// power of 2. The alignment must be no larger than the largest supported page
/// size on the platform.
///
/// The `old_size` and `align` parameters are the parameters that were used to
/// create the allocation referenced by `ptr`. The `old_size` parameter may also
/// be the value returned by `usable_size` for the requested size.
#[inline]
pub unsafe fn reallocate(ptr: *mut u8, old_size: uint, size: uint, align: uint) -> *mut u8 {
    imp::reallocate(ptr, old_size, size, align)
}

/// Extends or shrinks the allocation referenced by `ptr` to `size` bytes of
/// memory in-place.
///
/// If the operation succeeds, it returns `usable_size(size, align)` and if it
/// fails (or is a no-op) it returns `usable_size(old_size, align)`.
///
/// Behavior is undefined if the requested size is 0 or the alignment is not a
/// power of 2. The alignment must be no larger than the largest supported page
/// size on the platform.
///
/// The `old_size` and `align` parameters are the parameters that were used to
/// create the allocation referenced by `ptr`. The `old_size` parameter may be
/// any value in range_inclusive(requested_size, usable_size).
#[inline]
pub unsafe fn reallocate_inplace(ptr: *mut u8, old_size: uint, size: uint, align: uint) -> uint {
    imp::reallocate_inplace(ptr, old_size, size, align)
}

/// Deallocates the memory referenced by `ptr`.
///
/// The `ptr` parameter must not be null.
///
/// The `size` and `align` parameters are the parameters that were used to
/// create the allocation referenced by `ptr`. The `size` parameter may also be
/// the value returned by `usable_size` for the requested size.
#[inline]
pub unsafe fn deallocate(ptr: *mut u8, size: uint, align: uint) {
    imp::deallocate(ptr, size, align)
}

/// Returns the usable size of an allocation created with the specified the
/// `size` and `align`.
#[inline]
pub fn usable_size(size: uint, align: uint) -> uint {
    imp::usable_size(size, align)
}

/// Prints implementation-defined allocator statistics.
///
/// These statistics may be inconsistent if other threads use the allocator
/// during the call.
#[unstable]
pub fn stats_print() {
    imp::stats_print();
}

/// An arbitrary non-null address to represent zero-size allocations.
///
/// This preserves the non-null invariant for types like `Box<T>`. The address may overlap with
/// non-zero-size memory allocations.
pub const EMPTY: *mut () = 0x1 as *mut ();

/// The allocator for unique pointers.
#[cfg(not(test))]
#[lang="exchange_malloc"]
#[inline]
unsafe fn exchange_malloc(size: uint, align: uint) -> *mut u8 {
    if size == 0 {
        EMPTY as *mut u8
    } else {
        allocate(size, align)
    }
}

#[cfg(not(test))]
#[lang="exchange_free"]
#[inline]
unsafe fn exchange_free(ptr: *mut u8, size: uint, align: uint) {
    deallocate(ptr, size, align);
}

// The minimum alignment guaranteed by the architecture. This value is used to
// add fast paths for low alignment values. In practice, the alignment is a
// constant at the call site and the branch will be optimized out.
#[cfg(any(target_arch = "arm",
          target_arch = "mips",
          target_arch = "mipsel"))]
const MIN_ALIGN: uint = 8;
#[cfg(any(target_arch = "x86",
          target_arch = "x86_64"))]
const MIN_ALIGN: uint = 16;

#[cfg(jemalloc)]
mod imp {
    use core::option::{None, Option};
    use core::ptr::{RawPtr, null_mut, null};
    use core::num::Int;
    use libc::{c_char, c_int, c_void, size_t};
    use super::MIN_ALIGN;

    #[link(name = "jemalloc", kind = "static")]
    #[cfg(not(test))]
    extern {}

    extern {
        fn je_mallocx(size: size_t, flags: c_int) -> *mut c_void;
        fn je_rallocx(ptr: *mut c_void, size: size_t,
                      flags: c_int) -> *mut c_void;
        fn je_xallocx(ptr: *mut c_void, size: size_t, extra: size_t,
                      flags: c_int) -> size_t;
        fn je_sdallocx(ptr: *mut c_void, size: size_t, flags: c_int);
        fn je_nallocx(size: size_t, flags: c_int) -> size_t;
        fn je_malloc_stats_print(write_cb: Option<extern "C" fn(cbopaque: *mut c_void,
                                                                *const c_char)>,
                                 cbopaque: *mut c_void,
                                 opts: *const c_char);
    }

    // -lpthread needs to occur after -ljemalloc, the earlier argument isn't enough
    #[cfg(all(not(windows), not(target_os = "android")))]
    #[link(name = "pthread")]
    extern {}

    // MALLOCX_ALIGN(a) macro
    #[inline(always)]
    fn mallocx_align(a: uint) -> c_int { a.trailing_zeros() as c_int }

    #[inline(always)]
    fn align_to_flags(align: uint) -> c_int {
        if align <= MIN_ALIGN { 0 } else { mallocx_align(align) }
    }

    #[inline]
    pub unsafe fn allocate(size: uint, align: uint) -> *mut u8 {
        let flags = align_to_flags(align);
        let ptr = je_mallocx(size as size_t, flags) as *mut u8;
        if ptr.is_null() {
            ::oom()
        }
        ptr
    }

    #[inline]
    pub unsafe fn reallocate(ptr: *mut u8, _old_size: uint, size: uint, align: uint) -> *mut u8 {
        let flags = align_to_flags(align);
        let ptr = je_rallocx(ptr as *mut c_void, size as size_t, flags) as *mut u8;
        if ptr.is_null() {
            ::oom()
        }
        ptr
    }

    #[inline]
    pub unsafe fn reallocate_inplace(ptr: *mut u8, _old_size: uint, size: uint,
                                     align: uint) -> uint {
        let flags = align_to_flags(align);
        je_xallocx(ptr as *mut c_void, size as size_t, 0, flags) as uint
    }

    #[inline]
    pub unsafe fn deallocate(ptr: *mut u8, size: uint, align: uint) {
        let flags = align_to_flags(align);
        je_sdallocx(ptr as *mut c_void, size as size_t, flags)
    }

    #[inline]
    pub fn usable_size(size: uint, align: uint) -> uint {
        let flags = align_to_flags(align);
        unsafe { je_nallocx(size as size_t, flags) as uint }
    }

    pub fn stats_print() {
        unsafe {
            je_malloc_stats_print(None, null_mut(), null())
        }
    }
}

#[cfg(all(not(jemalloc), unix))]
mod imp {
    use core::cmp;
    use core::ptr;
    use core::ptr::RawPtr;
    use libc;
    use super::MIN_ALIGN;

    extern {
        fn posix_memalign(memptr: *mut *mut libc::c_void,
                          align: libc::size_t,
                          size: libc::size_t) -> libc::c_int;
    }

    #[inline]
    pub unsafe fn allocate(size: uint, align: uint) -> *mut u8 {
        if align <= MIN_ALIGN {
            let ptr = libc::malloc(size as libc::size_t);
            if ptr.is_null() {
                ::oom();
            }
            ptr as *mut u8
        } else {
            let mut out = 0 as *mut libc::c_void;
            let ret = posix_memalign(&mut out,
                                     align as libc::size_t,
                                     size as libc::size_t);
            if ret != 0 {
                ::oom();
            }
            out as *mut u8
        }
    }

    #[inline]
    pub unsafe fn reallocate(ptr: *mut u8, old_size: uint, size: uint, align: uint) -> *mut u8 {
        if align <= MIN_ALIGN {
            let ptr = libc::realloc(ptr as *mut libc::c_void, size as libc::size_t);
            if ptr.is_null() {
                ::oom();
            }
            ptr as *mut u8
        } else {
            let new_ptr = allocate(size, align);
            ptr::copy_memory(new_ptr, ptr as *const u8, cmp::min(size, old_size));
            deallocate(ptr, old_size, align);
            new_ptr
        }
    }

    #[inline]
    pub unsafe fn reallocate_inplace(_ptr: *mut u8, old_size: uint, _size: uint,
                                     _align: uint) -> uint {
        old_size
    }

    #[inline]
    pub unsafe fn deallocate(ptr: *mut u8, _size: uint, _align: uint) {
        libc::free(ptr as *mut libc::c_void)
    }

    #[inline]
    pub fn usable_size(size: uint, _align: uint) -> uint {
        size
    }

    pub fn stats_print() {}
}

#[cfg(all(not(jemalloc), windows))]
mod imp {
    use libc::{c_void, size_t};
    use libc;
    use core::ptr::RawPtr;
    use super::MIN_ALIGN;

    extern {
        fn _aligned_malloc(size: size_t, align: size_t) -> *mut c_void;
        fn _aligned_realloc(block: *mut c_void, size: size_t,
                            align: size_t) -> *mut c_void;
        fn _aligned_free(ptr: *mut c_void);
    }

    #[inline]
    pub unsafe fn allocate(size: uint, align: uint) -> *mut u8 {
        if align <= MIN_ALIGN {
            let ptr = libc::malloc(size as size_t);
            if ptr.is_null() {
                ::oom();
            }
            ptr as *mut u8
        } else {
            let ptr = _aligned_malloc(size as size_t, align as size_t);
            if ptr.is_null() {
                ::oom();
            }
            ptr as *mut u8
        }
    }

    #[inline]
    pub unsafe fn reallocate(ptr: *mut u8, _old_size: uint, size: uint, align: uint) -> *mut u8 {
        if align <= MIN_ALIGN {
            let ptr = libc::realloc(ptr as *mut c_void, size as size_t);
            if ptr.is_null() {
                ::oom();
            }
            ptr as *mut u8
        } else {
            let ptr = _aligned_realloc(ptr as *mut c_void, size as size_t,
                                       align as size_t);
            if ptr.is_null() {
                ::oom();
            }
            ptr as *mut u8
        }
    }

    #[inline]
    pub unsafe fn reallocate_inplace(_ptr: *mut u8, old_size: uint, _size: uint,
                                     _align: uint) -> uint {
        old_size
    }

    #[inline]
    pub unsafe fn deallocate(ptr: *mut u8, _size: uint, align: uint) {
        if align <= MIN_ALIGN {
            libc::free(ptr as *mut libc::c_void)
        } else {
            _aligned_free(ptr as *mut c_void)
        }
    }

    #[inline]
    pub fn usable_size(size: uint, _align: uint) -> uint {
        size
    }

    pub fn stats_print() {}
}

#[cfg(test)]
mod test {
    extern crate test;
    use self::test::Bencher;
    use heap;

    #[test]
    fn basic_reallocate_inplace_noop() {
        unsafe {
            let size = 4000;
            let ptr = heap::allocate(size, 8);
            let ret = heap::reallocate_inplace(ptr, size, size, 8);
            heap::deallocate(ptr, size, 8);
            assert_eq!(ret, heap::usable_size(size, 8));
        }
    }

    #[bench]
    fn alloc_owned_small(b: &mut Bencher) {
        b.iter(|| {
            box 10i
        })
    }
}
<|endoftext|>


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

//! This module contains the linkage attributes to all runtime dependencies of
//! the standard library This varies per-platform, but these libraries are
//! necessary for running libstd.

// All platforms need to link to rustrt
#[link(name = "rustrt", kind = "static")]
extern {}

// LLVM implements the `frem` instruction as a call to `fmod`, which lives in
// libm. Hence, we must explicitly link to it.
//
// On linux librt and libdl are indirect dependencies via rustrt,
// and binutils 2.22+ won't add them automatically
#[cfg(target_os = "linux")]
#[link(name = "c")]
#[link(name = "dl")]
#[link(name = "m")]
#[link(name = "pthread")]
extern {}

#[cfg(target_os = "android")]
#[link(name = "dl")]
#[link(name = "log")]
#[link(name = "m")]
#[link(name = "c")]
extern {}

#[cfg(target_os = "freebsd")]
#[link(name = "execinfo")]
#[link(name = "pthread")]
extern {}

#[cfg(target_os = "macos")]
#[link(name = "System")]
extern {}
<commit_msg>auto merge of #13134 : alexcrichton/rust/freebsd-libm, r=thestinger<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! This module contains the linkage attributes to all runtime dependencies of
//! the standard library This varies per-platform, but these libraries are
//! necessary for running libstd.

// All platforms need to link to rustrt
#[link(name = "rustrt", kind = "static")]
extern {}

// LLVM implements the `frem` instruction as a call to `fmod`, which lives in
// libm. Hence, we must explicitly link to it.
//
// On linux librt and libdl are indirect dependencies via rustrt,
// and binutils 2.22+ won't add them automatically
#[cfg(target_os = "linux")]
#[link(name = "c")]
#[link(name = "dl")]
#[link(name = "m")]
#[link(name = "pthread")]
extern {}

#[cfg(target_os = "android")]
#[link(name = "dl")]
#[link(name = "log")]
#[link(name = "m")]
#[link(name = "c")]
extern {}

#[cfg(target_os = "freebsd")]
#[link(name = "execinfo")]
#[link(name = "pthread")]
#[link(name = "m")]
extern {}

#[cfg(target_os = "macos")]
#[link(name = "System")]
extern {}
<|endoftext|>


<commit_before><commit_msg>hir: comment out unused nodes<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2020 The vulkano developers
// 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. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

// This example demonstrates how to initialize immutable buffers.

use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, ImmutableBuffer};
use vulkano::command_buffer::AutoCommandBufferBuilder;
use vulkano::descriptor::descriptor_set::PersistentDescriptorSet;
use vulkano::descriptor::PipelineLayoutAbstract;
use vulkano::device::{Device, DeviceExtensions};
use vulkano::instance::{Instance, InstanceExtensions, PhysicalDevice};
use vulkano::pipeline::ComputePipeline;
use vulkano::sync;
use vulkano::sync::GpuFuture;

use std::sync::Arc;

fn main() {
    // The most part of this example is exactly the same as `basic-compute-shader`. You should read the
    // `basic-compute-shader` example if you haven't done so yet.

    let instance = Instance::new(None, &InstanceExtensions::none(), None).unwrap();
    let physical = PhysicalDevice::enumerate(&instance).next().unwrap();

    let queue_family = physical
        .queue_families()
        .find(|&q| q.supports_compute())
        .unwrap();

    let (device, mut queues) = Device::new(
        physical,
        physical.supported_features(),
        &DeviceExtensions {
            khr_storage_buffer_storage_class: true,
            ..DeviceExtensions::none()
        },
        [(queue_family, 0.5)].iter().cloned(),
    )
    .unwrap();

    let queue = queues.next().unwrap();

    println!("Device initialized");

    let pipeline = Arc::new({
        mod cs {
            vulkano_shaders::shader! {
                ty: "compute",
                src: "
#version 450

layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;

layout(set = 0, binding = 0) buffer Data {
    uint data[];
} data;

layout(set = 0, binding = 1) buffer ImmutableData {
    uint data;
} immutable_data;

void main() {
    uint idx = gl_GlobalInvocationID.x;
    data.data[idx] *= 12;
    data.data[idx] += immutable_data.data;
}"
            }
        }
        let shader = cs::Shader::load(device.clone()).unwrap();
        ComputePipeline::new(device.clone(), &shader.main_entry_point(), &()).unwrap()
    });

    let data_buffer = {
        let data_iter = (0..65536u32).map(|n| n);
        CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), false, data_iter)
            .unwrap()
    };

    // Create immutable buffer and initialize it
    let immutable_data_buffer = {

        // uninitialized(), uninitialized_array() and raw() return two things: the buffer,
        // and a special access that should be used for the initial upload to the buffer.
        let (immutable_data_buffer, immutable_data_buffer_init) = unsafe {
            ImmutableBuffer::<u32>::uninitialized(device.clone(), BufferUsage::all()).unwrap()
        };

        // Build command buffer which initialize our buffer.
        let mut builder =
            AutoCommandBufferBuilder::primary_one_time_submit(device.clone(), queue.family())
                .unwrap();

        // Initializing a immutable buffer is done by coping data to
        // ImmutableBufferInitialization which is returned by a function we use to create buffer.
        // We can use copy_buffer(), fill_buffer() and some other functions that copies data to
        // buffer also.
        builder
            .update_buffer(immutable_data_buffer_init, 3)
            .unwrap();

        let command_buffer = builder.build().unwrap();

        let future = sync::now(device.clone())
            .then_execute(queue.clone(), command_buffer)
            .unwrap()
            .then_signal_fence_and_flush()
            .unwrap();

        future.wait(None).unwrap();

        // Once a buffer is initialized, we no longer need ImmutableBufferInitialization.
        // So we return only the buffer.
        immutable_data_buffer
    };

    let layout = pipeline.layout().descriptor_set_layout(0).unwrap();
    let set = Arc::new(
        PersistentDescriptorSet::start(layout.clone())
            .add_buffer(data_buffer.clone())
            .unwrap()
            // Now you can just add immutable buffer like other buffers.
            .add_buffer(immutable_data_buffer.clone())
            .unwrap()
            .build()
            .unwrap(),
    );

    let mut builder =
        AutoCommandBufferBuilder::primary_one_time_submit(device.clone(), queue.family()).unwrap();

    builder
        .dispatch([1024, 1, 1], pipeline.clone(), set.clone(), ())
        .unwrap();

    let command_buffer = builder.build().unwrap();

    let future = sync::now(device.clone())
        .then_execute(queue.clone(), command_buffer)
        .unwrap()
        .then_signal_fence_and_flush()
        .unwrap();

    future.wait(None).unwrap();

    let data_buffer_content = data_buffer.read().unwrap();
    for n in 0..65536u32 {
        assert_eq!(data_buffer_content[n as usize], n * 12 + 3);
    }
}
<commit_msg>Migration to a newer API for #1296 (#1507)<commit_after>// Copyright (c) 2020 The vulkano developers
// 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. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

// This example demonstrates how to initialize immutable buffers.

use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, ImmutableBuffer};
use vulkano::command_buffer::AutoCommandBufferBuilder;
use vulkano::descriptor::descriptor_set::PersistentDescriptorSet;
use vulkano::descriptor::PipelineLayoutAbstract;
use vulkano::device::{Device, DeviceExtensions};
use vulkano::instance::{Instance, InstanceExtensions, PhysicalDevice};
use vulkano::pipeline::ComputePipeline;
use vulkano::sync;
use vulkano::sync::GpuFuture;

use std::sync::Arc;

fn main() {
    // The most part of this example is exactly the same as `basic-compute-shader`. You should read the
    // `basic-compute-shader` example if you haven't done so yet.

    let instance = Instance::new(None, &InstanceExtensions::none(), None).unwrap();
    let physical = PhysicalDevice::enumerate(&instance).next().unwrap();

    let queue_family = physical
        .queue_families()
        .find(|&q| q.supports_compute())
        .unwrap();

    let (device, mut queues) = Device::new(
        physical,
        physical.supported_features(),
        &DeviceExtensions {
            khr_storage_buffer_storage_class: true,
            ..DeviceExtensions::none()
        },
        [(queue_family, 0.5)].iter().cloned(),
    )
    .unwrap();

    let queue = queues.next().unwrap();

    println!("Device initialized");

    let pipeline = Arc::new({
        mod cs {
            vulkano_shaders::shader! {
                ty: "compute",
                src: "
#version 450

layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;

layout(set = 0, binding = 0) buffer Data {
    uint data[];
} data;

layout(set = 0, binding = 1) buffer ImmutableData {
    uint data;
} immutable_data;

void main() {
    uint idx = gl_GlobalInvocationID.x;
    data.data[idx] *= 12;
    data.data[idx] += immutable_data.data;
}"
            }
        }
        let shader = cs::Shader::load(device.clone()).unwrap();
        ComputePipeline::new(device.clone(), &shader.main_entry_point(), &(), None).unwrap()
    });

    let data_buffer = {
        let data_iter = (0..65536u32).map(|n| n);
        CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), false, data_iter)
            .unwrap()
    };

    // Create immutable buffer and initialize it
    let immutable_data_buffer = {

        // uninitialized(), uninitialized_array() and raw() return two things: the buffer,
        // and a special access that should be used for the initial upload to the buffer.
        let (immutable_data_buffer, immutable_data_buffer_init) = unsafe {
            ImmutableBuffer::<u32>::uninitialized(device.clone(), BufferUsage::all()).unwrap()
        };

        // Build command buffer which initialize our buffer.
        let mut builder =
            AutoCommandBufferBuilder::primary_one_time_submit(device.clone(), queue.family())
                .unwrap();

        // Initializing a immutable buffer is done by coping data to
        // ImmutableBufferInitialization which is returned by a function we use to create buffer.
        // We can use copy_buffer(), fill_buffer() and some other functions that copies data to
        // buffer also.
        builder
            .update_buffer(immutable_data_buffer_init, &3)
            .unwrap();

        let command_buffer = builder.build().unwrap();

        let future = sync::now(device.clone())
            .then_execute(queue.clone(), command_buffer)
            .unwrap()
            .then_signal_fence_and_flush()
            .unwrap();

        future.wait(None).unwrap();

        // Once a buffer is initialized, we no longer need ImmutableBufferInitialization.
        // So we return only the buffer.
        immutable_data_buffer
    };

    let layout = pipeline.layout().descriptor_set_layout(0).unwrap();
    let set = Arc::new(
        PersistentDescriptorSet::start(layout.clone())
            .add_buffer(data_buffer.clone())
            .unwrap()
            // Now you can just add immutable buffer like other buffers.
            .add_buffer(immutable_data_buffer.clone())
            .unwrap()
            .build()
            .unwrap(),
    );

    let mut builder =
        AutoCommandBufferBuilder::primary_one_time_submit(device.clone(), queue.family()).unwrap();

    builder
        .dispatch([1024, 1, 1], pipeline.clone(), set.clone(), (), vec![])
        .unwrap();

    let command_buffer = builder.build().unwrap();

    let future = sync::now(device.clone())
        .then_execute(queue.clone(), command_buffer)
        .unwrap()
        .then_signal_fence_and_flush()
        .unwrap();

    future.wait(None).unwrap();

    let data_buffer_content = data_buffer.read().unwrap();
    for n in 0..65536u32 {
        assert_eq!(data_buffer_content[n as usize], n * 12 + 3);
    }
}
<|endoftext|>


<commit_before>// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use base::AsRawDescriptor;
use base::AsRawDescriptors;
use base::Event;
use base::RawDescriptor;
use base::Result;

/// A structure suitable for implementing edge triggered interrupts in device backends.
pub struct IrqEdgeEvent(Event);

impl IrqEdgeEvent {
    pub fn new() -> Result<IrqEdgeEvent> {
        Event::new().map(IrqEdgeEvent)
    }

    pub fn try_clone(&self) -> Result<IrqEdgeEvent> {
        self.0.try_clone().map(IrqEdgeEvent)
    }

    /// Creates an instance of IrqLevelEvent from an existing event.
    pub fn from_event(trigger_evt: Event) -> IrqEdgeEvent {
        IrqEdgeEvent(trigger_evt)
    }

    pub fn get_trigger(&self) -> &Event {
        &self.0
    }

    pub fn trigger(&self) -> Result<()> {
        self.0.write(1)
    }

    pub fn clear_trigger(&self) {
        let _ = self.0.read();
    }
}

/// A structure suitable for implementing level triggered interrupts in device backends.
pub struct IrqLevelEvent {
    /// An event used by the device backend to signal hypervisor/VM about data or new unit
    /// of work being available.
    trigger_evt: Event,
    /// An event used by the hypervisor to signal device backend that it completed processing
    /// a unit of work and that device should re-raise `trigger_evt` if there is additional
    /// work needs to be done.
    resample_evt: Event,
}

impl IrqLevelEvent {
    pub fn new() -> Result<IrqLevelEvent> {
        let trigger_evt = Event::new()?;
        let resample_evt = Event::new()?;
        Ok(IrqLevelEvent {
            trigger_evt,
            resample_evt,
        })
    }

    pub fn try_clone(&self) -> Result<IrqLevelEvent> {
        let trigger_evt = self.trigger_evt.try_clone()?;
        let resample_evt = self.resample_evt.try_clone()?;
        Ok(IrqLevelEvent {
            trigger_evt,
            resample_evt,
        })
    }

    /// Creates an instance of IrqLevelEvent from an existing pair of events.
    pub fn from_event_pair(trigger_evt: Event, resample_evt: Event) -> IrqLevelEvent {
        IrqLevelEvent {
            trigger_evt,
            resample_evt,
        }
    }

    pub fn get_trigger(&self) -> &Event {
        &self.trigger_evt
    }

    pub fn get_resample(&self) -> &Event {
        &self.resample_evt
    }

    /// Allows backend to inject interrupt (typically into guest).
    pub fn trigger(&self) -> Result<()> {
        self.trigger_evt.write(1)
    }

    /// Allows code servicing interrupt to consume or clear the event.
    pub fn clear_trigger(&self) {
        let _ = self.trigger_evt.read();
    }

    /// Allows code servicing interrupt to signal that processing is done and that the backend
    /// should go ahead and re-trigger it if there is more work needs to be done.
    /// Note that typically resampling is signalled not by individual backends, but rather
    /// by the code implementing interrupt controller.
    pub fn trigger_resample(&self) -> Result<()> {
        self.resample_evt.write(1)
    }

    /// Allows backend to consume or clear the resample event.
    pub fn clear_resample(&self) {
        let _ = self.resample_evt.read();
    }
}

impl AsRawDescriptors for IrqEdgeEvent {
    fn as_raw_descriptors(&self) -> Vec<RawDescriptor> {
        vec![self.0.as_raw_descriptor()]
    }
}

impl AsRawDescriptors for IrqLevelEvent {
    fn as_raw_descriptors(&self) -> Vec<RawDescriptor> {
        vec![
            self.trigger_evt.as_raw_descriptor(),
            self.resample_evt.as_raw_descriptor(),
        ]
    }
}
<commit_msg>devices: extend IrqLevelEvent documentation<commit_after>// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use base::AsRawDescriptor;
use base::AsRawDescriptors;
use base::Event;
use base::RawDescriptor;
use base::Result;

/// A structure suitable for implementing edge triggered interrupts in device backends.
pub struct IrqEdgeEvent(Event);

impl IrqEdgeEvent {
    pub fn new() -> Result<IrqEdgeEvent> {
        Event::new().map(IrqEdgeEvent)
    }

    pub fn try_clone(&self) -> Result<IrqEdgeEvent> {
        self.0.try_clone().map(IrqEdgeEvent)
    }

    /// Creates an instance of IrqLevelEvent from an existing event.
    pub fn from_event(trigger_evt: Event) -> IrqEdgeEvent {
        IrqEdgeEvent(trigger_evt)
    }

    pub fn get_trigger(&self) -> &Event {
        &self.0
    }

    pub fn trigger(&self) -> Result<()> {
        self.0.write(1)
    }

    pub fn clear_trigger(&self) {
        let _ = self.0.read();
    }
}

/// A structure suitable for implementing level triggered interrupts in device backends.
///
/// Level-triggered interrupts require the device to monitor a resample event from the IRQ chip,
/// which can be retrieved with [`IrqLevelEvent::get_resample()`]. When the guest OS acknowledges
/// the interrupt with an End of Interrupt (EOI) command, the IRQ chip will signal the resample
/// event. Each time the resample event is signalled, the device should re-check its state and call
/// [`IrqLevelEvent::trigger()`] again if the interrupt should still be asserted.
pub struct IrqLevelEvent {
    /// An event used by the device backend to signal hypervisor/VM about data or new unit
    /// of work being available.
    trigger_evt: Event,
    /// An event used by the hypervisor to signal device backend that it completed processing a unit
    /// of work and that device should re-raise `trigger_evt` if additional work needs to be done.
    resample_evt: Event,
}

impl IrqLevelEvent {
    pub fn new() -> Result<IrqLevelEvent> {
        let trigger_evt = Event::new()?;
        let resample_evt = Event::new()?;
        Ok(IrqLevelEvent {
            trigger_evt,
            resample_evt,
        })
    }

    pub fn try_clone(&self) -> Result<IrqLevelEvent> {
        let trigger_evt = self.trigger_evt.try_clone()?;
        let resample_evt = self.resample_evt.try_clone()?;
        Ok(IrqLevelEvent {
            trigger_evt,
            resample_evt,
        })
    }

    /// Creates an instance of IrqLevelEvent from an existing pair of events.
    pub fn from_event_pair(trigger_evt: Event, resample_evt: Event) -> IrqLevelEvent {
        IrqLevelEvent {
            trigger_evt,
            resample_evt,
        }
    }

    pub fn get_trigger(&self) -> &Event {
        &self.trigger_evt
    }

    pub fn get_resample(&self) -> &Event {
        &self.resample_evt
    }

    /// Allows backend to inject interrupt (typically into guest).
    pub fn trigger(&self) -> Result<()> {
        self.trigger_evt.write(1)
    }

    /// Allows code servicing interrupt to consume or clear the event.
    pub fn clear_trigger(&self) {
        let _ = self.trigger_evt.read();
    }

    /// Allows code servicing interrupt to signal that processing is done and that the backend
    /// should go ahead and re-trigger it if there is more work needs to be done.
    /// Note that typically resampling is signalled not by individual backends, but rather
    /// by the code implementing interrupt controller.
    pub fn trigger_resample(&self) -> Result<()> {
        self.resample_evt.write(1)
    }

    /// Allows backend to consume or clear the resample event.
    pub fn clear_resample(&self) {
        let _ = self.resample_evt.read();
    }
}

impl AsRawDescriptors for IrqEdgeEvent {
    fn as_raw_descriptors(&self) -> Vec<RawDescriptor> {
        vec![self.0.as_raw_descriptor()]
    }
}

impl AsRawDescriptors for IrqLevelEvent {
    fn as_raw_descriptors(&self) -> Vec<RawDescriptor> {
        vec![
            self.trigger_evt.as_raw_descriptor(),
            self.resample_evt.as_raw_descriptor(),
        ]
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// 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. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::marker::PhantomData;
use std::ptr;
use std::sync::atomic::AtomicBool;
use std::sync::Arc;

use buffer::TrackedBuffer;
use command_buffer::pool::AllocatedCommandBuffer;
use command_buffer::pool::CommandPool;
use command_buffer::CommandsList;
use command_buffer::CommandsListSink;
use command_buffer::CommandsListSinkCaller;
use command_buffer::DynamicState;
use command_buffer::RawCommandBufferPrototype;
use command_buffer::StatesManager;
use device::Device;
use framebuffer::RenderPass;
use framebuffer::Subpass;
use framebuffer::traits::Framebuffer;
use image::Layout;
use image::TrackedImage;
use sync::AccessFlagBits;
use sync::PipelineStages;

use OomError;
use VulkanObject;
use VulkanPointers;
use check_errors;
use vk;

/// Determines the kind of command buffer that we want to create.
#[derive(Debug, Clone)]
pub enum Kind<'a, R, F: 'a> {
    /// A primary command buffer can execute all commands and can call secondary command buffers.
    Primary,

    /// A secondary command buffer can execute all dispatch and transfer operations, but not
    /// drawing operations.
    Secondary,

    /// A secondary command buffer within a render pass can only call draw operations that can
    /// be executed from within a specific subpass.
    SecondaryRenderPass {
        /// Which subpass this secondary command buffer can be called from.
        subpass: Subpass<R>,
        /// The framebuffer object that will be used when calling the command buffer.
        /// This parameter is optional and is an optimization hint for the implementation.
        framebuffer: Option<&'a F>,
    },
}

/// Flags to pass when creating a command buffer.
///
/// The safest option is `SimultaneousUse`, but it may be slower than the other two.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Flags {
    /// The command buffer can be used multiple times, but must not execute more than once
    /// simultaneously.
    None,

    /// The command buffer can be executed multiple times in parallel.
    SimultaneousUse,

    /// The command buffer can only be submitted once. Any further submit is forbidden.
    OneTimeSubmit,
}

pub struct UnsyncedCommandBuffer<L, P> where P: CommandPool {
    // The Vulkan command buffer.
    cmd: vk::CommandBuffer,

    // Device that owns the command buffer.
    device: Arc<Device>,

    // Pool that owns the command buffer.
    pool: P::Finished,

    // Flags that were used at creation.
    flags: Flags,

    // True if the command buffer has always been submitted once. Only relevant if `flags` is
    // `OneTimeSubmit`.
    already_submitted: AtomicBool,

    // True if we are a secondary command buffer.
    secondary_cb: bool,

    // The commands list. Holds resources of the resources list alive.
    commands_list: L,
}

impl<L, P> UnsyncedCommandBuffer<L, P> where L: CommandsList, P: CommandPool {
    /// Creates a new builder.
    pub unsafe fn new<R, F>(list: L, pool: P, kind: Kind<R, F>, flags: Flags)
                            -> Result<UnsyncedCommandBuffer<L, P>, OomError>
        where R: RenderPass, F: Framebuffer
    {
        let secondary = match kind {
            Kind::Primary => false,
            Kind::Secondary | Kind::SecondaryRenderPass { .. } => true,
        };

        let cmd = try!(pool.alloc(secondary, 1)).next().unwrap();

        match UnsyncedCommandBuffer::already_allocated(list, pool, cmd, kind, flags) {
            Ok(cmd) => Ok(cmd),
            Err(err) => {
                // FIXME: uncomment this and solve the fact that `pool` has been moved
                //unsafe { pool.free(secondary, Some(cmd.into()).into_iter()) };
                Err(err)
            },
        }
    }

    /// Creates a new command buffer builder from an already-allocated command buffer.
    ///
    /// # Safety
    ///
    /// - The allocated command buffer must belong to the pool and must not be used anywhere else
    ///   in the code for the duration of this command buffer.
    ///
    pub unsafe fn already_allocated<R, F>(list: L, pool: P, cmd: AllocatedCommandBuffer,
                                          kind: Kind<R, F>, flags: Flags)
                                          -> Result<UnsyncedCommandBuffer<L, P>, OomError>
        where R: RenderPass, F: Framebuffer
    {
        let device = pool.device().clone();
        let vk = device.pointers();
        let cmd = cmd.internal_object();

        let vk_flags = {
            let a = match flags {
                Flags::None => 0,
                Flags::SimultaneousUse => vk::COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT,
                Flags::OneTimeSubmit => vk::COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
            };

            let b = match kind {
                Kind::Primary | Kind::Secondary => 0,
                Kind::SecondaryRenderPass { .. } => {
                    vk::COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT
                },
            };

            a | b
        };

        let (rp, sp) = if let Kind::SecondaryRenderPass { ref subpass, .. } = kind {
            (subpass.render_pass().inner().internal_object(), subpass.index())
        } else {
            (0, 0)
        };

        let framebuffer = if let Kind::SecondaryRenderPass { ref subpass, framebuffer: Some(ref framebuffer) } = kind {
            // TODO: restore check
            //assert!(framebuffer.is_compatible_with(subpass.render_pass()));     // TODO: proper error
            framebuffer.internal_object()
        } else {
            0
        };

        let inheritance = vk::CommandBufferInheritanceInfo {
            sType: vk::STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
            pNext: ptr::null(),
            renderPass: rp,
            subpass: sp,
            framebuffer: framebuffer,
            occlusionQueryEnable: 0,            // TODO:
            queryFlags: 0,          // TODO:
            pipelineStatistics: 0,          // TODO:
        };

        let infos = vk::CommandBufferBeginInfo {
            sType: vk::STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
            pNext: ptr::null(),
            flags: vk_flags,
            pInheritanceInfo: &inheritance,
        };

        try!(check_errors(vk.BeginCommandBuffer(cmd, &infos)));

        {
            let mut builder = RawCommandBufferPrototype {
                device: device.clone(),
                command_buffer: Some(cmd),
                current_state: DynamicState::none(),
                bound_graphics_pipeline: 0,
                bound_compute_pipeline: 0,
                bound_index_buffer: (0, 0, 0),
                resources_states: StatesManager::new(),
                marker: PhantomData,
            };

            list.append(&mut Sink(&mut builder, &device));
        };

        try!(check_errors(vk.EndCommandBuffer(cmd)));

        Ok(UnsyncedCommandBuffer {
            device: device.clone(),
            pool: pool.finish(),
            cmd: cmd,
            flags: flags,
            secondary_cb: match kind {
                Kind::Primary => false,
                Kind::Secondary | Kind::SecondaryRenderPass { .. } => true,
            },
            already_submitted: AtomicBool::new(false),
            commands_list: list,
        })
    }
}

// Helper object for UnsyncedCommandBuffer. Implementation detail.
struct Sink<'a>(&'a mut RawCommandBufferPrototype<'a>, &'a Arc<Device>);
impl<'a> CommandsListSink<'a> for Sink<'a> {
    #[inline]
    fn device(&self) -> &Arc<Device> {
        self.1
    }

    #[inline]
    fn add_command(&mut self, f: Box<CommandsListSinkCaller<'a> + 'a>) {
        f.call(self.0)
    }

    #[inline]
    fn add_buffer_transition(&mut self, _: &TrackedBuffer, _: usize, _: usize, _: bool,
                             _: PipelineStages, _: AccessFlagBits)
    {
    }

    #[inline]
    fn add_image_transition(&mut self, _: &TrackedImage, _: u32, _: u32, _: u32, _: u32,
                            _: bool, _: Layout, _: PipelineStages, _: AccessFlagBits)
    {
    }

    #[inline]
    fn add_image_transition_notification(&mut self, _: &TrackedImage, _: u32, _: u32, _: u32,
                                         _: u32, _: Layout, _: PipelineStages, _: AccessFlagBits)
    {
    }
}
<commit_msg>Add Kind::primary()<commit_after>// Copyright (c) 2016 The vulkano developers
// 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. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::marker::PhantomData;
use std::ptr;
use std::sync::atomic::AtomicBool;
use std::sync::Arc;

use buffer::TrackedBuffer;
use command_buffer::pool::AllocatedCommandBuffer;
use command_buffer::pool::CommandPool;
use command_buffer::CommandsList;
use command_buffer::CommandsListSink;
use command_buffer::CommandsListSinkCaller;
use command_buffer::DynamicState;
use command_buffer::RawCommandBufferPrototype;
use command_buffer::StatesManager;
use device::Device;
use framebuffer::EmptySinglePassRenderPass;
use framebuffer::RenderPass;
use framebuffer::StdFramebuffer;
use framebuffer::Subpass;
use framebuffer::traits::Framebuffer;
use image::Layout;
use image::TrackedImage;
use sync::AccessFlagBits;
use sync::PipelineStages;

use OomError;
use VulkanObject;
use VulkanPointers;
use check_errors;
use vk;

/// Determines the kind of command buffer that we want to create.
#[derive(Debug, Clone)]
pub enum Kind<'a, R, F: 'a> {
    /// A primary command buffer can execute all commands and can call secondary command buffers.
    Primary,

    /// A secondary command buffer can execute all dispatch and transfer operations, but not
    /// drawing operations.
    Secondary,

    /// A secondary command buffer within a render pass can only call draw operations that can
    /// be executed from within a specific subpass.
    SecondaryRenderPass {
        /// Which subpass this secondary command buffer can be called from.
        subpass: Subpass<R>,
        /// The framebuffer object that will be used when calling the command buffer.
        /// This parameter is optional and is an optimization hint for the implementation.
        framebuffer: Option<&'a F>,
    },
}

impl<'a> Kind<'a, EmptySinglePassRenderPass, StdFramebuffer<EmptySinglePassRenderPass, ()>> {
    /// Equivalent to `Kind::Primary`.
    ///
    /// > **Note**: If you use `let kind = Kind::Primary;` in your code, you will probably get a
    /// > compilation error because the Rust compiler couldn't determine the template parameters
    /// > of `Kind`. To solve that problem in an easy way you can use this function instead.
    #[inline]
    pub fn primary() -> Kind<'a, EmptySinglePassRenderPass, StdFramebuffer<EmptySinglePassRenderPass, ()>> {
        Kind::Primary
    }
}

/// Flags to pass when creating a command buffer.
///
/// The safest option is `SimultaneousUse`, but it may be slower than the other two.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Flags {
    /// The command buffer can be used multiple times, but must not execute more than once
    /// simultaneously.
    None,

    /// The command buffer can be executed multiple times in parallel.
    SimultaneousUse,

    /// The command buffer can only be submitted once. Any further submit is forbidden.
    OneTimeSubmit,
}

pub struct UnsyncedCommandBuffer<L, P> where P: CommandPool {
    // The Vulkan command buffer.
    cmd: vk::CommandBuffer,

    // Device that owns the command buffer.
    device: Arc<Device>,

    // Pool that owns the command buffer.
    pool: P::Finished,

    // Flags that were used at creation.
    flags: Flags,

    // True if the command buffer has always been submitted once. Only relevant if `flags` is
    // `OneTimeSubmit`.
    already_submitted: AtomicBool,

    // True if we are a secondary command buffer.
    secondary_cb: bool,

    // The commands list. Holds resources of the resources list alive.
    commands_list: L,
}

impl<L, P> UnsyncedCommandBuffer<L, P> where L: CommandsList, P: CommandPool {
    /// Creates a new builder.
    pub unsafe fn new<R, F>(list: L, pool: P, kind: Kind<R, F>, flags: Flags)
                            -> Result<UnsyncedCommandBuffer<L, P>, OomError>
        where R: RenderPass, F: Framebuffer
    {
        let secondary = match kind {
            Kind::Primary => false,
            Kind::Secondary | Kind::SecondaryRenderPass { .. } => true,
        };

        let cmd = try!(pool.alloc(secondary, 1)).next().unwrap();

        match UnsyncedCommandBuffer::already_allocated(list, pool, cmd, kind, flags) {
            Ok(cmd) => Ok(cmd),
            Err(err) => {
                // FIXME: uncomment this and solve the fact that `pool` has been moved
                //unsafe { pool.free(secondary, Some(cmd.into()).into_iter()) };
                Err(err)
            },
        }
    }

    /// Creates a new command buffer builder from an already-allocated command buffer.
    ///
    /// # Safety
    ///
    /// - The allocated command buffer must belong to the pool and must not be used anywhere else
    ///   in the code for the duration of this command buffer.
    ///
    pub unsafe fn already_allocated<R, F>(list: L, pool: P, cmd: AllocatedCommandBuffer,
                                          kind: Kind<R, F>, flags: Flags)
                                          -> Result<UnsyncedCommandBuffer<L, P>, OomError>
        where R: RenderPass, F: Framebuffer
    {
        let device = pool.device().clone();
        let vk = device.pointers();
        let cmd = cmd.internal_object();

        let vk_flags = {
            let a = match flags {
                Flags::None => 0,
                Flags::SimultaneousUse => vk::COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT,
                Flags::OneTimeSubmit => vk::COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
            };

            let b = match kind {
                Kind::Primary | Kind::Secondary => 0,
                Kind::SecondaryRenderPass { .. } => {
                    vk::COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT
                },
            };

            a | b
        };

        let (rp, sp) = if let Kind::SecondaryRenderPass { ref subpass, .. } = kind {
            (subpass.render_pass().inner().internal_object(), subpass.index())
        } else {
            (0, 0)
        };

        let framebuffer = if let Kind::SecondaryRenderPass { ref subpass, framebuffer: Some(ref framebuffer) } = kind {
            // TODO: restore check
            //assert!(framebuffer.is_compatible_with(subpass.render_pass()));     // TODO: proper error
            framebuffer.internal_object()
        } else {
            0
        };

        let inheritance = vk::CommandBufferInheritanceInfo {
            sType: vk::STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
            pNext: ptr::null(),
            renderPass: rp,
            subpass: sp,
            framebuffer: framebuffer,
            occlusionQueryEnable: 0,            // TODO:
            queryFlags: 0,          // TODO:
            pipelineStatistics: 0,          // TODO:
        };

        let infos = vk::CommandBufferBeginInfo {
            sType: vk::STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
            pNext: ptr::null(),
            flags: vk_flags,
            pInheritanceInfo: &inheritance,
        };

        try!(check_errors(vk.BeginCommandBuffer(cmd, &infos)));

        {
            let mut builder = RawCommandBufferPrototype {
                device: device.clone(),
                command_buffer: Some(cmd),
                current_state: DynamicState::none(),
                bound_graphics_pipeline: 0,
                bound_compute_pipeline: 0,
                bound_index_buffer: (0, 0, 0),
                resources_states: StatesManager::new(),
                marker: PhantomData,
            };

            list.append(&mut Sink(&mut builder, &device));
        };

        try!(check_errors(vk.EndCommandBuffer(cmd)));

        Ok(UnsyncedCommandBuffer {
            device: device.clone(),
            pool: pool.finish(),
            cmd: cmd,
            flags: flags,
            secondary_cb: match kind {
                Kind::Primary => false,
                Kind::Secondary | Kind::SecondaryRenderPass { .. } => true,
            },
            already_submitted: AtomicBool::new(false),
            commands_list: list,
        })
    }
}

// Helper object for UnsyncedCommandBuffer. Implementation detail.
struct Sink<'a>(&'a mut RawCommandBufferPrototype<'a>, &'a Arc<Device>);
impl<'a> CommandsListSink<'a> for Sink<'a> {
    #[inline]
    fn device(&self) -> &Arc<Device> {
        self.1
    }

    #[inline]
    fn add_command(&mut self, f: Box<CommandsListSinkCaller<'a> + 'a>) {
        f.call(self.0)
    }

    #[inline]
    fn add_buffer_transition(&mut self, _: &TrackedBuffer, _: usize, _: usize, _: bool,
                             _: PipelineStages, _: AccessFlagBits)
    {
    }

    #[inline]
    fn add_image_transition(&mut self, _: &TrackedImage, _: u32, _: u32, _: u32, _: u32,
                            _: bool, _: Layout, _: PipelineStages, _: AccessFlagBits)
    {
    }

    #[inline]
    fn add_image_transition_notification(&mut self, _: &TrackedImage, _: u32, _: u32, _: u32,
                                         _: u32, _: Layout, _: PipelineStages, _: AccessFlagBits)
    {
    }
}
<|endoftext|>


<commit_before>extern crate fitsio;
#[macro_use]
extern crate fitsio_derive;
extern crate tempdir;

/* This example docuents the following things:
 *
 * creating a new file
 * writing header keys
 * writing an image into the primary hdu
 * creating a table
 * adding data to a table
 * closing the file
 * re-opening it
 * reading an image region
 * reading some rows from a table column
 */

use std::error::Error;
use tempdir::TempDir;

use fitsio::images::{ImageDescription, ImageType};
use fitsio::tables::{ColumnDataType, ColumnDescription, FitsRow};
use fitsio::FitsFile;

fn run() -> Result<(), Box<Error>> {
    /* Create a temporary directory to work from */
    let tmp_dir = TempDir::new("fitsio")?;
    let file_path = tmp_dir.path().join("example.fits");

    // creating a new file with 512 rows and 1024 columns
    let primary_hdu_description = ImageDescription {
        data_type: ImageType::Double,
        dimensions: &[512, 1024],
    };

    {
        // .overwrite ensures that if the file already exists, the existing file is removed first.
        let mut fitsfile = FitsFile::create(&file_path)
            .with_custom_primary(&primary_hdu_description)
            .overwrite()
            .open()?;

        /* We will now add some dummy header keys. We add:
         * - the name of the project (String)
         * - the exposure time (f32)
         * - the image id (i64)
         */

        /* First we get the primary HDU */
        let hdu = fitsfile.primary_hdu()?;

        /* Now we add the header keys */
        hdu.write_key(&mut fitsfile, "PROJECT", "My First Astronomy Project")?;

        /* Now the exposure time */
        hdu.write_key(&mut fitsfile, "EXPTIME", 15.2f32)?;

        /* And finally the image id */
        hdu.write_key(&mut fitsfile, "IMAGE_ID", 20180101010005i64)?;

        /* Now we write some dummy data to the primary HDU. We write the full image in this case.
         * */

        let dummy_data: Vec<f32> = (0..(1024 * 512))
            .map(|val| (val as f32) * 12.5 + 102.5)
            .collect();

        hdu.write_image(&mut fitsfile, &dummy_data)?;

        /* We can create a new image with the following */
        let image_description = ImageDescription {
            data_type: ImageType::Long,
            dimensions: &[256, 256],
        };
        fitsfile.create_image("IMG", &image_description)?;

        /* Now we add a new table HDU called "DATA"
         *
         * We add three columns:
         *
         * 1. Object id (i32)
         * 2. Object name (String, up to 10 characters)
         * 3. Object magnitude (f32)
         * */
        let col1 = ColumnDescription::new("OBJ_ID")
            .with_type(ColumnDataType::Int)
            .create()?;
        let col2 = ColumnDescription::new("NAME")
            .with_type(ColumnDataType::String)
            .that_repeats(10)
            .create()?;
        let col3 = ColumnDescription::new("MAG")
            .with_type(ColumnDataType::Float)
            .create()?;
        let columns = &[col1, col2, col3];
        let table_hdu = fitsfile.create_table("DATA", columns)?;

        /* Add some data to the columns */
        let n_rows = 10;
        let obj_id_data: Vec<i32> = (0..n_rows).collect();
        let name_data: Vec<String> = (0..n_rows).map(|idx| format!("N{}", idx)).collect();
        let mag_data: Vec<f32> = (0..n_rows).map(|idx| -0.2 * idx as f32).collect();

        table_hdu.write_col(&mut fitsfile, "OBJ_ID", &obj_id_data)?;
        table_hdu.write_col(&mut fitsfile, "NAME", &name_data)?;
        table_hdu.write_col(&mut fitsfile, "MAG", &mag_data)?;

        /* `fitsfile` is dropped here at the end of the scope, which closes fhe file on disk */
    }

    /* Here we re-open the file. We want to adjust things, so we use the `edit` method */
    let mut fitsfile = FitsFile::edit(&file_path)?;

    /* Print the fits file contents to stdout */
    fitsfile.pretty_print().expect("printing fits file");

    /* Get the primary HDU and read a section of the image data */
    let phdu = fitsfile.primary_hdu()?;

    /* Let's say we have a region around a star that we want to extract. The star is at (25, 25,
     * 1-indexed) and we want to extract a 5x5 box around it. This means we want to read rows 19 to
     * 19, and columns 19 to 29 (0-indexed). The range arguments are exclusive of the upper bound,
     * so we must use 19..29 for each axis.
     *
     * Note: this is not performant, and if this is the desired use of `fitsio`, I would not
     * suggest this approach. */
    let image_data: Vec<f32> = phdu.read_region(&mut fitsfile, &[&(19..29), &(19..29)])?;
    assert_eq!(image_data.len(), 100);

    /* We can now get the column data. Let's assume we want all of the magnitudes for objects near
     * this one (by index). This object is at index 4 (0-indexed) and we want to read one value
     * before and after it. */
    let table_hdu = fitsfile.hdu("DATA")?;
    let magnitudes: Vec<f32> = table_hdu.read_col_range(&mut fitsfile, "MAG", &(3..6))?;
    assert_eq!(magnitudes.len(), 3);

    /* Read a single row from the file. Columns can be renamed to allow for more rustic attribute
     * names */
    #[derive(Default, FitsRow)]
    struct Row {
        #[fitsio(colname = "OBJ_ID")]
        obj_id: i32,
        #[fitsio(colname = "NAME")]
        name: String,
        #[fitsio(colname = "MAG")]
        mag: f32,
    }
    let row: Row = table_hdu.row(&mut fitsfile, 4)?;
    assert_eq!(row.obj_id, 4);
    assert_eq!(row.name, "N4");
    assert!(row.mag > -1.0 && row.mag < -0.5);

    /* The file is closed when it is dropped here */

    Ok(())
}

fn main() {
    run().unwrap();
}
<commit_msg>Update example<commit_after>extern crate fitsio;
#[macro_use]
extern crate fitsio_derive;
extern crate tempdir;

/* This example docuents the following things:
 *
 * creating a new file
 * writing header keys
 * writing an image into the primary hdu
 * creating a table
 * adding data to a table
 * closing the file
 * re-opening it
 * reading an image region
 * reading some rows from a table column
 */

use std::error::Error;
use tempdir::TempDir;

use fitsio::images::{ImageDescription, ImageType};
use fitsio::tables::{ColumnDataType, ColumnDescription, FitsRow};
use fitsio::FitsFile;

fn run() -> Result<(), Box<Error>> {
    /* Create a temporary directory to work from */
    let tmp_dir = TempDir::new("fitsio")?;
    let file_path = tmp_dir.path().join("example.fits");

    // creating a new file with 512 rows and 1024 columns
    let primary_hdu_description = ImageDescription {
        data_type: ImageType::Double,
        dimensions: &[512, 1024],
    };

    {
        // .overwrite ensures that if the file already exists, the existing file is removed first.
        let mut fitsfile = FitsFile::create(&file_path)
            .with_custom_primary(&primary_hdu_description)
            .overwrite()
            .open()?;

        /* We will now add some dummy header keys. We add:
         * - the name of the project (String)
         * - the exposure time (f32)
         * - the image id (i64)
         */

        /* First we get the primary HDU */
        let hdu = fitsfile.primary_hdu()?;

        /* Now we add the header keys */
        hdu.write_key(&mut fitsfile, "PROJECT", "My First Astronomy Project")?;

        /* Now the exposure time */
        hdu.write_key(&mut fitsfile, "EXPTIME", 15.2f32)?;

        /* And finally the image id */
        hdu.write_key(&mut fitsfile, "IMAGE_ID", 20180101010005i64)?;

        /* Now we write some dummy data to the primary HDU. We write the full image in this case.
         * */

        let dummy_data: Vec<f32> = (0..(1024 * 512))
            .map(|val| (val as f32) * 12.5 + 102.5)
            .collect();

        hdu.write_image(&mut fitsfile, &dummy_data)?;

        /* We can create a new image with the following */
        let image_description = ImageDescription {
            data_type: ImageType::Long,
            dimensions: &[256, 256],
        };
        fitsfile.create_image("IMG", &image_description)?;

        /* Now we add a new table HDU called "DATA"
         *
         * We add three columns:
         *
         * 1. Object id (i32)
         * 2. Object name (String, up to 10 characters)
         * 3. Object magnitude (f32)
         * */
        let col1 = ColumnDescription::new("OBJ_ID")
            .with_type(ColumnDataType::Int)
            .create()?;
        let col2 = ColumnDescription::new("NAME")
            .with_type(ColumnDataType::String)
            .that_repeats(10)
            .create()?;
        let col3 = ColumnDescription::new("MAG")
            .with_type(ColumnDataType::Float)
            .create()?;
        let columns = &[col1, col2, col3];
        let table_hdu = fitsfile.create_table("DATA", columns)?;

        /* Add some data to the columns */
        let n_rows = 10;
        let obj_id_data: Vec<i32> = (0..n_rows).collect();
        let name_data: Vec<String> = (0..n_rows).map(|idx| format!("N{}", idx)).collect();
        let mag_data: Vec<f32> = (0..n_rows).map(|idx| -0.2 * idx as f32).collect();

        table_hdu.write_col(&mut fitsfile, "OBJ_ID", &obj_id_data)?;
        table_hdu.write_col(&mut fitsfile, "NAME", &name_data)?;
        table_hdu.write_col(&mut fitsfile, "MAG", &mag_data)?;

        /* `fitsfile` is dropped here at the end of the scope, which closes fhe file on disk */
    }

    /* Here we re-open the file. We want to adjust things, so we use the `edit` method */
    let mut fitsfile = FitsFile::edit(&file_path)?;

    /* Print the fits file contents to stdout */
    fitsfile.pretty_print().expect("printing fits file");

    /* Get the primary HDU and read a section of the image data */
    let phdu = fitsfile.primary_hdu()?;

    /* Let's say we have a region around a star that we want to extract. The star is at (25, 25,
     * 1-indexed) and we want to extract a 5x5 box around it. This means we want to read rows 19 to
     * 19, and columns 19 to 29 (0-indexed). The range arguments are exclusive of the upper bound,
     * so we must use 19..29 for each axis.
     *
     * Note: this is not performant, and if this is the desired use of `fitsio`, I would not
     * suggest this approach. */
    let image_data: Vec<f32> = phdu.read_region(&mut fitsfile, &[&(19..29), &(19..29)])?;
    assert_eq!(image_data.len(), 121);

    /* We can now get the column data. Let's assume we want all of the magnitudes for objects near
     * this one (by index). This object is at index 4 (0-indexed) and we want to read one value
     * before and after it. */
    let table_hdu = fitsfile.hdu("DATA")?;
    let magnitudes: Vec<f32> = table_hdu.read_col_range(&mut fitsfile, "MAG", &(3..6))?;
    assert_eq!(magnitudes.len(), 3);

    /* Read a single row from the file. Columns can be renamed to allow for more rustic attribute
     * names */
    #[derive(Default, FitsRow)]
    struct Row {
        #[fitsio(colname = "OBJ_ID")]
        obj_id: i32,
        #[fitsio(colname = "NAME")]
        name: String,
        #[fitsio(colname = "MAG")]
        mag: f32,
    }
    let row: Row = table_hdu.row(&mut fitsfile, 4)?;
    assert_eq!(row.obj_id, 4);
    assert_eq!(row.name, "N4");
    assert!(row.mag > -1.0 && row.mag < -0.5);

    /* The file is closed when it is dropped here */

    Ok(())
}

fn main() {
    run().unwrap();
}
<|endoftext|>


<commit_before>use std::io::{self, Read, Write};

use futures::{Poll, Task};
use futures::stream::Stream;

use Ready;

/// An I/O object which can be used to track the read/write readiness of an
/// underlying object.
///
/// Many I/O objects implement a stream of readiness with "edge" semantics where
/// once a notification is returned another one will never be returned until the
/// stream is not ready for I/O. That is, once a stream receives a `Read`
/// notification, it will never receive another one until all the pending data
/// has been read.
///
/// This object will keep track of this and implements two methods,
/// `maybe_read_ready` and `maybe_write_ready`. If an appropriate notification
/// has been seen in the `Stream` implementation and `WouldBlock` has *not*
/// been seen yet from the `Read` and `Write` implementations, these methods
/// will return `true`. Otherwise, if `WouldBlock` has been seen, then the
/// methods will return `false`.
///
/// This abstraction can be useful when readiness notifications need to be
/// translated to different readiness notifications at a particular I/O layer.
/// For example if an underlying stream is readable it doesn't necessarily mean
/// the outer stream may always be readable, and this object can be used to keep
/// track of all the notifications.
pub struct ReadyTracker<S> {
    inner: S,
    read_ready: bool,
    write_ready: bool,
}

impl<S> ReadyTracker<S>
    where S: Stream<Item=Ready, Error=io::Error>,
{
    /// Creates a new I/O object ready to track read/write notifications.
    pub fn new(s: S) -> ReadyTracker<S> {
        ReadyTracker {
            inner: s,
            read_ready: false,
            write_ready: false,
        }
    }
}

impl<S> ReadyTracker<S> {
    /// Returns whether the underlying stream might be ready for a read.
    ///
    /// A stream may be ready for a read when a `Read` notification was seen
    /// from the `Stream::poll` implementation, and the object has not be `read`
    /// enough to see `WouldBlock` yet.
    pub fn maybe_read_ready(&self) -> bool {
        self.read_ready
    }

    /// Returns whether the underlying stream might be ready for a write.
    ///
    /// A stream may be ready for a write when a `Write` notification was seen
    /// from the `Stream::poll` implementation, and the object has not be
    /// `write` enough to see `WouldBlock` yet.
    pub fn maybe_write_ready(&self) -> bool {
        self.write_ready
    }
}

impl<S> Stream for ReadyTracker<S>
    where S: Stream<Item=Ready, Error=io::Error>,
{
    type Item = Ready;
    type Error = io::Error;

    fn poll(&mut self, task: &mut Task) -> Poll<Option<Ready>, io::Error> {
        match self.inner.poll(task) {
            Poll::Ok(Some(ready)) => {
                self.read_ready = self.read_ready || ready.is_read();
                self.write_ready = self.write_ready || ready.is_write();
                Poll::Ok(Some(ready))
            }
            other => other,
        }
    }

    fn schedule(&mut self, task: &mut Task) {
        self.inner.schedule(task)
    }
}

fn is_wouldblock<T>(res: &io::Result<T>) -> bool {
    match *res {
        Ok(_) => false,
        Err(ref e) => e.kind() == io::ErrorKind::WouldBlock,
    }
}

impl<S: Read> Read for ReadyTracker<S> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let res = self.inner.read(buf);
        if is_wouldblock(&res) {
            debug!("read no longer ready");
            self.read_ready = false;
        }
        return res
    }
}

impl<S: Write> Write for ReadyTracker<S> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let res = self.inner.write(buf);
        if is_wouldblock(&res) {
            debug!("write no longer ready");
            self.write_ready = false;
        }
        return res
    }

    fn flush(&mut self) -> io::Result<()> {
        let res = self.inner.flush();
        if is_wouldblock(&res) {
            debug!("write no longer ready");
            self.write_ready = false;
        }
        return res
    }
}

<commit_msg>Assume read/write ready in ReadTracker at start<commit_after>use std::io::{self, Read, Write};

use futures::{Poll, Task};
use futures::stream::Stream;

use Ready;

/// An I/O object which can be used to track the read/write readiness of an
/// underlying object.
///
/// Many I/O objects implement a stream of readiness with "edge" semantics where
/// once a notification is returned another one will never be returned until the
/// stream is not ready for I/O. That is, once a stream receives a `Read`
/// notification, it will never receive another one until all the pending data
/// has been read.
///
/// This object will keep track of this and implements two methods,
/// `maybe_read_ready` and `maybe_write_ready`. If an appropriate notification
/// has been seen in the `Stream` implementation and `WouldBlock` has *not*
/// been seen yet from the `Read` and `Write` implementations, these methods
/// will return `true`. Otherwise, if `WouldBlock` has been seen, then the
/// methods will return `false`.
///
/// This abstraction can be useful when readiness notifications need to be
/// translated to different readiness notifications at a particular I/O layer.
/// For example if an underlying stream is readable it doesn't necessarily mean
/// the outer stream may always be readable, and this object can be used to keep
/// track of all the notifications.
pub struct ReadyTracker<S> {
    inner: S,
    read_ready: bool,
    write_ready: bool,
}

impl<S> ReadyTracker<S>
    where S: Stream<Item=Ready, Error=io::Error>,
{
    /// Creates a new I/O object ready to track read/write notifications.
    pub fn new(s: S) -> ReadyTracker<S> {
        ReadyTracker {
            inner: s,
            read_ready: true,
            write_ready: true,
        }
    }
}

impl<S> ReadyTracker<S> {
    /// Returns whether the underlying stream might be ready for a read.
    ///
    /// A stream may be ready for a read when a `Read` notification was seen
    /// from the `Stream::poll` implementation, and the object has not be `read`
    /// enough to see `WouldBlock` yet.
    pub fn maybe_read_ready(&self) -> bool {
        self.read_ready
    }

    /// Returns whether the underlying stream might be ready for a write.
    ///
    /// A stream may be ready for a write when a `Write` notification was seen
    /// from the `Stream::poll` implementation, and the object has not be
    /// `write` enough to see `WouldBlock` yet.
    pub fn maybe_write_ready(&self) -> bool {
        self.write_ready
    }
}

impl<S> Stream for ReadyTracker<S>
    where S: Stream<Item=Ready, Error=io::Error>,
{
    type Item = Ready;
    type Error = io::Error;

    fn poll(&mut self, task: &mut Task) -> Poll<Option<Ready>, io::Error> {
        match self.inner.poll(task) {
            Poll::Ok(Some(ready)) => {
                self.read_ready = self.read_ready || ready.is_read();
                self.write_ready = self.write_ready || ready.is_write();
                Poll::Ok(Some(ready))
            }
            other => other,
        }
    }

    fn schedule(&mut self, task: &mut Task) {
        self.inner.schedule(task)
    }
}

fn is_wouldblock<T>(res: &io::Result<T>) -> bool {
    match *res {
        Ok(_) => false,
        Err(ref e) => e.kind() == io::ErrorKind::WouldBlock,
    }
}

impl<S: Read> Read for ReadyTracker<S> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let res = self.inner.read(buf);
        if is_wouldblock(&res) {
            debug!("read no longer ready");
            self.read_ready = false;
        }
        return res
    }
}

impl<S: Write> Write for ReadyTracker<S> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let res = self.inner.write(buf);
        if is_wouldblock(&res) {
            debug!("write no longer ready");
            self.write_ready = false;
        }
        return res
    }

    fn flush(&mut self) -> io::Result<()> {
        let res = self.inner.flush();
        if is_wouldblock(&res) {
            debug!("write no longer ready");
            self.write_ready = false;
        }
        return res
    }
}

<|endoftext|>


<commit_before>pub mod common;
pub mod index_resource;
pub mod show_resource;
pub mod image_resource;
pub mod default_resource;
pub mod web_resource;

use std::default::Default;

#[derive(Clone)]
pub enum ChannelItemType {
    Show(ChannelShowItem),
    Index(ChannelIndexItem),
    Image(ChannelImageItem)
}

#[derive(Clone)]
#[derive(Default)]
pub struct ChannelIndexItem { }

#[derive(Clone)]
#[derive(Default)]
pub struct ChannelShowItem {
    pub postid: String,
    pub page: usize,
}

#[derive(Default)]
pub struct ChannelItem {
    pub extra: Option<ChannelItemType>,
    pub result: String
}

#[derive(Clone)]
#[derive(Default)]
pub struct ChannelImageItem {
    pub url: String,
    pub bytes: Vec<u8>
}
<commit_msg>make channel item debug-able<commit_after>pub mod common;
pub mod index_resource;
pub mod show_resource;
pub mod image_resource;
pub mod default_resource;
pub mod web_resource;

use std::default::Default;

#[derive(Debug)]
#[derive(Clone)]
pub enum ChannelItemType {
    Show(ChannelShowItem),
    Index(ChannelIndexItem),
    Image(ChannelImageItem)
}

#[derive(Debug)]
#[derive(Clone)]
#[derive(Default)]
pub struct ChannelIndexItem { }

#[derive(Debug)]
#[derive(Clone)]
#[derive(Default)]
pub struct ChannelShowItem {
    pub postid: String,
    pub page: usize,
}

#[derive(Debug)]
#[derive(Default)]
pub struct ChannelItem {
    pub extra: Option<ChannelItemType>,
    pub result: String
}

#[derive(Debug)]
#[derive(Clone)]
#[derive(Default)]
pub struct ChannelImageItem {
    pub url: String,
    pub bytes: Vec<u8>
}
<|endoftext|>


<commit_before>//!
//!	Code to write a sequence table to disk.
//!
extern crate bincode;

use std::io::prelude::*;
use std::io::SeekFrom;
use std::io::Result;
use std::io::Error;
use std::io::ErrorKind;
use byteorder::{ByteOrder, LittleEndian, ReadBytesExt};
use bincode::rustc_serialize::{decode_from, decode};
use flate2::{Decompress,Flush};

use super::SeqTableParams;
use super::write::SeqInfo;
use super::write::SeqBlock;

#[derive(Debug)]
pub struct SeqTable<R: Read + Seek> {
    params: SeqTableParams,
    block_length: u64,
    infotable: Vec<SeqInfo>,
    reader: R,
    dec_buffer: Vec<u8>,
    read_buffer: Vec<u8>,
}

impl<R: Read + Seek> SeqTable<R> {
    pub fn open(mut reader: R) -> Result<SeqTable<R>> {
        try!(reader.seek(SeekFrom::Start(0)));
        // load parameters
        let params = SeqTableParams {
            cut_length: try!(reader.read_u8()),
            plus_offset: try!(reader.read_u8()),
            minus_offset: try!(reader.read_u8()),
            read_length: try!(reader.read_u16::<LittleEndian>()),
        };
        // load block size
        let blen = try!(reader.read_u64::<LittleEndian>());
        // load info table offset
        let offset = try!(reader.read_u64::<LittleEndian>());
        // load buffer size
        let bufsize = try!(reader.read_u64::<LittleEndian>()) as usize;
        // load info table
        try!(reader.seek(SeekFrom::Start(offset)));
        let infotable = (decode_from(&mut reader, bincode::SizeLimit::Infinite)).unwrap(); // TODO: fix

        Ok(SeqTable {
            params: params,
            block_length: blen,
            infotable: infotable,
            reader: reader,
            dec_buffer: vec![0u8; bufsize],
            read_buffer: vec![0u8; bufsize],
        })
    }

    pub fn get_sequence<'a>(&'a mut self, name: &str) -> Result<SeqReader<'a, R>> {
        // locate sequence info
        match self.infotable.iter().find(|&x| x.name == name) {
            Some(iref) => {
                match iref.blocks.get(0) {
                    Some(block) => {
                        try!(self.reader.seek(SeekFrom::Start(block.offset)));
                        Ok(SeqReader {
                            reader: &mut self.reader,
                            block_length: self.block_length,
                            info: &iref,
                            block: None,
                            block_idx: 0,
                            dec_buffer: &mut self.dec_buffer,
                            read_buffer: &mut self.read_buffer,
                        })
                    },
                    None => Err(Error::new(ErrorKind::NotFound, "sequence not found")),
                }

            },
            None => Err(Error::new(ErrorKind::NotFound, "sequence not found")),
        }
    }
}

#[derive(Debug)]
struct SeqReader<'a, R: 'a + Read + Seek> {
    reader: &'a mut R,
    block_length: u64,
    info: &'a SeqInfo,
    block: Option<Vec<(u16, u16)>>,
    block_idx: usize,
    dec_buffer: &'a mut Vec<u8>,
    read_buffer: &'a mut Vec<u8>,
}

impl<'a, R: 'a + Read + Seek> SeqReader<'a, R> {

    fn read_block(&mut self, block_info: &SeqBlock) -> Result<Vec<(u16,u16)>> {

        // read from disk (compressed)
        let buf = &mut self.read_buffer[0..block_info.comp_size as usize];
        let mut decompressor = Decompress::new(false);

        try!(self.reader.seek(SeekFrom::Start(block_info.offset)));
        try!(self.reader.read(buf));

        // uncompress
        let bufout = &mut self.dec_buffer[0..block_info.enc_size as usize];
        decompressor.decompress(&buf, bufout, Flush::Finish).ok().expect("decompressing block");

        // decode back into vector
        let block: Vec<(u16, u16)> = decode(bufout).ok().expect("decode block");

        return Ok(block);
    }

    pub fn get(&mut self, position: u64) -> Result<(u16, u16)> {
        let idx = (position / self.block_length) as usize;

        let block = if self.block.is_some() && self.block_idx == idx {
            self.block.as_ref().unwrap()
        } else {
            match self.info.blocks.get(idx) {
                Some(block_info) => {
                    let aux = try!(self.read_block(block_info));
                    self.block = Some(aux);
                    self.block_idx = idx;
                    self.block.as_ref().unwrap()
                },
                None => return Err(Error::new(ErrorKind::AddrNotAvailable, "index out of range")),
            }
        };

        // get value
        let idx2 = position as usize - idx * self.block_length as usize;
        Ok(block[idx2])
    }
}
<commit_msg>Add functions to get params and sequence info out of a seqtable<commit_after>//!
//!	Code to write a sequence table to disk.
//!
extern crate bincode;

use std::io::prelude::*;
use std::io::SeekFrom;
use std::io::Result;
use std::io::Error;
use std::io::ErrorKind;
use byteorder::{ByteOrder, LittleEndian, ReadBytesExt};
use bincode::rustc_serialize::{decode_from, decode};
use flate2::{Decompress,Flush};

use super::SeqTableParams;
use super::write::SeqInfo;
use super::write::SeqBlock;

#[derive(Debug)]
pub struct SeqTable<R: Read + Seek> {
    params: SeqTableParams,
    block_length: u64,
    infotable: Vec<SeqInfo>,
    reader: R,
    dec_buffer: Vec<u8>,
    read_buffer: Vec<u8>,
}

pub struct SequenceInfo {
    pub name: String,
    pub length: u64,
}

impl<R: Read + Seek> SeqTable<R> {
    pub fn open(mut reader: R) -> Result<SeqTable<R>> {
        try!(reader.seek(SeekFrom::Start(0)));
        // load parameters
        let params = SeqTableParams {
            cut_length: try!(reader.read_u8()),
            plus_offset: try!(reader.read_u8()),
            minus_offset: try!(reader.read_u8()),
            read_length: try!(reader.read_u16::<LittleEndian>()),
        };
        // load block size
        let blen = try!(reader.read_u64::<LittleEndian>());
        // load info table offset
        let offset = try!(reader.read_u64::<LittleEndian>());
        // load buffer size
        let bufsize = try!(reader.read_u64::<LittleEndian>()) as usize;
        // load info table
        try!(reader.seek(SeekFrom::Start(offset)));
        let infotable = (decode_from(&mut reader, bincode::SizeLimit::Infinite)).unwrap(); // TODO: fix

        Ok(SeqTable {
            params: params,
            block_length: blen,
            infotable: infotable,
            reader: reader,
            dec_buffer: vec![0u8; bufsize],
            read_buffer: vec![0u8; bufsize],
        })
    }

    pub fn get_sequence<'a>(&'a mut self, name: &str) -> Result<SeqReader<'a, R>> {
        // locate sequence info
        match self.infotable.iter().find(|&x| x.name == name) {
            Some(iref) => {
                match iref.blocks.get(0) {
                    Some(block) => {
                        try!(self.reader.seek(SeekFrom::Start(block.offset)));
                        Ok(SeqReader {
                            reader: &mut self.reader,
                            block_length: self.block_length,
                            info: &iref,
                            block: None,
                            block_idx: 0,
                            dec_buffer: &mut self.dec_buffer,
                            read_buffer: &mut self.read_buffer,
                        })
                    },
                    None => Err(Error::new(ErrorKind::NotFound, "sequence not found")),
                }

            },
            None => Err(Error::new(ErrorKind::NotFound, "sequence not found")),
        }
    }

    pub fn params(&self) -> &SeqTableParams {
        &self.params
    }

    pub fn sequences(&self) -> Vec<SequenceInfo> {
        self.infotable.iter().map(|info|
            SequenceInfo{ name: info.name.clone(), length: info.length }
        ).collect()
    }
}

#[derive(Debug)]
struct SeqReader<'a, R: 'a + Read + Seek> {
    reader: &'a mut R,
    block_length: u64,
    info: &'a SeqInfo,
    block: Option<Vec<(u16, u16)>>,
    block_idx: usize,
    dec_buffer: &'a mut Vec<u8>,
    read_buffer: &'a mut Vec<u8>,
}

impl<'a, R: 'a + Read + Seek> SeqReader<'a, R> {

    fn read_block(&mut self, block_info: &SeqBlock) -> Result<Vec<(u16,u16)>> {

        // read from disk (compressed)
        let buf = &mut self.read_buffer[0..block_info.comp_size as usize];
        let mut decompressor = Decompress::new(false);

        try!(self.reader.seek(SeekFrom::Start(block_info.offset)));
        try!(self.reader.read(buf));

        // uncompress
        let bufout = &mut self.dec_buffer[0..block_info.enc_size as usize];
        decompressor.decompress(&buf, bufout, Flush::Finish).ok().expect("decompressing block");

        // decode back into vector
        let block: Vec<(u16, u16)> = decode(bufout).ok().expect("decode block");

        return Ok(block);
    }

    pub fn get(&mut self, position: u64) -> Result<(u16, u16)> {
        let idx = (position / self.block_length) as usize;

        let block = if self.block.is_some() && self.block_idx == idx {
            self.block.as_ref().unwrap()
        } else {
            match self.info.blocks.get(idx) {
                Some(block_info) => {
                    let aux = try!(self.read_block(block_info));
                    self.block = Some(aux);
                    self.block_idx = idx;
                    self.block.as_ref().unwrap()
                },
                None => return Err(Error::new(ErrorKind::AddrNotAvailable, "index out of range")),
            }
        };

        // get value
        let idx2 = position as usize - idx * self.block_length as usize;
        Ok(block[idx2])
    }
}
<|endoftext|>